2 * Unit test suite for rich edit control
4 * Copyright 2006 Google (Thomas Kho)
5 * Copyright 2007 Matt Finnicum
6 * Copyright 2007 Dmitry Timoshkov
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
35 #include <wine/test.h>
37 #define ID_RICHEDITTESTDBUTTON 0x123
39 static CHAR string1
[MAX_PATH
], string2
[MAX_PATH
], string3
[MAX_PATH
];
41 #define ok_w3(format, szString1, szString2, szString3) \
42 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
43 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
44 WideCharToMultiByte(CP_ACP, 0, szString3, -1, string3, MAX_PATH, NULL, NULL); \
45 ok(!lstrcmpW(szString3, szString1) || !lstrcmpW(szString3, szString2), \
46 format, string1, string2, string3);
48 static HMODULE hmoduleRichEdit
;
50 static HWND
new_window(LPCSTR lpClassName
, DWORD dwStyle
, HWND parent
) {
52 hwnd
= CreateWindowA(lpClassName
, NULL
, dwStyle
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
53 |WS_VISIBLE
, 0, 0, 200, 60, parent
, NULL
,
54 hmoduleRichEdit
, NULL
);
55 ok(hwnd
!= NULL
, "class: %s, error: %d\n", lpClassName
, (int) GetLastError());
59 static HWND
new_windowW(LPCWSTR lpClassName
, DWORD dwStyle
, HWND parent
) {
61 hwnd
= CreateWindowW(lpClassName
, NULL
, dwStyle
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
62 |WS_VISIBLE
, 0, 0, 200, 60, parent
, NULL
,
63 hmoduleRichEdit
, NULL
);
64 ok(hwnd
!= NULL
, "class: %s, error: %d\n", wine_dbgstr_w(lpClassName
), (int) GetLastError());
68 static HWND
new_richedit(HWND parent
) {
69 return new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, parent
);
72 static HWND
new_richeditW(HWND parent
) {
73 return new_windowW(RICHEDIT_CLASS20W
, ES_MULTILINE
, parent
);
76 /* Keeps the window reponsive for the deley_time in seconds.
77 * This is useful for debugging a test to see what is happening. */
78 static void keep_responsive(time_t delay_time
)
83 /* The message pump uses PeekMessage() to empty the queue and then
84 * sleeps for 50ms before retrying the queue. */
85 end
= time(NULL
) + delay_time
;
86 while (time(NULL
) < end
) {
87 if (PeekMessageA(&msg
, NULL
, 0, 0, PM_REMOVE
)) {
88 TranslateMessage(&msg
);
89 DispatchMessageA(&msg
);
96 static void simulate_typing_characters(HWND hwnd
, const char* szChars
)
100 while (*szChars
!= '\0') {
101 SendMessageA(hwnd
, WM_KEYDOWN
, *szChars
, 1);
102 ret
= SendMessageA(hwnd
, WM_CHAR
, *szChars
, 1);
103 ok(ret
== 0, "WM_CHAR('%c') ret=%d\n", *szChars
, ret
);
104 SendMessageA(hwnd
, WM_KEYUP
, *szChars
, 1);
109 static BOOL
hold_key(int vk
)
114 result
= GetKeyboardState(key_state
);
115 ok(result
, "GetKeyboardState failed.\n");
116 if (!result
) return FALSE
;
117 key_state
[vk
] |= 0x80;
118 result
= SetKeyboardState(key_state
);
119 ok(result
, "SetKeyboardState failed.\n");
123 static BOOL
release_key(int vk
)
128 result
= GetKeyboardState(key_state
);
129 ok(result
, "GetKeyboardState failed.\n");
130 if (!result
) return FALSE
;
131 key_state
[vk
] &= ~0x80;
132 result
= SetKeyboardState(key_state
);
133 ok(result
, "SetKeyboardState failed.\n");
137 static const char haystack
[] = "WINEWine wineWine wine WineWine";
149 static struct find_s find_tests
[] = {
150 /* Find in empty text */
151 {0, -1, "foo", FR_DOWN
, -1},
152 {0, -1, "foo", 0, -1},
153 {0, -1, "", FR_DOWN
, -1},
154 {20, 5, "foo", FR_DOWN
, -1},
155 {5, 20, "foo", FR_DOWN
, -1}
158 static struct find_s find_tests2
[] = {
160 {0, -1, "foo", FR_DOWN
| FR_MATCHCASE
, -1},
161 {5, 20, "WINE", FR_DOWN
| FR_MATCHCASE
, -1},
163 /* Subsequent finds */
164 {0, -1, "Wine", FR_DOWN
| FR_MATCHCASE
, 4},
165 {5, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 13},
166 {14, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 23},
167 {24, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 27},
170 {19, 20, "Wine", FR_MATCHCASE
, 13},
171 {10, 20, "Wine", FR_MATCHCASE
, 4},
172 {20, 10, "Wine", FR_MATCHCASE
, 13},
174 /* Case-insensitive */
175 {1, 31, "wInE", FR_DOWN
, 4},
176 {1, 31, "Wine", FR_DOWN
, 4},
178 /* High-to-low ranges */
179 {20, 5, "Wine", FR_DOWN
, -1},
180 {2, 1, "Wine", FR_DOWN
, -1},
181 {30, 29, "Wine", FR_DOWN
, -1},
182 {20, 5, "Wine", 0, 13},
185 {5, 10, "", FR_DOWN
, -1},
186 {10, 5, "", FR_DOWN
, -1},
187 {0, -1, "", FR_DOWN
, -1},
190 /* Whole-word search */
191 {0, -1, "wine", FR_DOWN
| FR_WHOLEWORD
, 18},
192 {0, -1, "win", FR_DOWN
| FR_WHOLEWORD
, -1},
193 {13, -1, "wine", FR_DOWN
| FR_WHOLEWORD
, 18},
194 {0, -1, "winewine", FR_DOWN
| FR_WHOLEWORD
, 0},
195 {10, -1, "winewine", FR_DOWN
| FR_WHOLEWORD
, 23},
196 {11, -1, "winewine", FR_WHOLEWORD
, 0},
197 {31, -1, "winewine", FR_WHOLEWORD
, 23},
200 {5, 200, "XXX", FR_DOWN
, -1},
201 {-20, 20, "Wine", FR_DOWN
, -1},
202 {-20, 20, "Wine", FR_DOWN
, -1},
203 {-15, -20, "Wine", FR_DOWN
, -1},
204 {1<<12, 1<<13, "Wine", FR_DOWN
, -1},
206 /* Check the case noted in bug 4479 where matches at end aren't recognized */
207 {23, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 23},
208 {27, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 27},
209 {27, 32, "Wine", FR_DOWN
| FR_MATCHCASE
, 27},
210 {13, 31, "WineWine", FR_DOWN
| FR_MATCHCASE
, 23},
211 {13, 32, "WineWine", FR_DOWN
| FR_MATCHCASE
, 23},
213 /* The backwards case of bug 4479; bounds look right
214 * Fails because backward find is wrong */
215 {19, 20, "WINE", FR_MATCHCASE
, 0},
216 {0, 20, "WINE", FR_MATCHCASE
, -1},
218 {0, -1, "wineWine wine", 0, -1},
221 static WCHAR
*atowstr(const char *str
)
225 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
226 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
227 MultiByteToWideChar(CP_ACP
, 0, str
, -1, ret
, len
);
231 static void check_EM_FINDTEXT(HWND hwnd
, const char *name
, struct find_s
*f
, int id
, BOOL unicode
)
237 memset(&ftw
, 0, sizeof(ftw
));
238 ftw
.chrg
.cpMin
= f
->start
;
239 ftw
.chrg
.cpMax
= f
->end
;
240 ftw
.lpstrText
= atowstr(f
->needle
);
242 findloc
= SendMessageA(hwnd
, EM_FINDTEXT
, f
->flags
, (LPARAM
)&ftw
);
243 ok(findloc
== f
->expected_loc
,
244 "EM_FINDTEXT(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
245 name
, id
, unicode
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
, f
->expected_loc
);
247 findloc
= SendMessageA(hwnd
, EM_FINDTEXTW
, f
->flags
, (LPARAM
)&ftw
);
248 ok(findloc
== f
->expected_loc
,
249 "EM_FINDTEXTW(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
250 name
, id
, unicode
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
, f
->expected_loc
);
252 HeapFree(GetProcessHeap(), 0, (void*)ftw
.lpstrText
);
255 memset(&fta
, 0, sizeof(fta
));
256 fta
.chrg
.cpMin
= f
->start
;
257 fta
.chrg
.cpMax
= f
->end
;
258 fta
.lpstrText
= f
->needle
;
260 findloc
= SendMessageA(hwnd
, EM_FINDTEXT
, f
->flags
, (LPARAM
)&fta
);
261 ok(findloc
== f
->expected_loc
,
262 "EM_FINDTEXT(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
263 name
, id
, unicode
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
, f
->expected_loc
);
267 static void check_EM_FINDTEXTEX(HWND hwnd
, const char *name
, struct find_s
*f
,
268 int id
, BOOL unicode
)
271 int expected_end_loc
;
275 memset(&ftw
, 0, sizeof(ftw
));
276 ftw
.chrg
.cpMin
= f
->start
;
277 ftw
.chrg
.cpMax
= f
->end
;
278 ftw
.lpstrText
= atowstr(f
->needle
);
279 findloc
= SendMessageA(hwnd
, EM_FINDTEXTEX
, f
->flags
, (LPARAM
)&ftw
);
280 ok(findloc
== f
->expected_loc
,
281 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
282 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
);
283 ok(ftw
.chrgText
.cpMin
== f
->expected_loc
,
284 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
285 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, ftw
.chrgText
.cpMin
);
286 expected_end_loc
= ((f
->expected_loc
== -1) ? -1
287 : f
->expected_loc
+ strlen(f
->needle
));
288 ok(ftw
.chrgText
.cpMax
== expected_end_loc
,
289 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n",
290 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, ftw
.chrgText
.cpMax
, expected_end_loc
);
291 HeapFree(GetProcessHeap(), 0, (void*)ftw
.lpstrText
);
294 memset(&fta
, 0, sizeof(fta
));
295 fta
.chrg
.cpMin
= f
->start
;
296 fta
.chrg
.cpMax
= f
->end
;
297 fta
.lpstrText
= f
->needle
;
298 findloc
= SendMessageA(hwnd
, EM_FINDTEXTEX
, f
->flags
, (LPARAM
)&fta
);
299 ok(findloc
== f
->expected_loc
,
300 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
301 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
);
302 ok(fta
.chrgText
.cpMin
== f
->expected_loc
,
303 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
304 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, fta
.chrgText
.cpMin
);
305 expected_end_loc
= ((f
->expected_loc
== -1) ? -1
306 : f
->expected_loc
+ strlen(f
->needle
));
307 ok(fta
.chrgText
.cpMax
== expected_end_loc
,
308 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n",
309 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, fta
.chrgText
.cpMax
, expected_end_loc
);
313 static void run_tests_EM_FINDTEXT(HWND hwnd
, const char *name
, struct find_s
*find
,
314 int num_tests
, BOOL unicode
)
318 for (i
= 0; i
< num_tests
; i
++) {
319 check_EM_FINDTEXT(hwnd
, name
, &find
[i
], i
, unicode
);
320 check_EM_FINDTEXTEX(hwnd
, name
, &find
[i
], i
, unicode
);
324 static void test_EM_FINDTEXT(BOOL unicode
)
330 hwndRichEdit
= new_richeditW(NULL
);
332 hwndRichEdit
= new_richedit(NULL
);
334 /* Empty rich edit control */
335 run_tests_EM_FINDTEXT(hwndRichEdit
, "1", find_tests
,
336 sizeof(find_tests
)/sizeof(struct find_s
), unicode
);
338 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)haystack
);
341 run_tests_EM_FINDTEXT(hwndRichEdit
, "2", find_tests2
,
342 sizeof(find_tests2
)/sizeof(struct find_s
), unicode
);
344 /* Setting a format on an arbitrary range should have no effect in search
345 results. This tests correct offset reporting across runs. */
346 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
347 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
348 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
349 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
350 SendMessageA(hwndRichEdit
, EM_SETSEL
, 6, 20);
351 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
353 /* Haystack text, again */
354 run_tests_EM_FINDTEXT(hwndRichEdit
, "2-bis", find_tests2
,
355 sizeof(find_tests2
)/sizeof(struct find_s
), unicode
);
357 /* Yet another range */
358 cf2
.dwMask
= CFM_BOLD
| cf2
.dwMask
;
359 cf2
.dwEffects
= CFE_BOLD
^ cf2
.dwEffects
;
360 SendMessageA(hwndRichEdit
, EM_SETSEL
, 11, 15);
361 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
363 /* Haystack text, again */
364 run_tests_EM_FINDTEXT(hwndRichEdit
, "2-bisbis", find_tests2
,
365 sizeof(find_tests2
)/sizeof(struct find_s
), unicode
);
367 DestroyWindow(hwndRichEdit
);
370 static const struct getline_s
{
375 {0, 10, "foo bar\r"},
380 /* Buffer smaller than line length */
386 static void test_EM_GETLINE(void)
389 HWND hwndRichEdit
= new_richedit(NULL
);
390 static const int nBuf
= 1024;
391 char dest
[1024], origdest
[1024];
392 const char text
[] = "foo bar\n"
396 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
398 memset(origdest
, 0xBB, nBuf
);
399 for (i
= 0; i
< sizeof(gl
)/sizeof(struct getline_s
); i
++)
402 int expected_nCopied
= min(gl
[i
].buffer_len
, strlen(gl
[i
].text
));
403 int expected_bytes_written
= min(gl
[i
].buffer_len
, strlen(gl
[i
].text
));
404 memset(dest
, 0xBB, nBuf
);
405 *(WORD
*) dest
= gl
[i
].buffer_len
;
407 /* EM_GETLINE appends a "\r\0" to the end of the line
408 * nCopied counts up to and including the '\r' */
409 nCopied
= SendMessageA(hwndRichEdit
, EM_GETLINE
, gl
[i
].line
, (LPARAM
)dest
);
410 ok(nCopied
== expected_nCopied
, "%d: %d!=%d\n", i
, nCopied
,
412 /* two special cases since a parameter is passed via dest */
413 if (gl
[i
].buffer_len
== 0)
414 ok(!dest
[0] && !dest
[1] && !strncmp(dest
+2, origdest
+2, nBuf
-2),
416 else if (gl
[i
].buffer_len
== 1)
417 ok(dest
[0] == gl
[i
].text
[0] && !dest
[1] &&
418 !strncmp(dest
+2, origdest
+2, nBuf
-2), "buffer_len=1\n");
421 /* Prepare hex strings of buffers to dump on failure. */
422 char expectedbuf
[1024];
423 char resultbuf
[1024];
426 for (j
= 0; j
< 32; j
++)
427 sprintf(resultbuf
+strlen(resultbuf
), "%02x", dest
[j
] & 0xFF);
428 expectedbuf
[0] = '\0';
429 for (j
= 0; j
< expected_bytes_written
; j
++) /* Written bytes */
430 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", gl
[i
].text
[j
] & 0xFF);
431 for (; j
< gl
[i
].buffer_len
; j
++) /* Ignored bytes */
432 sprintf(expectedbuf
+strlen(expectedbuf
), "??");
433 for (; j
< 32; j
++) /* Bytes after declared buffer size */
434 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", origdest
[j
] & 0xFF);
436 /* Test the part of the buffer that is expected to be written according
437 * to the MSDN documentation fo EM_GETLINE, which does not state that
438 * a NULL terminating character will be added unless no text is copied.
440 * Windows NT does not append a NULL terminating character, but
441 * Windows 2000 and up do append a NULL terminating character if there
442 * is space in the buffer. The test will ignore this difference. */
443 ok(!strncmp(dest
, gl
[i
].text
, expected_bytes_written
),
444 "%d: expected_bytes_written=%d\n" "expected=0x%s\n" "but got= 0x%s\n",
445 i
, expected_bytes_written
, expectedbuf
, resultbuf
);
446 /* Test the part of the buffer after the declared length to make sure
447 * there are no buffer overruns. */
448 ok(!strncmp(dest
+ gl
[i
].buffer_len
, origdest
+ gl
[i
].buffer_len
,
449 nBuf
- gl
[i
].buffer_len
),
450 "%d: expected_bytes_written=%d\n" "expected=0x%s\n" "but got= 0x%s\n",
451 i
, expected_bytes_written
, expectedbuf
, resultbuf
);
455 DestroyWindow(hwndRichEdit
);
458 static void test_EM_LINELENGTH(void)
460 HWND hwndRichEdit
= new_richedit(NULL
);
466 int offset_test
[10][2] = {
481 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
483 for (i
= 0; i
< 10; i
++) {
484 result
= SendMessageA(hwndRichEdit
, EM_LINELENGTH
, offset_test
[i
][0], 0);
485 ok(result
== offset_test
[i
][1], "Length of line at offset %d is %ld, expected %d\n",
486 offset_test
[i
][0], result
, offset_test
[i
][1]);
489 DestroyWindow(hwndRichEdit
);
492 static int get_scroll_pos_y(HWND hwnd
)
495 SendMessageA(hwnd
, EM_GETSCROLLPOS
, 0, (LPARAM
)&p
);
496 ok(p
.x
!= -1 && p
.y
!= -1, "p.x:%d p.y:%d\n", p
.x
, p
.y
);
500 static void move_cursor(HWND hwnd
, LONG charindex
)
503 cr
.cpMax
= charindex
;
504 cr
.cpMin
= charindex
;
505 SendMessageA(hwnd
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
508 static void line_scroll(HWND hwnd
, int amount
)
510 SendMessageA(hwnd
, EM_LINESCROLL
, 0, amount
);
513 static void test_EM_SCROLLCARET(void)
516 const char text
[] = "aa\n"
517 "this is a long line of text that should be longer than the "
525 /* The richedit window height needs to be large enough vertically to fit in
526 * more than two lines of text, so the new_richedit function can't be used
527 * since a height of 60 was not large enough on some systems.
529 HWND hwndRichEdit
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
,
530 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
531 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
532 ok(hwndRichEdit
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
534 /* Can't verify this */
535 SendMessageA(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
537 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
539 /* Caret above visible window */
540 line_scroll(hwndRichEdit
, 3);
541 prevY
= get_scroll_pos_y(hwndRichEdit
);
542 SendMessageA(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
543 curY
= get_scroll_pos_y(hwndRichEdit
);
544 ok(prevY
!= curY
, "%d == %d\n", prevY
, curY
);
546 /* Caret below visible window */
547 move_cursor(hwndRichEdit
, sizeof(text
) - 1);
548 line_scroll(hwndRichEdit
, -3);
549 prevY
= get_scroll_pos_y(hwndRichEdit
);
550 SendMessageA(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
551 curY
= get_scroll_pos_y(hwndRichEdit
);
552 ok(prevY
!= curY
, "%d == %d\n", prevY
, curY
);
554 /* Caret in visible window */
555 move_cursor(hwndRichEdit
, sizeof(text
) - 2);
556 prevY
= get_scroll_pos_y(hwndRichEdit
);
557 SendMessageA(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
558 curY
= get_scroll_pos_y(hwndRichEdit
);
559 ok(prevY
== curY
, "%d != %d\n", prevY
, curY
);
561 /* Caret still in visible window */
562 line_scroll(hwndRichEdit
, -1);
563 prevY
= get_scroll_pos_y(hwndRichEdit
);
564 SendMessageA(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
565 curY
= get_scroll_pos_y(hwndRichEdit
);
566 ok(prevY
== curY
, "%d != %d\n", prevY
, curY
);
568 DestroyWindow(hwndRichEdit
);
571 static void test_EM_POSFROMCHAR(void)
573 HWND hwndRichEdit
= new_richedit(NULL
);
576 unsigned int height
= 0;
581 static const char text
[] = "aa\n"
582 "this is a long line of text that should be longer than the "
591 rtl
= (GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_FONTSIGNATURE
,
592 (LPSTR
) &sig
, sizeof(LOCALESIGNATURE
)) &&
593 (sig
.lsUsb
[3] & 0x08000000) != 0);
595 /* Fill the control to lines to ensure that most of them are offscreen */
596 for (i
= 0; i
< 50; i
++)
598 /* Do not modify the string; it is exactly 16 characters long. */
599 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 0);
600 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"0123456789ABCDE\n");
604 Richedit 1.0 receives a POINTL* on wParam and character offset on lParam, returns void.
605 Richedit 2.0 receives character offset on wParam, ignores lParam, returns MAKELONG(x,y)
606 Richedit 3.0 accepts either of the above API conventions.
609 /* Testing Richedit 2.0 API format */
611 /* Testing start of lines. X-offset should be constant on all cases (native is 1).
612 Since all lines are identical and drawn with the same font,
613 they should have the same height... right?
615 for (i
= 0; i
< 50; i
++)
617 /* All the lines are 16 characters long */
618 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, i
* 16, 0);
621 ok(HIWORD(result
) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result
));
622 ok(LOWORD(result
) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
623 xpos
= LOWORD(result
);
627 ok(HIWORD(result
) > 0, "EM_POSFROMCHAR reports y=%d, expected > 0\n", HIWORD(result
));
628 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
629 height
= HIWORD(result
);
633 ok(HIWORD(result
) == i
* height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), i
* height
);
634 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
638 /* Testing position at end of text */
639 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 50 * 16, 0);
640 ok(HIWORD(result
) == 50 * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), 50 * height
);
641 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
643 /* Testing position way past end of text */
644 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 55 * 16, 0);
645 ok(HIWORD(result
) == 50 * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), 50 * height
);
646 expected
= (rtl
? 8 : 1);
647 ok(LOWORD(result
) == expected
, "EM_POSFROMCHAR reports x=%d, expected %d\n", LOWORD(result
), expected
);
649 /* Testing that vertical scrolling does, in fact, have an effect on EM_POSFROMCHAR */
650 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0); /* line down */
651 for (i
= 0; i
< 50; i
++)
653 /* All the lines are 16 characters long */
654 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, i
* 16, 0);
655 ok((signed short)(HIWORD(result
)) == (i
- 1) * height
,
656 "EM_POSFROMCHAR reports y=%hd, expected %d\n",
657 (signed short)(HIWORD(result
)), (i
- 1) * height
);
658 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
661 /* Testing position at end of text */
662 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 50 * 16, 0);
663 ok(HIWORD(result
) == (50 - 1) * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), (50 - 1) * height
);
664 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
666 /* Testing position way past end of text */
667 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 55 * 16, 0);
668 ok(HIWORD(result
) == (50 - 1) * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), (50 - 1) * height
);
669 expected
= (rtl
? 8 : 1);
670 ok(LOWORD(result
) == expected
, "EM_POSFROMCHAR reports x=%d, expected %d\n", LOWORD(result
), expected
);
672 /* Testing that horizontal scrolling does, in fact, have an effect on EM_POSFROMCHAR */
673 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
674 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0); /* line up */
676 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 0, 0);
677 ok(HIWORD(result
) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result
));
678 ok(LOWORD(result
) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
679 xpos
= LOWORD(result
);
681 SendMessageA(hwndRichEdit
, WM_HSCROLL
, SB_LINERIGHT
, 0);
682 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 0, 0);
683 ok(HIWORD(result
) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result
));
684 ok((signed short)(LOWORD(result
)) < xpos
,
685 "EM_POSFROMCHAR reports x=%hd, expected value less than %d\n",
686 (signed short)(LOWORD(result
)), xpos
);
687 SendMessageA(hwndRichEdit
, WM_HSCROLL
, SB_LINELEFT
, 0);
689 /* Test around end of text that doesn't end in a newline. */
690 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"12345678901234");
691 SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
,
692 SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0)-1);
693 ok(pt
.x
> 1, "pt.x = %d\n", pt
.x
);
695 SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
,
696 SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0));
697 ok(pt
.x
> xpos
, "pt.x = %d\n", pt
.x
);
698 xpos
= (rtl
? pt
.x
+ 7 : pt
.x
);
699 SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
,
700 SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0)+1);
701 ok(pt
.x
== xpos
, "pt.x = %d\n", pt
.x
);
703 /* Try a negative position. */
704 SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
, -1);
705 ok(pt
.x
== 1, "pt.x = %d\n", pt
.x
);
707 DestroyWindow(hwndRichEdit
);
710 static void test_EM_SETCHARFORMAT(void)
712 HWND hwndRichEdit
= new_richedit(NULL
);
715 int tested_effects
[] = {
731 rtl
= (GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_FONTSIGNATURE
,
732 (LPSTR
) &sig
, sizeof(LOCALESIGNATURE
)) &&
733 (sig
.lsUsb
[3] & 0x08000000) != 0);
735 /* Invalid flags, CHARFORMAT2 structure blanked out */
736 memset(&cf2
, 0, sizeof(cf2
));
737 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)0xfffffff0, (LPARAM
)&cf2
);
738 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
740 /* A valid flag, CHARFORMAT2 structure blanked out */
741 memset(&cf2
, 0, sizeof(cf2
));
742 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
743 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
745 /* A valid flag, CHARFORMAT2 structure blanked out */
746 memset(&cf2
, 0, sizeof(cf2
));
747 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2
);
748 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
750 /* A valid flag, CHARFORMAT2 structure blanked out */
751 memset(&cf2
, 0, sizeof(cf2
));
752 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_WORD
, (LPARAM
)&cf2
);
753 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
755 /* A valid flag, CHARFORMAT2 structure blanked out */
756 memset(&cf2
, 0, sizeof(cf2
));
757 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
758 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
760 /* Invalid flags, CHARFORMAT2 structure minimally filled */
761 memset(&cf2
, 0, sizeof(cf2
));
762 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
763 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)0xfffffff0, (LPARAM
)&cf2
);
764 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
765 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
766 ok(rc
== FALSE
, "Should not be able to undo here.\n");
767 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
769 /* A valid flag, CHARFORMAT2 structure minimally filled */
770 memset(&cf2
, 0, sizeof(cf2
));
771 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
772 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
773 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
774 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
775 ok(rc
== FALSE
, "Should not be able to undo here.\n");
776 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
778 /* A valid flag, CHARFORMAT2 structure minimally filled */
779 memset(&cf2
, 0, sizeof(cf2
));
780 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
781 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2
);
782 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
783 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
784 ok(rc
== FALSE
, "Should not be able to undo here.\n");
785 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
787 /* A valid flag, CHARFORMAT2 structure minimally filled */
788 memset(&cf2
, 0, sizeof(cf2
));
789 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
790 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_WORD
, (LPARAM
)&cf2
);
791 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
792 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
793 todo_wine
ok(rc
== TRUE
, "Should not be able to undo here.\n");
794 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
796 /* A valid flag, CHARFORMAT2 structure minimally filled */
797 memset(&cf2
, 0, sizeof(cf2
));
798 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
799 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
800 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
801 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
802 ok(rc
== TRUE
, "Should not be able to undo here.\n");
803 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
805 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
806 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
808 /* Test state of modify flag before and after valid EM_SETCHARFORMAT */
809 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
810 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
811 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
812 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
814 /* wParam==0 is default char format, does not set modify */
815 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
816 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
817 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
818 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, 0, (LPARAM
)&cf2
);
819 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
822 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
823 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
826 skip("RTL language found\n");
828 /* wParam==SCF_SELECTION sets modify if nonempty selection */
829 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
830 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
831 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
832 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
833 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
834 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
835 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
837 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
838 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
839 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
840 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
841 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
842 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
843 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
844 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
845 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
846 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
847 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
848 ok(rc
== -1, "Text not marked as modified, expected modified! (%d)\n", rc
);
850 /* wParam==SCF_ALL sets modify regardless of whether text is present */
851 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
852 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
853 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
854 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
855 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
856 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
857 ok(rc
== -1, "Text not marked as modified, expected modified! (%d)\n", rc
);
859 DestroyWindow(hwndRichEdit
);
861 /* EM_GETCHARFORMAT tests */
862 for (i
= 0; tested_effects
[i
]; i
++)
864 hwndRichEdit
= new_richedit(NULL
);
865 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
867 /* Need to set a TrueType font to get consistent CFM_BOLD results */
868 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
869 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
870 cf2
.dwMask
= CFM_FACE
|CFM_WEIGHT
;
872 strcpy(cf2
.szFaceName
, "Courier New");
873 cf2
.wWeight
= FW_DONTCARE
;
874 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
876 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
877 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
878 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 4);
879 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
880 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
881 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
883 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
884 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
885 ok((cf2
.dwEffects
& tested_effects
[i
]) == 0,
886 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
888 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
889 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
890 cf2
.dwMask
= tested_effects
[i
];
891 if (cf2
.dwMask
== CFE_SUBSCRIPT
|| cf2
.dwMask
== CFE_SUPERSCRIPT
)
892 cf2
.dwMask
= CFM_SUPERSCRIPT
;
893 cf2
.dwEffects
= tested_effects
[i
];
894 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
895 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
897 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
898 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
899 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
900 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
901 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
902 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
904 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
905 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
906 ok((cf2
.dwEffects
& tested_effects
[i
]) == tested_effects
[i
],
907 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
909 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
910 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
911 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 4);
912 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
913 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
914 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
916 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
917 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
918 ok((cf2
.dwEffects
& tested_effects
[i
]) == 0,
919 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
921 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
922 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
923 SendMessageA(hwndRichEdit
, EM_SETSEL
, 1, 3);
924 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
925 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
926 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == 0)
928 (cf2
.dwMask
& tested_effects
[i
]) == 0),
929 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i
, cf2
.dwMask
, tested_effects
[i
]);
931 DestroyWindow(hwndRichEdit
);
934 for (i
= 0; tested_effects
[i
]; i
++)
936 hwndRichEdit
= new_richedit(NULL
);
937 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
939 /* Need to set a TrueType font to get consistent CFM_BOLD results */
940 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
941 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
942 cf2
.dwMask
= CFM_FACE
|CFM_WEIGHT
;
944 strcpy(cf2
.szFaceName
, "Courier New");
945 cf2
.wWeight
= FW_DONTCARE
;
946 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
948 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
949 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
950 cf2
.dwMask
= tested_effects
[i
];
951 if (cf2
.dwMask
== CFE_SUBSCRIPT
|| cf2
.dwMask
== CFE_SUPERSCRIPT
)
952 cf2
.dwMask
= CFM_SUPERSCRIPT
;
953 cf2
.dwEffects
= tested_effects
[i
];
954 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 4);
955 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
957 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
958 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
959 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
960 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
961 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
962 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
964 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
965 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
966 ok((cf2
.dwEffects
& tested_effects
[i
]) == 0,
967 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
969 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
970 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
971 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 4);
972 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
973 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
974 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
976 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
977 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
978 ok((cf2
.dwEffects
& tested_effects
[i
]) == tested_effects
[i
],
979 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
981 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
982 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
983 SendMessageA(hwndRichEdit
, EM_SETSEL
, 1, 3);
984 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
985 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
986 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == 0)
988 (cf2
.dwMask
& tested_effects
[i
]) == 0),
989 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i
, cf2
.dwMask
, tested_effects
[i
]);
990 ok((cf2
.dwEffects
& tested_effects
[i
]) == tested_effects
[i
],
991 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x set\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
993 DestroyWindow(hwndRichEdit
);
996 /* Effects applied on an empty selection should take effect when selection is
997 replaced with text */
998 hwndRichEdit
= new_richedit(NULL
);
999 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1000 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 2); /* Empty selection */
1002 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1003 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1004 cf2
.dwMask
= CFM_BOLD
;
1005 cf2
.dwEffects
= CFE_BOLD
;
1006 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1008 /* Selection is now nonempty */
1009 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1011 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1012 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1013 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 6);
1014 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1016 ok (((cf2
.dwMask
& CFM_BOLD
) == CFM_BOLD
),
1017 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, CFM_BOLD
);
1018 ok((cf2
.dwEffects
& CFE_BOLD
) == CFE_BOLD
,
1019 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, CFE_BOLD
);
1022 /* Set two effects on an empty selection */
1023 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1024 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 2); /* Empty selection */
1026 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1027 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1028 cf2
.dwMask
= CFM_BOLD
;
1029 cf2
.dwEffects
= CFE_BOLD
;
1030 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1031 cf2
.dwMask
= CFM_ITALIC
;
1032 cf2
.dwEffects
= CFE_ITALIC
;
1033 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1035 /* Selection is now nonempty */
1036 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1038 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1039 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1040 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 6);
1041 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1043 ok (((cf2
.dwMask
& (CFM_BOLD
|CFM_ITALIC
)) == (CFM_BOLD
|CFM_ITALIC
)),
1044 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, (CFM_BOLD
|CFM_ITALIC
));
1045 ok((cf2
.dwEffects
& (CFE_BOLD
|CFE_ITALIC
)) == (CFE_BOLD
|CFE_ITALIC
),
1046 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, (CFE_BOLD
|CFE_ITALIC
));
1048 /* Setting the (empty) selection to exactly the same place as before should
1049 NOT clear the insertion style! */
1050 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1051 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 2); /* Empty selection */
1053 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1054 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1055 cf2
.dwMask
= CFM_BOLD
;
1056 cf2
.dwEffects
= CFE_BOLD
;
1057 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1059 /* Empty selection in same place, insert style should NOT be forgotten here. */
1060 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 2);
1062 /* Selection is now nonempty */
1063 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1065 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1066 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1067 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 6);
1068 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1070 ok (((cf2
.dwMask
& CFM_BOLD
) == CFM_BOLD
),
1071 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, CFM_BOLD
);
1072 ok((cf2
.dwEffects
& CFE_BOLD
) == CFE_BOLD
,
1073 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, CFE_BOLD
);
1075 /* Ditto with EM_EXSETSEL */
1076 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1077 cr
.cpMin
= 2; cr
.cpMax
= 2;
1078 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
); /* Empty selection */
1080 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1081 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1082 cf2
.dwMask
= CFM_BOLD
;
1083 cf2
.dwEffects
= CFE_BOLD
;
1084 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1086 /* Empty selection in same place, insert style should NOT be forgotten here. */
1087 cr
.cpMin
= 2; cr
.cpMax
= 2;
1088 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
); /* Empty selection */
1090 /* Selection is now nonempty */
1091 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1093 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1094 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1095 cr
.cpMin
= 2; cr
.cpMax
= 6;
1096 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
); /* Empty selection */
1097 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1099 ok (((cf2
.dwMask
& CFM_BOLD
) == CFM_BOLD
),
1100 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, CFM_BOLD
);
1101 ok((cf2
.dwEffects
& CFE_BOLD
) == CFE_BOLD
,
1102 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, CFE_BOLD
);
1104 DestroyWindow(hwndRichEdit
);
1107 static void test_EM_SETTEXTMODE(void)
1109 HWND hwndRichEdit
= new_richedit(NULL
);
1110 CHARFORMAT2A cf2
, cf2test
;
1114 /*Attempt to use mutually exclusive modes*/
1115 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_PLAINTEXT
|TM_RICHTEXT
, 0);
1116 ok(rc
== E_INVALIDARG
,
1117 "EM_SETTEXTMODE: using mutually exclusive mode flags - returned: %x\n", rc
);
1119 /*Test that EM_SETTEXTMODE fails if text exists within the control*/
1120 /*Insert text into the control*/
1122 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1124 /*Attempt to change the control to plain text mode*/
1125 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_PLAINTEXT
, 0);
1126 ok(rc
== E_UNEXPECTED
,
1127 "EM_SETTEXTMODE: changed text mode in control containing text - returned: %x\n", rc
);
1129 /*Test that EM_SETTEXTMODE does not allow rich edit text to be pasted.
1130 If rich text is pasted, it should have the same formatting as the rest
1131 of the text in the control*/
1133 /*Italicize the text
1134 *NOTE: If the default text was already italicized, the test will simply
1135 reverse; in other words, it will copy a regular "wine" into a plain
1136 text window that uses an italicized format*/
1137 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1138 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
1140 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
1141 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
1143 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1144 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
1146 /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine;
1147 however, SCF_ALL has been implemented*/
1148 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
1149 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1151 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1152 ok(rc
== -1, "Text not marked as modified, expected modified! (%d)\n", rc
);
1154 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1156 /*Select the string "wine"*/
1159 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1161 /*Copy the italicized "wine" to the clipboard*/
1162 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
1164 /*Reset the formatting to default*/
1165 cf2
.dwEffects
= CFE_ITALIC
^cf2
.dwEffects
;
1166 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
1167 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1169 /*Clear the text in the control*/
1170 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
1172 /*Switch to Plain Text Mode*/
1173 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_PLAINTEXT
, 0);
1174 ok(rc
== 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control: returned: %d\n", rc
);
1176 /*Input "wine" again in normal format*/
1177 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1179 /*Paste the italicized "wine" into the control*/
1180 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
1182 /*Select a character from the first "wine" string*/
1185 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1187 /*Retrieve its formatting*/
1188 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2
);
1190 /*Select a character from the second "wine" string*/
1193 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1195 /*Retrieve its formatting*/
1196 cf2test
.cbSize
= sizeof(CHARFORMAT2A
);
1197 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2test
);
1199 /*Compare the two formattings*/
1200 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
1201 "two formats found in plain text mode - cf2.dwEffects: %x cf2test.dwEffects: %x\n",
1202 cf2
.dwEffects
, cf2test
.dwEffects
);
1203 /*Test TM_RICHTEXT by: switching back to Rich Text mode
1204 printing "wine" in the current format(normal)
1205 pasting "wine" from the clipboard(italicized)
1206 comparing the two formats(should differ)*/
1208 /*Attempt to switch with text in control*/
1209 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_RICHTEXT
, 0);
1210 ok(rc
!= 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc
);
1213 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
1215 /*Switch into Rich Text mode*/
1216 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_RICHTEXT
, 0);
1217 ok(rc
== 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc
);
1219 /*Print "wine" in normal formatting into the control*/
1220 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1222 /*Paste italicized "wine" into the control*/
1223 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
1225 /*Select text from the first "wine" string*/
1228 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1230 /*Retrieve its formatting*/
1231 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2
);
1233 /*Select text from the second "wine" string*/
1236 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1238 /*Retrieve its formatting*/
1239 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2test
);
1241 /*Test that the two formattings are not the same*/
1242 todo_wine
ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
!= cf2test
.dwEffects
),
1243 "expected different formats - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1244 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
1246 DestroyWindow(hwndRichEdit
);
1249 static void test_SETPARAFORMAT(void)
1251 HWND hwndRichEdit
= new_richedit(NULL
);
1254 LONG expectedMask
= PFM_ALL2
& ~PFM_TABLEROWDELIMITER
;
1255 fmt
.cbSize
= sizeof(PARAFORMAT2
);
1256 fmt
.dwMask
= PFM_ALIGNMENT
;
1257 fmt
.wAlignment
= PFA_LEFT
;
1259 ret
= SendMessageA(hwndRichEdit
, EM_SETPARAFORMAT
, 0, (LPARAM
)&fmt
);
1260 ok(ret
!= 0, "expected non-zero got %d\n", ret
);
1262 fmt
.cbSize
= sizeof(PARAFORMAT2
);
1264 ret
= SendMessageA(hwndRichEdit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
1265 /* Ignore the PFM_TABLEROWDELIMITER bit because it changes
1266 * between richedit different native builds of riched20.dll
1267 * used on different Windows versions. */
1268 ret
&= ~PFM_TABLEROWDELIMITER
;
1269 fmt
.dwMask
&= ~PFM_TABLEROWDELIMITER
;
1271 ok(ret
== expectedMask
, "expected %x got %x\n", expectedMask
, ret
);
1272 ok(fmt
.dwMask
== expectedMask
, "expected %x got %x\n", expectedMask
, fmt
.dwMask
);
1274 DestroyWindow(hwndRichEdit
);
1277 static void test_TM_PLAINTEXT(void)
1279 /*Tests plain text properties*/
1281 HWND hwndRichEdit
= new_richedit(NULL
);
1282 CHARFORMAT2A cf2
, cf2test
;
1286 /*Switch to plain text mode*/
1288 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
1289 SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, TM_PLAINTEXT
, 0);
1291 /*Fill control with text*/
1293 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"Is Wine an emulator? No it's not");
1295 /*Select some text and bold it*/
1299 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1300 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1301 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
1303 cf2
.dwMask
= CFM_BOLD
| cf2
.dwMask
;
1304 cf2
.dwEffects
= CFE_BOLD
^ cf2
.dwEffects
;
1306 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1307 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
1309 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_WORD
| SCF_SELECTION
, (LPARAM
)&cf2
);
1310 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
1312 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
1313 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1315 /*Get the formatting of those characters*/
1317 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1319 /*Get the formatting of some other characters*/
1320 cf2test
.cbSize
= sizeof(CHARFORMAT2A
);
1323 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1324 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2test
);
1326 /*Test that they are the same as plain text allows only one formatting*/
1328 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
1329 "two selections' formats differ - cf2.dwMask: %x, cf2test.dwMask %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1330 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
1332 /*Fill the control with a "wine" string, which when inserted will be bold*/
1334 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1336 /*Copy the bolded "wine" string*/
1340 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1341 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
1343 /*Swap back to rich text*/
1345 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
1346 SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, TM_RICHTEXT
, 0);
1348 /*Set the default formatting to bold italics*/
1350 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
1351 cf2
.dwMask
|= CFM_ITALIC
;
1352 cf2
.dwEffects
^= CFE_ITALIC
;
1353 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
1354 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1356 /*Set the text in the control to "wine", which will be bold and italicized*/
1358 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1360 /*Paste the plain text "wine" string, which should take the insert
1361 formatting, which at the moment is bold italics*/
1363 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
1365 /*Select the first "wine" string and retrieve its formatting*/
1369 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1370 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1372 /*Select the second "wine" string and retrieve its formatting*/
1376 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1377 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2test
);
1379 /*Compare the two formattings. They should be the same.*/
1381 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
1382 "Copied text retained formatting - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1383 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
1384 DestroyWindow(hwndRichEdit
);
1387 static void test_WM_GETTEXT(void)
1389 HWND hwndRichEdit
= new_richedit(NULL
);
1390 static const char text
[] = "Hello. My name is RichEdit!";
1391 static const char text2
[] = "Hello. My name is RichEdit!\r";
1392 static const char text2_after
[] = "Hello. My name is RichEdit!\r\n";
1393 char buffer
[1024] = {0};
1396 /* Baseline test with normal-sized buffer */
1397 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
1398 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1399 ok(result
== lstrlenA(buffer
),
1400 "WM_GETTEXT returned %d, expected %d\n", result
, lstrlenA(buffer
));
1401 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1402 result
= strcmp(buffer
,text
);
1404 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1406 /* Test for returned value of WM_GETTEXTLENGTH */
1407 result
= SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0);
1408 ok(result
== lstrlenA(text
),
1409 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
1410 result
, lstrlenA(text
));
1412 /* Test for behavior in overflow case */
1413 memset(buffer
, 0, 1024);
1414 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, strlen(text
), (LPARAM
)buffer
);
1416 result
== lstrlenA(text
) - 1, /* XP, win2k3 */
1417 "WM_GETTEXT returned %d, expected 0 or %d\n", result
, lstrlenA(text
) - 1);
1418 result
= strcmp(buffer
,text
);
1420 result
= strncmp(buffer
, text
, lstrlenA(text
) - 1); /* XP, win2k3 */
1422 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1424 /* Baseline test with normal-sized buffer and carriage return */
1425 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
1426 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1427 ok(result
== lstrlenA(buffer
),
1428 "WM_GETTEXT returned %d, expected %d\n", result
, lstrlenA(buffer
));
1429 result
= strcmp(buffer
,text2_after
);
1431 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1433 /* Test for returned value of WM_GETTEXTLENGTH */
1434 result
= SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0);
1435 ok(result
== lstrlenA(text2_after
),
1436 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
1437 result
, lstrlenA(text2_after
));
1439 /* Test for behavior of CRLF conversion in case of overflow */
1440 memset(buffer
, 0, 1024);
1441 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, strlen(text2
), (LPARAM
)buffer
);
1443 result
== lstrlenA(text2
) - 1, /* XP, win2k3 */
1444 "WM_GETTEXT returned %d, expected 0 or %d\n", result
, lstrlenA(text2
) - 1);
1445 result
= strcmp(buffer
,text2
);
1447 result
= strncmp(buffer
, text2
, lstrlenA(text2
) - 1); /* XP, win2k3 */
1449 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1451 DestroyWindow(hwndRichEdit
);
1454 static void test_EM_GETTEXTRANGE(void)
1456 HWND hwndRichEdit
= new_richedit(NULL
);
1457 const char * text1
= "foo bar\r\nfoo bar";
1458 const char * text2
= "foo bar\rfoo bar";
1459 const char * expect
= "bar\rfoo";
1460 char buffer
[1024] = {0};
1462 TEXTRANGEA textRange
;
1464 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
1466 textRange
.lpstrText
= buffer
;
1467 textRange
.chrg
.cpMin
= 4;
1468 textRange
.chrg
.cpMax
= 11;
1469 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1470 ok(result
== 7, "EM_GETTEXTRANGE returned %ld\n", result
);
1471 ok(!strcmp(expect
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1473 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
1475 textRange
.lpstrText
= buffer
;
1476 textRange
.chrg
.cpMin
= 4;
1477 textRange
.chrg
.cpMax
= 11;
1478 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1479 ok(result
== 7, "EM_GETTEXTRANGE returned %ld\n", result
);
1480 ok(!strcmp(expect
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1482 /* cpMax of text length is used instead of -1 in this case */
1483 textRange
.lpstrText
= buffer
;
1484 textRange
.chrg
.cpMin
= 0;
1485 textRange
.chrg
.cpMax
= -1;
1486 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1487 ok(result
== strlen(text2
), "EM_GETTEXTRANGE returned %ld\n", result
);
1488 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1490 /* cpMin < 0 causes no text to be copied, and 0 to be returned */
1491 textRange
.lpstrText
= buffer
;
1492 textRange
.chrg
.cpMin
= -1;
1493 textRange
.chrg
.cpMax
= 1;
1494 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1495 ok(result
== 0, "EM_GETTEXTRANGE returned %ld\n", result
);
1496 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1498 /* cpMax of -1 is not replaced with text length if cpMin != 0 */
1499 textRange
.lpstrText
= buffer
;
1500 textRange
.chrg
.cpMin
= 1;
1501 textRange
.chrg
.cpMax
= -1;
1502 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1503 ok(result
== 0, "EM_GETTEXTRANGE returned %ld\n", result
);
1504 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1506 /* no end character is copied if cpMax - cpMin < 0 */
1507 textRange
.lpstrText
= buffer
;
1508 textRange
.chrg
.cpMin
= 5;
1509 textRange
.chrg
.cpMax
= 5;
1510 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1511 ok(result
== 0, "EM_GETTEXTRANGE returned %ld\n", result
);
1512 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1514 /* cpMax of text length is used if cpMax > text length*/
1515 textRange
.lpstrText
= buffer
;
1516 textRange
.chrg
.cpMin
= 0;
1517 textRange
.chrg
.cpMax
= 1000;
1518 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1519 ok(result
== strlen(text2
), "EM_GETTEXTRANGE returned %ld\n", result
);
1520 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1522 DestroyWindow(hwndRichEdit
);
1525 static void test_EM_GETSELTEXT(void)
1527 HWND hwndRichEdit
= new_richedit(NULL
);
1528 const char * text1
= "foo bar\r\nfoo bar";
1529 const char * text2
= "foo bar\rfoo bar";
1530 const char * expect
= "bar\rfoo";
1531 char buffer
[1024] = {0};
1534 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
1536 SendMessageA(hwndRichEdit
, EM_SETSEL
, 4, 11);
1537 result
= SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, 0, (LPARAM
)buffer
);
1538 ok(result
== 7, "EM_GETTEXTRANGE returned %ld\n", result
);
1539 ok(!strcmp(expect
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1541 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
1543 SendMessageA(hwndRichEdit
, EM_SETSEL
, 4, 11);
1544 result
= SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, 0, (LPARAM
)buffer
);
1545 ok(result
== 7, "EM_GETTEXTRANGE returned %ld\n", result
);
1546 ok(!strcmp(expect
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1548 DestroyWindow(hwndRichEdit
);
1551 /* FIXME: need to test unimplemented options and robustly test wparam */
1552 static void test_EM_SETOPTIONS(void)
1555 static const char text
[] = "Hello. My name is RichEdit!";
1556 char buffer
[1024] = {0};
1557 DWORD dwStyle
, options
, oldOptions
;
1558 DWORD optionStyles
= ES_AUTOVSCROLL
|ES_AUTOHSCROLL
|ES_NOHIDESEL
|
1559 ES_READONLY
|ES_WANTRETURN
|ES_SAVESEL
|
1560 ES_SELECTIONBAR
|ES_VERTICAL
;
1562 /* Test initial options. */
1563 hwndRichEdit
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, WS_POPUP
,
1564 0, 0, 200, 60, NULL
, NULL
,
1565 hmoduleRichEdit
, NULL
);
1566 ok(hwndRichEdit
!= NULL
, "class: %s, error: %d\n",
1567 RICHEDIT_CLASS20A
, (int) GetLastError());
1568 options
= SendMessageA(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1569 ok(options
== 0, "Incorrect initial options %x\n", options
);
1570 DestroyWindow(hwndRichEdit
);
1572 hwndRichEdit
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
,
1573 WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
1574 0, 0, 200, 60, NULL
, NULL
,
1575 hmoduleRichEdit
, NULL
);
1576 ok(hwndRichEdit
!= NULL
, "class: %s, error: %d\n",
1577 RICHEDIT_CLASS20A
, (int) GetLastError());
1578 options
= SendMessageA(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1579 /* WS_[VH]SCROLL cause the ECO_AUTO[VH]SCROLL options to be set */
1580 ok(options
== (ECO_AUTOVSCROLL
|ECO_AUTOHSCROLL
),
1581 "Incorrect initial options %x\n", options
);
1583 /* NEGATIVE TESTING - NO OPTIONS SET */
1584 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
1585 SendMessageA(hwndRichEdit
, EM_SETOPTIONS
, ECOOP_SET
, 0);
1587 /* testing no readonly by sending 'a' to the control*/
1588 SendMessageA(hwndRichEdit
, WM_CHAR
, 'a', 0x1E0001);
1589 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1591 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text
, buffer
);
1592 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
1594 /* READONLY - sending 'a' to the control */
1595 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
1596 SendMessageA(hwndRichEdit
, EM_SETOPTIONS
, ECOOP_SET
, ECO_READONLY
);
1597 SendMessageA(hwndRichEdit
, WM_CHAR
, 'a', 0x1E0001);
1598 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1599 ok(buffer
[0]==text
[0],
1600 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text
, buffer
);
1602 /* EM_SETOPTIONS changes the window style, but changing the
1603 * window style does not change the options. */
1604 dwStyle
= GetWindowLongA(hwndRichEdit
, GWL_STYLE
);
1605 ok(dwStyle
& ES_READONLY
, "Readonly style not set by EM_SETOPTIONS\n");
1606 SetWindowLongA(hwndRichEdit
, GWL_STYLE
, dwStyle
& ~ES_READONLY
);
1607 options
= SendMessageA(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1608 ok(options
& ES_READONLY
, "Readonly option set by SetWindowLong\n");
1609 /* Confirm that the text is still read only. */
1610 SendMessageA(hwndRichEdit
, WM_CHAR
, 'a', ('a' << 16) | 0x0001);
1611 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1612 ok(buffer
[0]==text
[0],
1613 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text
, buffer
);
1615 oldOptions
= options
;
1616 SetWindowLongA(hwndRichEdit
, GWL_STYLE
, dwStyle
|optionStyles
);
1617 options
= SendMessageA(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1618 ok(options
== oldOptions
,
1619 "Options set by SetWindowLong (%x -> %x)\n", oldOptions
, options
);
1621 DestroyWindow(hwndRichEdit
);
1624 static BOOL
check_CFE_LINK_selection(HWND hwnd
, int sel_start
, int sel_end
)
1626 CHARFORMAT2A text_format
;
1627 text_format
.cbSize
= sizeof(text_format
);
1628 SendMessageA(hwnd
, EM_SETSEL
, sel_start
, sel_end
);
1629 SendMessageA(hwnd
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&text_format
);
1630 return (text_format
.dwEffects
& CFE_LINK
) != 0;
1633 static void check_CFE_LINK_rcvd(HWND hwnd
, BOOL is_url
, const char * url
)
1635 BOOL link_present
= FALSE
;
1637 link_present
= check_CFE_LINK_selection(hwnd
, 0, 1);
1639 { /* control text is url; should get CFE_LINK */
1640 ok(link_present
, "URL Case: CFE_LINK not set for [%s].\n", url
);
1644 ok(!link_present
, "Non-URL Case: CFE_LINK set for [%s].\n", url
);
1648 static HWND
new_static_wnd(HWND parent
) {
1649 return new_window("Static", 0, parent
);
1652 static void test_EM_AUTOURLDETECT(void)
1654 /* DO NOT change the properties of the first two elements. To shorten the
1655 tests, all tests after WM_SETTEXT test just the first two elements -
1656 one non-URL and one URL */
1661 {"winehq.org", FALSE
},
1662 {"http://www.winehq.org", TRUE
},
1663 {"http//winehq.org", FALSE
},
1664 {"ww.winehq.org", FALSE
},
1665 {"www.winehq.org", TRUE
},
1666 {"ftp://192.168.1.1", TRUE
},
1667 {"ftp//192.168.1.1", FALSE
},
1668 {"mailto:your@email.com", TRUE
},
1669 {"prospero:prosperoserver", TRUE
},
1670 {"telnet:test", TRUE
},
1671 {"news:newserver", TRUE
},
1672 {"wais:waisserver", TRUE
}
1677 HWND hwndRichEdit
, parent
;
1679 /* All of the following should cause the URL to be detected */
1680 const char * templates_delim
[] = {
1681 "This is some text with X on it",
1682 "This is some text with (X) on it",
1683 "This is some text with X\r on it",
1684 "This is some text with ---X--- on it",
1685 "This is some text with \"X\" on it",
1686 "This is some text with 'X' on it",
1687 "This is some text with 'X' on it",
1688 "This is some text with :X: on it",
1690 "This text ends with X",
1692 "This is some text with X) on it",
1693 "This is some text with X--- on it",
1694 "This is some text with X\" on it",
1695 "This is some text with X' on it",
1696 "This is some text with X: on it",
1698 "This is some text with (X on it",
1699 "This is some text with \rX on it",
1700 "This is some text with ---X on it",
1701 "This is some text with \"X on it",
1702 "This is some text with 'X on it",
1703 "This is some text with :X on it",
1705 /* None of these should cause the URL to be detected */
1706 const char * templates_non_delim
[] = {
1707 "This is some text with |X| on it",
1708 "This is some text with *X* on it",
1709 "This is some text with /X/ on it",
1710 "This is some text with +X+ on it",
1711 "This is some text with %X% on it",
1712 "This is some text with #X# on it",
1713 "This is some text with @X@ on it",
1714 "This is some text with \\X\\ on it",
1715 "This is some text with |X on it",
1716 "This is some text with *X on it",
1717 "This is some text with /X on it",
1718 "This is some text with +X on it",
1719 "This is some text with %X on it",
1720 "This is some text with #X on it",
1721 "This is some text with @X on it",
1722 "This is some text with \\X on it",
1724 /* All of these cause the URL detection to be extended by one more byte,
1725 thus demonstrating that the tested character is considered as part
1727 const char * templates_xten_delim
[] = {
1728 "This is some text with X| on it",
1729 "This is some text with X* on it",
1730 "This is some text with X/ on it",
1731 "This is some text with X+ on it",
1732 "This is some text with X% on it",
1733 "This is some text with X# on it",
1734 "This is some text with X@ on it",
1735 "This is some text with X\\ on it",
1739 parent
= new_static_wnd(NULL
);
1740 hwndRichEdit
= new_richedit(parent
);
1741 /* Try and pass EM_AUTOURLDETECT some test wParam values */
1742 urlRet
=SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, FALSE
, 0);
1743 ok(urlRet
==0, "Good wParam: urlRet is: %d\n", urlRet
);
1744 urlRet
=SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, 1, 0);
1745 ok(urlRet
==0, "Good wParam2: urlRet is: %d\n", urlRet
);
1746 /* Windows returns -2147024809 (0x80070057) on bad wParam values */
1747 urlRet
=SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, 8, 0);
1748 ok(urlRet
==E_INVALIDARG
, "Bad wParam: urlRet is: %d\n", urlRet
);
1749 urlRet
=SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, (WPARAM
)"h", (LPARAM
)"h");
1750 ok(urlRet
==E_INVALIDARG
, "Bad wParam2: urlRet is: %d\n", urlRet
);
1751 /* for each url, check the text to see if CFE_LINK effect is present */
1752 for (i
= 0; i
< sizeof(urls
)/sizeof(struct urls_s
); i
++) {
1754 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, FALSE
, 0);
1755 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)urls
[i
].text
);
1756 check_CFE_LINK_rcvd(hwndRichEdit
, FALSE
, urls
[i
].text
);
1758 /* Link detection should happen immediately upon WM_SETTEXT */
1759 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1760 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)urls
[i
].text
);
1761 check_CFE_LINK_rcvd(hwndRichEdit
, urls
[i
].is_url
, urls
[i
].text
);
1763 DestroyWindow(hwndRichEdit
);
1765 /* Test detection of URLs within normal text - WM_SETTEXT case. */
1766 for (i
= 0; i
< sizeof(urls
)/sizeof(struct urls_s
); i
++) {
1767 hwndRichEdit
= new_richedit(parent
);
1769 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
1774 at_pos
= strchr(templates_delim
[j
], 'X');
1775 at_offset
= at_pos
- templates_delim
[j
];
1776 memcpy(buffer
, templates_delim
[j
], at_offset
);
1777 buffer
[at_offset
] = '\0';
1778 strcat(buffer
, urls
[i
].text
);
1779 strcat(buffer
, templates_delim
[j
] + at_offset
+ 1);
1780 end_offset
= at_offset
+ strlen(urls
[i
].text
);
1782 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1783 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buffer
);
1785 /* This assumes no templates start with the URL itself, and that they
1786 have at least two characters before the URL text */
1787 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1788 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1789 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1790 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1791 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1792 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
1796 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1797 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
1798 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1799 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1803 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1804 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
1805 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1806 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1808 if (buffer
[end_offset
] != '\0')
1810 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1811 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
1812 if (buffer
[end_offset
+1] != '\0')
1814 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
1815 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
1820 for (j
= 0; j
< sizeof(templates_non_delim
) / sizeof(const char *); j
++) {
1825 at_pos
= strchr(templates_non_delim
[j
], 'X');
1826 at_offset
= at_pos
- templates_non_delim
[j
];
1827 memcpy(buffer
, templates_non_delim
[j
], at_offset
);
1828 buffer
[at_offset
] = '\0';
1829 strcat(buffer
, urls
[i
].text
);
1830 strcat(buffer
, templates_non_delim
[j
] + at_offset
+ 1);
1831 end_offset
= at_offset
+ strlen(urls
[i
].text
);
1833 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1834 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buffer
);
1836 /* This assumes no templates start with the URL itself, and that they
1837 have at least two characters before the URL text */
1838 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1839 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1840 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1841 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1842 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1843 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
1845 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1846 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
1847 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1848 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1849 if (buffer
[end_offset
] != '\0')
1851 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1852 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
1853 if (buffer
[end_offset
+1] != '\0')
1855 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
1856 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
1861 for (j
= 0; j
< sizeof(templates_xten_delim
) / sizeof(const char *); j
++) {
1866 at_pos
= strchr(templates_xten_delim
[j
], 'X');
1867 at_offset
= at_pos
- templates_xten_delim
[j
];
1868 memcpy(buffer
, templates_xten_delim
[j
], at_offset
);
1869 buffer
[at_offset
] = '\0';
1870 strcat(buffer
, urls
[i
].text
);
1871 strcat(buffer
, templates_xten_delim
[j
] + at_offset
+ 1);
1872 end_offset
= at_offset
+ strlen(urls
[i
].text
);
1874 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1875 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buffer
);
1877 /* This assumes no templates start with the URL itself, and that they
1878 have at least two characters before the URL text */
1879 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1880 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1881 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1882 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1883 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1884 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
1888 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1889 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
1890 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1891 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1892 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1893 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
, end_offset
+1, buffer
);
1897 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1898 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
1899 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1900 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1901 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1902 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+1, buffer
);
1904 if (buffer
[end_offset
+1] != '\0')
1906 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
1907 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+ 2, buffer
);
1908 if (buffer
[end_offset
+2] != '\0')
1910 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+2, end_offset
+3),
1911 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+2, end_offset
+3, buffer
);
1916 DestroyWindow(hwndRichEdit
);
1917 hwndRichEdit
= NULL
;
1920 /* Test detection of URLs within normal text - WM_CHAR case. */
1921 /* Test only the first two URL examples for brevity */
1922 for (i
= 0; i
< 2; i
++) {
1923 hwndRichEdit
= new_richedit(parent
);
1925 /* Also for brevity, test only the first three delimiters */
1926 for (j
= 0; j
< 3; j
++) {
1932 at_pos
= strchr(templates_delim
[j
], 'X');
1933 at_offset
= at_pos
- templates_delim
[j
];
1934 end_offset
= at_offset
+ strlen(urls
[i
].text
);
1936 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1937 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
1938 for (u
= 0; templates_delim
[j
][u
]; u
++) {
1939 if (templates_delim
[j
][u
] == '\r') {
1940 simulate_typing_characters(hwndRichEdit
, "\r");
1941 } else if (templates_delim
[j
][u
] != 'X') {
1942 SendMessageA(hwndRichEdit
, WM_CHAR
, templates_delim
[j
][u
], 1);
1944 for (v
= 0; urls
[i
].text
[v
]; v
++) {
1945 SendMessageA(hwndRichEdit
, WM_CHAR
, urls
[i
].text
[v
], 1);
1949 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
1951 /* This assumes no templates start with the URL itself, and that they
1952 have at least two characters before the URL text */
1953 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1954 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1955 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1956 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1957 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1958 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
1962 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1963 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
1964 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1965 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1969 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1970 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
1971 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1972 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1974 if (buffer
[end_offset
] != '\0')
1976 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1977 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
1978 if (buffer
[end_offset
+1] != '\0')
1980 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
1981 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
1985 /* The following will insert a paragraph break after the first character
1986 of the URL candidate, thus breaking the URL. It is expected that the
1987 CFE_LINK attribute should break across both pieces of the URL */
1988 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
+1, at_offset
+1);
1989 simulate_typing_characters(hwndRichEdit
, "\r");
1990 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
1992 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1993 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1994 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1995 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1996 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1997 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
1999 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2000 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2001 /* end_offset moved because of paragraph break */
2002 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2003 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+1, buffer
);
2004 ok(buffer
[end_offset
], "buffer \"%s\" ended prematurely. Is it missing a newline character?\n", buffer
);
2005 if (buffer
[end_offset
] != 0 && buffer
[end_offset
+1] != '\0')
2007 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2008 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2009 if (buffer
[end_offset
+2] != '\0')
2011 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+2, end_offset
+3),
2012 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+2, end_offset
+3, buffer
);
2016 /* The following will remove the just-inserted paragraph break, thus
2017 restoring the URL */
2018 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
+2, at_offset
+2);
2019 simulate_typing_characters(hwndRichEdit
, "\b");
2020 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2022 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2023 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2024 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2025 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2026 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2027 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2031 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2032 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2033 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2034 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2038 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2039 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2040 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2041 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2043 if (buffer
[end_offset
] != '\0')
2045 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2046 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2047 if (buffer
[end_offset
+1] != '\0')
2049 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2050 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2054 DestroyWindow(hwndRichEdit
);
2055 hwndRichEdit
= NULL
;
2058 /* Test detection of URLs within normal text - EM_SETTEXTEX case. */
2059 /* Test just the first two URL examples for brevity */
2060 for (i
= 0; i
< 2; i
++) {
2063 hwndRichEdit
= new_richedit(parent
);
2065 /* There are at least three ways in which EM_SETTEXTEX must cause URLs to
2067 1) Set entire text, a la WM_SETTEXT
2068 2) Set a selection of the text to the URL
2069 3) Set a portion of the text at a time, which eventually results in
2071 All of them should give equivalent results
2074 /* Set entire text in one go, like WM_SETTEXT */
2075 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2080 st
.codepage
= CP_ACP
;
2081 st
.flags
= ST_DEFAULT
;
2083 at_pos
= strchr(templates_delim
[j
], 'X');
2084 at_offset
= at_pos
- templates_delim
[j
];
2085 memcpy(buffer
, templates_delim
[j
], at_offset
);
2086 buffer
[at_offset
] = '\0';
2087 strcat(buffer
, urls
[i
].text
);
2088 strcat(buffer
, templates_delim
[j
] + at_offset
+ 1);
2089 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2091 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2092 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)buffer
);
2094 /* This assumes no templates start with the URL itself, and that they
2095 have at least two characters before the URL text */
2096 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2097 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2098 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2099 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2100 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2101 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2105 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2106 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2107 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2108 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2112 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2113 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2114 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2115 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2117 if (buffer
[end_offset
] != '\0')
2119 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2120 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2121 if (buffer
[end_offset
+1] != '\0')
2123 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2124 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2129 /* Set selection with X to the URL */
2130 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2135 at_pos
= strchr(templates_delim
[j
], 'X');
2136 at_offset
= at_pos
- templates_delim
[j
];
2137 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2139 st
.codepage
= CP_ACP
;
2140 st
.flags
= ST_DEFAULT
;
2141 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2142 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)templates_delim
[j
]);
2143 st
.flags
= ST_SELECTION
;
2144 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2145 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)urls
[i
].text
);
2146 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2148 /* This assumes no templates start with the URL itself, and that they
2149 have at least two characters before the URL text */
2150 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2151 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2152 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2153 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2154 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2155 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2159 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2160 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2161 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2162 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2166 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2167 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2168 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2169 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2171 if (buffer
[end_offset
] != '\0')
2173 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2174 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2175 if (buffer
[end_offset
+1] != '\0')
2177 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2178 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2183 /* Set selection with X to the first character of the URL, then the rest */
2184 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2189 at_pos
= strchr(templates_delim
[j
], 'X');
2190 at_offset
= at_pos
- templates_delim
[j
];
2191 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2193 strcpy(buffer
, "YY");
2194 buffer
[0] = urls
[i
].text
[0];
2196 st
.codepage
= CP_ACP
;
2197 st
.flags
= ST_DEFAULT
;
2198 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2199 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)templates_delim
[j
]);
2200 st
.flags
= ST_SELECTION
;
2201 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2202 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)buffer
);
2203 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
+1, at_offset
+2);
2204 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)(urls
[i
].text
+ 1));
2205 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2207 /* This assumes no templates start with the URL itself, and that they
2208 have at least two characters before the URL text */
2209 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2210 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2211 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2212 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2213 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2214 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2218 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2219 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2220 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2221 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2225 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2226 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2227 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2228 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2230 if (buffer
[end_offset
] != '\0')
2232 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2233 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2234 if (buffer
[end_offset
+1] != '\0')
2236 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2237 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2242 DestroyWindow(hwndRichEdit
);
2243 hwndRichEdit
= NULL
;
2246 /* Test detection of URLs within normal text - EM_REPLACESEL case. */
2247 /* Test just the first two URL examples for brevity */
2248 for (i
= 0; i
< 2; i
++) {
2249 hwndRichEdit
= new_richedit(parent
);
2251 /* Set selection with X to the URL */
2252 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2257 at_pos
= strchr(templates_delim
[j
], 'X');
2258 at_offset
= at_pos
- templates_delim
[j
];
2259 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2261 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2262 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)templates_delim
[j
]);
2263 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2264 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)urls
[i
].text
);
2265 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2267 /* This assumes no templates start with the URL itself, and that they
2268 have at least two characters before the URL text */
2269 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2270 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2271 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2272 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2273 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2274 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2278 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2279 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2280 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2281 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2285 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2286 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2287 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2288 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2290 if (buffer
[end_offset
] != '\0')
2292 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2293 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2294 if (buffer
[end_offset
+1] != '\0')
2296 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2297 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2302 /* Set selection with X to the first character of the URL, then the rest */
2303 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2308 at_pos
= strchr(templates_delim
[j
], 'X');
2309 at_offset
= at_pos
- templates_delim
[j
];
2310 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2312 strcpy(buffer
, "YY");
2313 buffer
[0] = urls
[i
].text
[0];
2315 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2316 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)templates_delim
[j
]);
2317 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2318 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)buffer
);
2319 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
+1, at_offset
+2);
2320 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)(urls
[i
].text
+ 1));
2321 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2323 /* This assumes no templates start with the URL itself, and that they
2324 have at least two characters before the URL text */
2325 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2326 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2327 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2328 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2329 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2330 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2334 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2335 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2336 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2337 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2341 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2342 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2343 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2344 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2346 if (buffer
[end_offset
] != '\0')
2348 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2349 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2350 if (buffer
[end_offset
+1] != '\0')
2352 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2353 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2358 DestroyWindow(hwndRichEdit
);
2359 hwndRichEdit
= NULL
;
2362 DestroyWindow(parent
);
2365 static void test_EM_SCROLL(void)
2368 int r
; /* return value */
2369 int expr
; /* expected return value */
2370 HWND hwndRichEdit
= new_richedit(NULL
);
2371 int y_before
, y_after
; /* units of lines of text */
2373 /* test a richedit box containing a single line of text */
2374 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");/* one line of text */
2376 for (i
= 0; i
< 4; i
++) {
2377 static const int cmd
[4] = { SB_PAGEDOWN
, SB_PAGEUP
, SB_LINEDOWN
, SB_LINEUP
};
2379 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, cmd
[i
], 0);
2380 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2381 ok(expr
== r
, "EM_SCROLL improper return value returned (i == %d). "
2382 "Got 0x%08x, expected 0x%08x\n", i
, r
, expr
);
2383 ok(y_after
== 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 "
2384 "(i == %d)\n", y_after
, i
);
2388 * test a richedit box that will scroll. There are two general
2389 * cases: the case without any long lines and the case with a long
2392 for (i
= 0; i
< 2; i
++) { /* iterate through different bodies of text */
2394 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a\nb\nc\nd\ne");
2396 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)
2397 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
2398 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
2399 "LONG LINE \nb\nc\nd\ne");
2400 for (j
= 0; j
< 12; j
++) /* reset scroll position to top */
2401 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_PAGEUP
, 0);
2403 /* get first visible line */
2404 y_before
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2405 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_PAGEDOWN
, 0); /* page down */
2407 /* get new current first visible line */
2408 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2410 ok(((r
& 0xffffff00) == 0x00010000) &&
2411 ((r
& 0x000000ff) != 0x00000000),
2412 "EM_SCROLL page down didn't scroll by a small positive number of "
2413 "lines (r == 0x%08x)\n", r
);
2414 ok(y_after
> y_before
, "EM_SCROLL page down not functioning "
2415 "(line %d scrolled to line %d\n", y_before
, y_after
);
2419 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_PAGEUP
, 0); /* page up */
2420 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2421 ok(((r
& 0xffffff00) == 0x0001ff00),
2422 "EM_SCROLL page up didn't scroll by a small negative number of lines "
2423 "(r == 0x%08x)\n", r
);
2424 ok(y_after
< y_before
, "EM_SCROLL page up not functioning (line "
2425 "%d scrolled to line %d\n", y_before
, y_after
);
2429 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0); /* line down */
2431 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2433 ok(r
== 0x00010001, "EM_SCROLL line down didn't scroll by one line "
2434 "(r == 0x%08x)\n", r
);
2435 ok(y_after
-1 == y_before
, "EM_SCROLL line down didn't go down by "
2436 "1 line (%d scrolled to %d)\n", y_before
, y_after
);
2440 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0); /* line up */
2442 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2444 ok(r
== 0x0001ffff, "EM_SCROLL line up didn't scroll by one line "
2445 "(r == 0x%08x)\n", r
);
2446 ok(y_after
+1 == y_before
, "EM_SCROLL line up didn't go up by 1 "
2447 "line (%d scrolled to %d)\n", y_before
, y_after
);
2451 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
,
2452 SB_LINEUP
, 0); /* lineup beyond top */
2454 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2457 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r
);
2458 ok(y_before
== y_after
,
2459 "EM_SCROLL line up beyond top worked (%d)\n", y_after
);
2463 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
,
2464 SB_PAGEUP
, 0);/*page up beyond top */
2466 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2469 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r
);
2470 ok(y_before
== y_after
,
2471 "EM_SCROLL page up beyond top worked (%d)\n", y_after
);
2473 for (j
= 0; j
< 12; j
++) /* page down all the way to the bottom */
2474 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_PAGEDOWN
, 0);
2475 y_before
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2476 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
,
2477 SB_PAGEDOWN
, 0); /* page down beyond bot */
2478 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2481 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r
);
2482 ok(y_before
== y_after
,
2483 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n",
2486 y_before
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2487 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0); /* line down beyond bot */
2488 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2491 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r
);
2492 ok(y_before
== y_after
,
2493 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n",
2496 DestroyWindow(hwndRichEdit
);
2499 static unsigned int recursionLevel
= 0;
2500 static unsigned int WM_SIZE_recursionLevel
= 0;
2501 static BOOL bailedOutOfRecursion
= FALSE
;
2502 static LRESULT (WINAPI
*richeditProc
)(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
);
2504 static LRESULT WINAPI
RicheditStupidOverrideProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
2508 if (bailedOutOfRecursion
) return 0;
2509 if (recursionLevel
>= 32) {
2510 bailedOutOfRecursion
= TRUE
;
2517 WM_SIZE_recursionLevel
++;
2518 r
= richeditProc(hwnd
, message
, wParam
, lParam
);
2519 /* Because, uhhhh... I never heard of ES_DISABLENOSCROLL */
2520 ShowScrollBar(hwnd
, SB_VERT
, TRUE
);
2521 WM_SIZE_recursionLevel
--;
2524 r
= richeditProc(hwnd
, message
, wParam
, lParam
);
2531 static void test_scrollbar_visibility(void)
2534 const char * text
="a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n";
2539 /* These tests show that richedit should temporarily refrain from automatically
2540 hiding or showing its scrollbars (vertical at least) when an explicit request
2541 is made via ShowScrollBar() or similar, outside of standard richedit logic.
2542 Some applications depend on forced showing (when otherwise richedit would
2543 hide the vertical scrollbar) and are thrown on an endless recursive loop
2544 if richedit auto-hides the scrollbar again. Apparently they never heard of
2545 the ES_DISABLENOSCROLL style... */
2547 hwndRichEdit
= new_richedit(NULL
);
2549 /* Test default scrollbar visibility behavior */
2550 memset(&si
, 0, sizeof(si
));
2551 si
.cbSize
= sizeof(si
);
2552 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2553 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2554 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2555 "Vertical scrollbar is visible, should be invisible.\n");
2556 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2557 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2558 si
.nPage
, si
.nMin
, si
.nMax
);
2560 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2561 memset(&si
, 0, sizeof(si
));
2562 si
.cbSize
= sizeof(si
);
2563 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2564 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2565 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2566 "Vertical scrollbar is visible, should be invisible.\n");
2567 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2568 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2569 si
.nPage
, si
.nMin
, si
.nMax
);
2571 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2572 memset(&si
, 0, sizeof(si
));
2573 si
.cbSize
= sizeof(si
);
2574 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2575 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2576 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2577 "Vertical scrollbar is invisible, should be visible.\n");
2578 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2579 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2580 si
.nPage
, si
.nMin
, si
.nMax
);
2582 /* Oddly, setting text to NULL does *not* reset the scrollbar range,
2583 even though it hides the scrollbar */
2584 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2585 memset(&si
, 0, sizeof(si
));
2586 si
.cbSize
= sizeof(si
);
2587 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2588 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2589 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2590 "Vertical scrollbar is visible, should be invisible.\n");
2591 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2592 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2593 si
.nPage
, si
.nMin
, si
.nMax
);
2595 /* Setting non-scrolling text again does *not* reset scrollbar range */
2596 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2597 memset(&si
, 0, sizeof(si
));
2598 si
.cbSize
= sizeof(si
);
2599 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2600 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2601 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2602 "Vertical scrollbar is visible, should be invisible.\n");
2603 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2604 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2605 si
.nPage
, si
.nMin
, si
.nMax
);
2607 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2608 memset(&si
, 0, sizeof(si
));
2609 si
.cbSize
= sizeof(si
);
2610 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2611 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2612 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2613 "Vertical scrollbar is visible, should be invisible.\n");
2614 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2615 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2616 si
.nPage
, si
.nMin
, si
.nMax
);
2618 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2619 memset(&si
, 0, sizeof(si
));
2620 si
.cbSize
= sizeof(si
);
2621 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2622 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2623 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2624 "Vertical scrollbar is visible, should be invisible.\n");
2625 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2626 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2627 si
.nPage
, si
.nMin
, si
.nMax
);
2629 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
2630 memset(&si
, 0, sizeof(si
));
2631 si
.cbSize
= sizeof(si
);
2632 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2633 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2634 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2635 "Vertical scrollbar is visible, should be invisible.\n");
2636 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2637 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2638 si
.nPage
, si
.nMin
, si
.nMax
);
2640 DestroyWindow(hwndRichEdit
);
2642 /* Test again, with ES_DISABLENOSCROLL style */
2643 hwndRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
|ES_DISABLENOSCROLL
, NULL
);
2645 /* Test default scrollbar visibility behavior */
2646 memset(&si
, 0, sizeof(si
));
2647 si
.cbSize
= sizeof(si
);
2648 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2649 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2650 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2651 "Vertical scrollbar is invisible, should be visible.\n");
2652 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 1,
2653 "reported page/range is %d (%d..%d) expected 0 (0..1)\n",
2654 si
.nPage
, si
.nMin
, si
.nMax
);
2656 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2657 memset(&si
, 0, sizeof(si
));
2658 si
.cbSize
= sizeof(si
);
2659 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2660 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2661 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2662 "Vertical scrollbar is invisible, should be visible.\n");
2663 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 1,
2664 "reported page/range is %d (%d..%d) expected 0 (0..1)\n",
2665 si
.nPage
, si
.nMin
, si
.nMax
);
2667 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2668 memset(&si
, 0, sizeof(si
));
2669 si
.cbSize
= sizeof(si
);
2670 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2671 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2672 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2673 "Vertical scrollbar is invisible, should be visible.\n");
2674 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2675 "reported page/range is %d (%d..%d)\n",
2676 si
.nPage
, si
.nMin
, si
.nMax
);
2678 /* Oddly, setting text to NULL does *not* reset the scrollbar range */
2679 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2680 memset(&si
, 0, sizeof(si
));
2681 si
.cbSize
= sizeof(si
);
2682 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2683 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2684 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2685 "Vertical scrollbar is invisible, should be visible.\n");
2686 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2687 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2688 si
.nPage
, si
.nMin
, si
.nMax
);
2690 /* Setting non-scrolling text again does *not* reset scrollbar range */
2691 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2692 memset(&si
, 0, sizeof(si
));
2693 si
.cbSize
= sizeof(si
);
2694 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2695 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2696 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2697 "Vertical scrollbar is invisible, should be visible.\n");
2698 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2699 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2700 si
.nPage
, si
.nMin
, si
.nMax
);
2702 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2703 memset(&si
, 0, sizeof(si
));
2704 si
.cbSize
= sizeof(si
);
2705 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2706 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2707 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2708 "Vertical scrollbar is invisible, should be visible.\n");
2709 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2710 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2711 si
.nPage
, si
.nMin
, si
.nMax
);
2713 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2714 memset(&si
, 0, sizeof(si
));
2715 si
.cbSize
= sizeof(si
);
2716 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2717 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2718 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2719 "Vertical scrollbar is invisible, should be visible.\n");
2720 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2721 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2722 si
.nPage
, si
.nMin
, si
.nMax
);
2724 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
2725 memset(&si
, 0, sizeof(si
));
2726 si
.cbSize
= sizeof(si
);
2727 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2728 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2729 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2730 "Vertical scrollbar is invisible, should be visible.\n");
2731 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2732 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2733 si
.nPage
, si
.nMin
, si
.nMax
);
2735 DestroyWindow(hwndRichEdit
);
2737 /* Test behavior with explicit visibility request, using ShowScrollBar() */
2738 hwndRichEdit
= new_richedit(NULL
);
2740 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */
2741 ShowScrollBar(hwndRichEdit
, SB_VERT
, TRUE
);
2742 memset(&si
, 0, sizeof(si
));
2743 si
.cbSize
= sizeof(si
);
2744 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2745 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2746 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2747 "Vertical scrollbar is invisible, should be visible.\n");
2749 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2750 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2751 si
.nPage
, si
.nMin
, si
.nMax
);
2754 /* Ditto, see above */
2755 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2756 memset(&si
, 0, sizeof(si
));
2757 si
.cbSize
= sizeof(si
);
2758 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2759 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2760 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2761 "Vertical scrollbar is invisible, should be visible.\n");
2763 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2764 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2765 si
.nPage
, si
.nMin
, si
.nMax
);
2768 /* Ditto, see above */
2769 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2770 memset(&si
, 0, sizeof(si
));
2771 si
.cbSize
= sizeof(si
);
2772 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2773 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2774 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2775 "Vertical scrollbar is invisible, should be visible.\n");
2777 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2778 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2779 si
.nPage
, si
.nMin
, si
.nMax
);
2782 /* Ditto, see above */
2783 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a\na");
2784 memset(&si
, 0, sizeof(si
));
2785 si
.cbSize
= sizeof(si
);
2786 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2787 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2788 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2789 "Vertical scrollbar is invisible, should be visible.\n");
2791 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2792 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2793 si
.nPage
, si
.nMin
, si
.nMax
);
2796 /* Ditto, see above */
2797 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2798 memset(&si
, 0, sizeof(si
));
2799 si
.cbSize
= sizeof(si
);
2800 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2801 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2802 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2803 "Vertical scrollbar is invisible, should be visible.\n");
2805 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2806 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2807 si
.nPage
, si
.nMin
, si
.nMax
);
2810 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2811 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2812 memset(&si
, 0, sizeof(si
));
2813 si
.cbSize
= sizeof(si
);
2814 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2815 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2816 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2817 "Vertical scrollbar is visible, should be invisible.\n");
2818 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2819 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2820 si
.nPage
, si
.nMin
, si
.nMax
);
2822 DestroyWindow(hwndRichEdit
);
2824 hwndRichEdit
= new_richedit(NULL
);
2826 ShowScrollBar(hwndRichEdit
, SB_VERT
, FALSE
);
2827 memset(&si
, 0, sizeof(si
));
2828 si
.cbSize
= sizeof(si
);
2829 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2830 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2831 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2832 "Vertical scrollbar is visible, should be invisible.\n");
2833 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2834 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2835 si
.nPage
, si
.nMin
, si
.nMax
);
2837 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2838 memset(&si
, 0, sizeof(si
));
2839 si
.cbSize
= sizeof(si
);
2840 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2841 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2842 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2843 "Vertical scrollbar is visible, should be invisible.\n");
2844 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2845 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2846 si
.nPage
, si
.nMin
, si
.nMax
);
2848 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2849 memset(&si
, 0, sizeof(si
));
2850 si
.cbSize
= sizeof(si
);
2851 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2852 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2853 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2854 "Vertical scrollbar is visible, should be invisible.\n");
2855 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2856 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2857 si
.nPage
, si
.nMin
, si
.nMax
);
2859 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2860 memset(&si
, 0, sizeof(si
));
2861 si
.cbSize
= sizeof(si
);
2862 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2863 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2864 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2865 "Vertical scrollbar is visible, should be invisible.\n");
2866 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2867 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2868 si
.nPage
, si
.nMin
, si
.nMax
);
2870 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2871 memset(&si
, 0, sizeof(si
));
2872 si
.cbSize
= sizeof(si
);
2873 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2874 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2875 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2876 "Vertical scrollbar is invisible, should be visible.\n");
2877 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2878 "reported page/range is %d (%d..%d)\n",
2879 si
.nPage
, si
.nMin
, si
.nMax
);
2881 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */
2882 ShowScrollBar(hwndRichEdit
, SB_VERT
, FALSE
);
2883 memset(&si
, 0, sizeof(si
));
2884 si
.cbSize
= sizeof(si
);
2885 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2886 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2887 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2888 "Vertical scrollbar is visible, should be invisible.\n");
2889 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2890 "reported page/range is %d (%d..%d)\n",
2891 si
.nPage
, si
.nMin
, si
.nMax
);
2893 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2894 memset(&si
, 0, sizeof(si
));
2895 si
.cbSize
= sizeof(si
);
2896 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2897 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2898 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2899 "Vertical scrollbar is visible, should be invisible.\n");
2900 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2901 "reported page/range is %d (%d..%d)\n",
2902 si
.nPage
, si
.nMin
, si
.nMax
);
2904 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that
2905 EM_SCROLL will make visible any forcefully invisible scrollbar */
2906 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0);
2907 memset(&si
, 0, sizeof(si
));
2908 si
.cbSize
= sizeof(si
);
2909 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2910 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2911 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2912 "Vertical scrollbar is invisible, should be visible.\n");
2913 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2914 "reported page/range is %d (%d..%d)\n",
2915 si
.nPage
, si
.nMin
, si
.nMax
);
2917 ShowScrollBar(hwndRichEdit
, SB_VERT
, FALSE
);
2918 memset(&si
, 0, sizeof(si
));
2919 si
.cbSize
= sizeof(si
);
2920 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2921 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2922 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2923 "Vertical scrollbar is visible, should be invisible.\n");
2924 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2925 "reported page/range is %d (%d..%d)\n",
2926 si
.nPage
, si
.nMin
, si
.nMax
);
2928 /* Again, EM_SCROLL, with SB_LINEUP */
2929 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0);
2930 memset(&si
, 0, sizeof(si
));
2931 si
.cbSize
= sizeof(si
);
2932 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2933 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2934 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2935 "Vertical scrollbar is invisible, should be visible.\n");
2936 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2937 "reported page/range is %d (%d..%d)\n",
2938 si
.nPage
, si
.nMin
, si
.nMax
);
2940 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2941 memset(&si
, 0, sizeof(si
));
2942 si
.cbSize
= sizeof(si
);
2943 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2944 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2945 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2946 "Vertical scrollbar is visible, should be invisible.\n");
2947 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2948 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2949 si
.nPage
, si
.nMin
, si
.nMax
);
2951 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2952 memset(&si
, 0, sizeof(si
));
2953 si
.cbSize
= sizeof(si
);
2954 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2955 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2956 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2957 "Vertical scrollbar is invisible, should be visible.\n");
2958 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2959 "reported page/range is %d (%d..%d)\n",
2960 si
.nPage
, si
.nMin
, si
.nMax
);
2962 DestroyWindow(hwndRichEdit
);
2965 /* Test behavior with explicit visibility request, using SetWindowLongA()() */
2966 hwndRichEdit
= new_richedit(NULL
);
2968 #define ENABLE_WS_VSCROLL(hwnd) \
2969 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) | WS_VSCROLL)
2970 #define DISABLE_WS_VSCROLL(hwnd) \
2971 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) & ~WS_VSCROLL)
2973 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */
2974 ENABLE_WS_VSCROLL(hwndRichEdit
);
2975 memset(&si
, 0, sizeof(si
));
2976 si
.cbSize
= sizeof(si
);
2977 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2978 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2979 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2980 "Vertical scrollbar is invisible, should be visible.\n");
2981 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2982 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2983 si
.nPage
, si
.nMin
, si
.nMax
);
2985 /* Ditto, see above */
2986 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2987 memset(&si
, 0, sizeof(si
));
2988 si
.cbSize
= sizeof(si
);
2989 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2990 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2991 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2992 "Vertical scrollbar is invisible, should be visible.\n");
2993 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2994 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2995 si
.nPage
, si
.nMin
, si
.nMax
);
2997 /* Ditto, see above */
2998 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
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
== 0 || si
.nMax
== 100),
3006 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3007 si
.nPage
, si
.nMin
, si
.nMax
);
3009 /* Ditto, see above */
3010 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a\na");
3011 memset(&si
, 0, sizeof(si
));
3012 si
.cbSize
= sizeof(si
);
3013 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3014 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3015 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3016 "Vertical scrollbar is invisible, should be visible.\n");
3017 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3018 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3019 si
.nPage
, si
.nMin
, si
.nMax
);
3021 /* Ditto, see above */
3022 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3023 memset(&si
, 0, sizeof(si
));
3024 si
.cbSize
= sizeof(si
);
3025 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3026 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3027 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3028 "Vertical scrollbar is invisible, should be visible.\n");
3029 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3030 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3031 si
.nPage
, si
.nMin
, si
.nMax
);
3033 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3034 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3035 memset(&si
, 0, sizeof(si
));
3036 si
.cbSize
= sizeof(si
);
3037 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3038 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3039 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3040 "Vertical scrollbar is visible, should be invisible.\n");
3041 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3042 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3043 si
.nPage
, si
.nMin
, si
.nMax
);
3045 DestroyWindow(hwndRichEdit
);
3047 hwndRichEdit
= new_richedit(NULL
);
3049 DISABLE_WS_VSCROLL(hwndRichEdit
);
3050 memset(&si
, 0, sizeof(si
));
3051 si
.cbSize
= sizeof(si
);
3052 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3053 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3054 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3055 "Vertical scrollbar is visible, should be invisible.\n");
3056 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3057 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3058 si
.nPage
, si
.nMin
, si
.nMax
);
3060 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3061 memset(&si
, 0, sizeof(si
));
3062 si
.cbSize
= sizeof(si
);
3063 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3064 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3065 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3066 "Vertical scrollbar is visible, should be invisible.\n");
3067 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3068 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3069 si
.nPage
, si
.nMin
, si
.nMax
);
3071 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
3072 memset(&si
, 0, sizeof(si
));
3073 si
.cbSize
= sizeof(si
);
3074 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3075 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3076 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3077 "Vertical scrollbar is visible, should be invisible.\n");
3078 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3079 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3080 si
.nPage
, si
.nMin
, si
.nMax
);
3082 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3083 memset(&si
, 0, sizeof(si
));
3084 si
.cbSize
= sizeof(si
);
3085 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3086 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3087 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3088 "Vertical scrollbar is visible, should be invisible.\n");
3089 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3090 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3091 si
.nPage
, si
.nMin
, si
.nMax
);
3093 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3094 memset(&si
, 0, sizeof(si
));
3095 si
.cbSize
= sizeof(si
);
3096 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3097 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3098 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3099 "Vertical scrollbar is invisible, should be visible.\n");
3100 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3101 "reported page/range is %d (%d..%d)\n",
3102 si
.nPage
, si
.nMin
, si
.nMax
);
3104 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */
3105 DISABLE_WS_VSCROLL(hwndRichEdit
);
3106 memset(&si
, 0, sizeof(si
));
3107 si
.cbSize
= sizeof(si
);
3108 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3109 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3110 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3111 "Vertical scrollbar is visible, should be invisible.\n");
3112 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3113 "reported page/range is %d (%d..%d)\n",
3114 si
.nPage
, si
.nMin
, si
.nMax
);
3116 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3117 memset(&si
, 0, sizeof(si
));
3118 si
.cbSize
= sizeof(si
);
3119 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3120 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3121 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3122 "Vertical scrollbar is visible, should be invisible.\n");
3123 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3124 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3125 si
.nPage
, si
.nMin
, si
.nMax
);
3127 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3128 memset(&si
, 0, sizeof(si
));
3129 si
.cbSize
= sizeof(si
);
3130 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3131 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3132 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3133 "Vertical scrollbar is invisible, should be visible.\n");
3134 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3135 "reported page/range is %d (%d..%d)\n",
3136 si
.nPage
, si
.nMin
, si
.nMax
);
3138 DISABLE_WS_VSCROLL(hwndRichEdit
);
3139 memset(&si
, 0, sizeof(si
));
3140 si
.cbSize
= sizeof(si
);
3141 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3142 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3143 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3144 "Vertical scrollbar is visible, should be invisible.\n");
3145 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3146 "reported page/range is %d (%d..%d)\n",
3147 si
.nPage
, si
.nMin
, si
.nMax
);
3149 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that
3150 EM_SCROLL will make visible any forcefully invisible scrollbar */
3151 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0);
3152 memset(&si
, 0, sizeof(si
));
3153 si
.cbSize
= sizeof(si
);
3154 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3155 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3156 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3157 "Vertical scrollbar is invisible, should be visible.\n");
3158 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3159 "reported page/range is %d (%d..%d)\n",
3160 si
.nPage
, si
.nMin
, si
.nMax
);
3162 DISABLE_WS_VSCROLL(hwndRichEdit
);
3163 memset(&si
, 0, sizeof(si
));
3164 si
.cbSize
= sizeof(si
);
3165 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3166 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3167 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3168 "Vertical scrollbar is visible, should be invisible.\n");
3169 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3170 "reported page/range is %d (%d..%d)\n",
3171 si
.nPage
, si
.nMin
, si
.nMax
);
3173 /* Again, EM_SCROLL, with SB_LINEUP */
3174 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0);
3175 memset(&si
, 0, sizeof(si
));
3176 si
.cbSize
= sizeof(si
);
3177 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3178 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3179 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3180 "Vertical scrollbar is invisible, should be visible.\n");
3181 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3182 "reported page/range is %d (%d..%d)\n",
3183 si
.nPage
, si
.nMin
, si
.nMax
);
3185 DestroyWindow(hwndRichEdit
);
3187 /* This window proc models what is going on with Corman Lisp 3.0.
3188 At WM_SIZE, this proc unconditionally calls ShowScrollBar() to
3189 force the scrollbar into visibility. Recursion should NOT happen
3190 as a result of this action.
3192 r
= GetClassInfoA(NULL
, RICHEDIT_CLASS20A
, &cls
);
3194 richeditProc
= cls
.lpfnWndProc
;
3195 cls
.lpfnWndProc
= RicheditStupidOverrideProcA
;
3196 cls
.lpszClassName
= "RicheditStupidOverride";
3197 if(!RegisterClassA(&cls
)) assert(0);
3200 WM_SIZE_recursionLevel
= 0;
3201 bailedOutOfRecursion
= FALSE
;
3202 hwndRichEdit
= new_window(cls
.lpszClassName
, ES_MULTILINE
, NULL
);
3203 ok(!bailedOutOfRecursion
,
3204 "WM_SIZE/scrollbar mutual recursion detected, expected none!\n");
3207 WM_SIZE_recursionLevel
= 0;
3208 bailedOutOfRecursion
= FALSE
;
3209 MoveWindow(hwndRichEdit
, 0, 0, 250, 100, TRUE
);
3210 ok(!bailedOutOfRecursion
,
3211 "WM_SIZE/scrollbar mutual recursion detected, expected none!\n");
3213 /* Unblock window in order to process WM_DESTROY */
3215 bailedOutOfRecursion
= FALSE
;
3216 WM_SIZE_recursionLevel
= 0;
3217 DestroyWindow(hwndRichEdit
);
3221 static void test_EM_SETUNDOLIMIT(void)
3223 /* cases we test for:
3224 * default behaviour - limiting at 100 undo's
3225 * undo disabled - setting a limit of 0
3226 * undo limited - undo limit set to some to some number, like 2
3227 * bad input - sending a negative number should default to 100 undo's */
3229 HWND hwndRichEdit
= new_richedit(NULL
);
3234 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"x");
3237 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
3238 /*Load "x" into the clipboard. Paste is an easy, undo'able operation.
3239 also, multiple pastes don't combine like WM_CHAR would */
3240 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
3242 /* first case - check the default */
3243 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
3244 for (i
=0; i
<101; i
++) /* Put 101 undo's on the stack */
3245 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
3246 for (i
=0; i
<100; i
++) /* Undo 100 of them */
3247 SendMessageA(hwndRichEdit
, WM_UNDO
, 0, 0);
3248 ok(!SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0),
3249 "EM_SETUNDOLIMIT allowed more than a hundred undo's by default.\n");
3251 /* second case - cannot undo */
3252 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0, 0);
3253 SendMessageA(hwndRichEdit
, EM_SETUNDOLIMIT
, 0, 0);
3254 SendMessageA(hwndRichEdit
,
3255 WM_PASTE
, 0, 0); /* Try to put something in the undo stack */
3256 ok(!SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0),
3257 "EM_SETUNDOLIMIT allowed undo with UNDOLIMIT set to 0\n");
3259 /* third case - set it to an arbitrary number */
3260 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0, 0);
3261 SendMessageA(hwndRichEdit
, EM_SETUNDOLIMIT
, 2, 0);
3262 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
3263 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
3264 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
3265 /* If SETUNDOLIMIT is working, there should only be two undo's after this */
3266 ok(SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0,0),
3267 "EM_SETUNDOLIMIT didn't allow the first undo with UNDOLIMIT set to 2\n");
3268 SendMessageA(hwndRichEdit
, WM_UNDO
, 0, 0);
3269 ok(SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0),
3270 "EM_SETUNDOLIMIT didn't allow a second undo with UNDOLIMIT set to 2\n");
3271 SendMessageA(hwndRichEdit
, WM_UNDO
, 0, 0);
3272 ok(!SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0),
3273 "EM_SETUNDOLIMIT allowed a third undo with UNDOLIMIT set to 2\n");
3275 /* fourth case - setting negative numbers should default to 100 undos */
3276 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
3277 result
= SendMessageA(hwndRichEdit
, EM_SETUNDOLIMIT
, -1, 0);
3279 "EM_SETUNDOLIMIT returned %d when set to -1, instead of 100\n",result
);
3281 DestroyWindow(hwndRichEdit
);
3284 static void test_ES_PASSWORD(void)
3286 /* This isn't hugely testable, so we're just going to run it through its paces */
3288 HWND hwndRichEdit
= new_richedit(NULL
);
3291 /* First, check the default of a regular control */
3292 result
= SendMessageA(hwndRichEdit
, EM_GETPASSWORDCHAR
, 0, 0);
3294 "EM_GETPASSWORDCHAR returned %c by default, instead of NULL\n",result
);
3296 /* Now, set it to something normal */
3297 SendMessageA(hwndRichEdit
, EM_SETPASSWORDCHAR
, 'x', 0);
3298 result
= SendMessageA(hwndRichEdit
, EM_GETPASSWORDCHAR
, 0, 0);
3300 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result
,result
);
3302 /* Now, set it to something odd */
3303 SendMessageA(hwndRichEdit
, EM_SETPASSWORDCHAR
, (WCHAR
)1234, 0);
3304 result
= SendMessageA(hwndRichEdit
, EM_GETPASSWORDCHAR
, 0, 0);
3306 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result
,result
);
3307 DestroyWindow(hwndRichEdit
);
3310 static DWORD CALLBACK
test_WM_SETTEXT_esCallback(DWORD_PTR dwCookie
,
3315 char** str
= (char**)dwCookie
;
3318 memcpy(*str
, pbBuff
, *pcb
);
3324 static void test_WM_SETTEXT(void)
3326 HWND hwndRichEdit
= new_richedit(NULL
);
3327 const char * TestItem1
= "TestSomeText";
3328 const char * TestItem2
= "TestSomeText\r";
3329 const char * TestItem2_after
= "TestSomeText\r\n";
3330 const char * TestItem3
= "TestSomeText\rSomeMoreText\r";
3331 const char * TestItem3_after
= "TestSomeText\r\nSomeMoreText\r\n";
3332 const char * TestItem4
= "TestSomeText\n\nTestSomeText";
3333 const char * TestItem4_after
= "TestSomeText\r\n\r\nTestSomeText";
3334 const char * TestItem5
= "TestSomeText\r\r\nTestSomeText";
3335 const char * TestItem5_after
= "TestSomeText TestSomeText";
3336 const char * TestItem6
= "TestSomeText\r\r\n\rTestSomeText";
3337 const char * TestItem6_after
= "TestSomeText \r\nTestSomeText";
3338 const char * TestItem7
= "TestSomeText\r\n\r\r\n\rTestSomeText";
3339 const char * TestItem7_after
= "TestSomeText\r\n \r\nTestSomeText";
3341 const char rtftextA
[] = "{\\rtf sometext}";
3342 const char urtftextA
[] = "{\\urtf sometext}";
3343 const WCHAR rtftextW
[] = {'{','\\','r','t','f',' ','s','o','m','e','t','e','x','t','}',0};
3344 const WCHAR urtftextW
[] = {'{','\\','u','r','t','f',' ','s','o','m','e','t','e','x','t','}',0};
3345 const WCHAR sometextW
[] = {'s','o','m','e','t','e','x','t',0};
3347 char buf
[1024] = {0};
3348 WCHAR bufW
[1024] = {0};
3351 /* This test attempts to show that WM_SETTEXT on a riched20 control causes
3352 any solitary \r to be converted to \r\n on return. Properly paired
3353 \r\n are not affected. It also shows that the special sequence \r\r\n
3354 gets converted to a single space.
3357 #define TEST_SETTEXT(a, b) \
3358 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)a); \
3359 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \
3360 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf); \
3361 ok (result == lstrlenA(buf), \
3362 "WM_GETTEXT returned %ld instead of expected %u\n", \
3363 result, lstrlenA(buf)); \
3364 result = strcmp(b, buf); \
3366 "WM_SETTEXT round trip: strcmp = %ld, text=\"%s\"\n", result, buf);
3368 TEST_SETTEXT(TestItem1
, TestItem1
)
3369 TEST_SETTEXT(TestItem2
, TestItem2_after
)
3370 TEST_SETTEXT(TestItem3
, TestItem3_after
)
3371 TEST_SETTEXT(TestItem3_after
, TestItem3_after
)
3372 TEST_SETTEXT(TestItem4
, TestItem4_after
)
3373 TEST_SETTEXT(TestItem5
, TestItem5_after
)
3374 TEST_SETTEXT(TestItem6
, TestItem6_after
)
3375 TEST_SETTEXT(TestItem7
, TestItem7_after
)
3377 /* The following tests demonstrate that WM_SETTEXT supports RTF strings */
3378 TEST_SETTEXT(rtftextA
, "sometext") /* interpreted as ascii rtf */
3379 TEST_SETTEXT(urtftextA
, "sometext") /* interpreted as ascii rtf */
3380 TEST_SETTEXT(rtftextW
, "{") /* interpreted as ascii text */
3381 TEST_SETTEXT(urtftextW
, "{") /* interpreted as ascii text */
3382 DestroyWindow(hwndRichEdit
);
3385 #define TEST_SETTEXTW(a, b) \
3386 result = SendMessageW(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)a); \
3387 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \
3388 result = SendMessageW(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufW); \
3389 ok (result == lstrlenW(bufW), \
3390 "WM_GETTEXT returned %ld instead of expected %u\n", \
3391 result, lstrlenW(bufW)); \
3392 result = lstrcmpW(b, bufW); \
3393 ok(result == 0, "WM_SETTEXT round trip: strcmp = %ld\n", result);
3395 hwndRichEdit
= CreateWindowW(RICHEDIT_CLASS20W
, NULL
,
3396 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
3397 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
3398 ok(hwndRichEdit
!= NULL
, "class: RichEdit20W, error: %d\n", (int) GetLastError());
3399 TEST_SETTEXTW(rtftextA
, sometextW
) /* interpreted as ascii rtf */
3400 TEST_SETTEXTW(urtftextA
, sometextW
) /* interpreted as ascii rtf */
3401 TEST_SETTEXTW(rtftextW
, rtftextW
) /* interpreted as ascii text */
3402 TEST_SETTEXTW(urtftextW
, urtftextW
) /* interpreted as ascii text */
3403 DestroyWindow(hwndRichEdit
);
3404 #undef TEST_SETTEXTW
3407 static void test_EM_STREAMOUT(void)
3409 HWND hwndRichEdit
= new_richedit(NULL
);
3412 char buf
[1024] = {0};
3415 const char * TestItem1
= "TestSomeText";
3416 const char * TestItem2
= "TestSomeText\r";
3417 const char * TestItem3
= "TestSomeText\r\n";
3419 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem1
);
3421 es
.dwCookie
= (DWORD_PTR
)&p
;
3423 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3424 memset(buf
, 0, sizeof(buf
));
3425 SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_TEXT
, (LPARAM
)&es
);
3427 ok(r
== 12, "streamed text length is %d, expecting 12\n", r
);
3428 ok(strcmp(buf
, TestItem1
) == 0,
3429 "streamed text different, got %s\n", buf
);
3431 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem2
);
3433 es
.dwCookie
= (DWORD_PTR
)&p
;
3435 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3436 memset(buf
, 0, sizeof(buf
));
3437 SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_TEXT
, (LPARAM
)&es
);
3439 /* Here again, \r gets converted to \r\n, like WM_GETTEXT */
3440 ok(r
== 14, "streamed text length is %d, expecting 14\n", r
);
3441 ok(strcmp(buf
, TestItem3
) == 0,
3442 "streamed text different from, got %s\n", buf
);
3443 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem3
);
3445 es
.dwCookie
= (DWORD_PTR
)&p
;
3447 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3448 memset(buf
, 0, sizeof(buf
));
3449 SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_TEXT
, (LPARAM
)&es
);
3451 ok(r
== 14, "streamed text length is %d, expecting 14\n", r
);
3452 ok(strcmp(buf
, TestItem3
) == 0,
3453 "streamed text different, got %s\n", buf
);
3455 DestroyWindow(hwndRichEdit
);
3458 static void test_EM_STREAMOUT_FONTTBL(void)
3460 HWND hwndRichEdit
= new_richedit(NULL
);
3462 char buf
[1024] = {0};
3467 const char * TestItem
= "TestSomeText";
3469 /* fills in the richedit control with some text */
3470 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem
);
3472 /* streams out the text in rtf format */
3474 es
.dwCookie
= (DWORD_PTR
)&p
;
3476 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3477 memset(buf
, 0, sizeof(buf
));
3478 SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_RTF
, (LPARAM
)&es
);
3480 /* scans for \fonttbl, error if not found */
3481 fontTbl
= strstr(buf
, "\\fonttbl");
3482 ok(fontTbl
!= NULL
, "missing \\fonttbl section\n");
3485 /* scans for terminating closing bracket */
3487 while(*fontTbl
&& brackCount
)
3491 else if(*fontTbl
== '}')
3495 /* checks whether closing bracket is ok */
3496 ok(brackCount
== 0, "missing closing bracket in \\fonttbl block\n");
3499 /* char before closing fonttbl block should be a closed bracket */
3501 ok(*fontTbl
== '}', "spurious character '%02x' before \\fonttbl closing bracket\n", *fontTbl
);
3503 /* char after fonttbl block should be a crlf */
3505 ok(*fontTbl
== 0x0d && *(fontTbl
+1) == 0x0a, "missing crlf after \\fonttbl block\n");
3508 DestroyWindow(hwndRichEdit
);
3512 static void test_EM_SETTEXTEX(void)
3514 HWND hwndRichEdit
, parent
;
3516 int sel_start
, sel_end
;
3519 WCHAR TestItem1
[] = {'T', 'e', 's', 't',
3521 'T', 'e', 'x', 't', 0};
3522 WCHAR TestItem1alt
[] = {'T', 'T', 'e', 's',
3528 WCHAR TestItem1altn
[] = {'T','T','e','s','t','S','o','m','e','T','e','x','t',
3529 '\r','t','S','o','m','e','T','e','x','t',0};
3530 WCHAR TestItem2
[] = {'T', 'e', 's', 't',
3534 const char * TestItem2_after
= "TestSomeText\r\n";
3535 WCHAR TestItem3
[] = {'T', 'e', 's', 't',
3538 '\r','\n','\r','\n', 0};
3539 WCHAR TestItem3alt
[] = {'T', 'e', 's', 't',
3543 WCHAR TestItem3_after
[] = {'T', 'e', 's', 't',
3547 WCHAR TestItem4
[] = {'T', 'e', 's', 't',
3550 '\r','\r','\n','\r',
3552 WCHAR TestItem4_after
[] = {'T', 'e', 's', 't',
3556 #define MAX_BUF_LEN 1024
3557 WCHAR buf
[MAX_BUF_LEN
];
3558 char bufACP
[MAX_BUF_LEN
];
3565 /* Test the scroll position with and without a parent window.
3567 * For some reason the scroll position is 0 after EM_SETTEXTEX
3568 * with the ST_SELECTION flag only when the control has a parent
3569 * window, even though the selection is at the end. */
3571 cls
.lpfnWndProc
= DefWindowProcA
;
3574 cls
.hInstance
= GetModuleHandleA(0);
3576 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
3577 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
3578 cls
.lpszMenuName
= NULL
;
3579 cls
.lpszClassName
= "ParentTestClass";
3580 if(!RegisterClassA(&cls
)) assert(0);
3582 parent
= CreateWindowA(cls
.lpszClassName
, NULL
, WS_POPUP
|WS_VISIBLE
,
3583 0, 0, 200, 60, NULL
, NULL
, NULL
, NULL
);
3584 ok (parent
!= 0, "Failed to create parent window\n");
3586 hwndRichEdit
= CreateWindowExA(0,
3587 RICHEDIT_CLASS20A
, NULL
,
3588 ES_MULTILINE
|WS_VSCROLL
|WS_VISIBLE
|WS_CHILD
,
3589 0, 0, 200, 60, parent
, NULL
,
3590 hmoduleRichEdit
, NULL
);
3592 setText
.codepage
= CP_ACP
;
3593 setText
.flags
= ST_SELECTION
;
3594 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
,
3595 (LPARAM
)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
3596 si
.cbSize
= sizeof(si
);
3598 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3599 todo_wine
ok(si
.nPos
== 0, "Position is incorrectly at %d\n", si
.nPos
);
3600 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
3601 ok(sel_start
== 18, "Selection start incorrectly at %d\n", sel_start
);
3602 ok(sel_end
== 18, "Selection end incorrectly at %d\n", sel_end
);
3604 DestroyWindow(parent
);
3606 /* Test without a parent window */
3607 hwndRichEdit
= new_richedit(NULL
);
3608 setText
.codepage
= CP_ACP
;
3609 setText
.flags
= ST_SELECTION
;
3610 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
,
3611 (LPARAM
)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
3612 si
.cbSize
= sizeof(si
);
3614 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3615 ok(si
.nPos
!= 0, "Position is incorrectly at %d\n", si
.nPos
);
3616 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
3617 ok(sel_start
== 18, "Selection start incorrectly at %d\n", sel_start
);
3618 ok(sel_end
== 18, "Selection end incorrectly at %d\n", sel_end
);
3620 /* The scroll position should also be 0 after EM_SETTEXTEX with ST_DEFAULT,
3621 * but this time it is because the selection is at the beginning. */
3622 setText
.codepage
= CP_ACP
;
3623 setText
.flags
= ST_DEFAULT
;
3624 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
,
3625 (LPARAM
)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
3626 si
.cbSize
= sizeof(si
);
3628 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3629 ok(si
.nPos
== 0, "Position is incorrectly at %d\n", si
.nPos
);
3630 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
3631 ok(sel_start
== 0, "Selection start incorrectly at %d\n", sel_start
);
3632 ok(sel_end
== 0, "Selection end incorrectly at %d\n", sel_end
);
3634 setText
.codepage
= 1200; /* no constant for unicode */
3635 getText
.codepage
= 1200; /* no constant for unicode */
3636 getText
.cb
= MAX_BUF_LEN
;
3637 getText
.flags
= GT_DEFAULT
;
3638 getText
.lpDefaultChar
= NULL
;
3639 getText
.lpUsedDefChar
= NULL
;
3642 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
3643 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3644 ok(lstrcmpW(buf
, TestItem1
) == 0,
3645 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
3647 /* Unlike WM_SETTEXT/WM_GETTEXT pair, EM_SETTEXTEX/EM_GETTEXTEX does not
3648 convert \r to \r\n on return: !ST_SELECTION && Unicode && !\rtf
3650 setText
.codepage
= 1200; /* no constant for unicode */
3651 getText
.codepage
= 1200; /* no constant for unicode */
3652 getText
.cb
= MAX_BUF_LEN
;
3653 getText
.flags
= GT_DEFAULT
;
3654 getText
.lpDefaultChar
= NULL
;
3655 getText
.lpUsedDefChar
= NULL
;
3657 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem2
);
3658 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3659 ok(lstrcmpW(buf
, TestItem2
) == 0,
3660 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
3662 /* However, WM_GETTEXT *does* see \r\n where EM_GETTEXTEX would see \r */
3663 SendMessageA(hwndRichEdit
, WM_GETTEXT
, MAX_BUF_LEN
, (LPARAM
)buf
);
3664 ok(strcmp((const char *)buf
, TestItem2_after
) == 0,
3665 "WM_GETTEXT did *not* see \\r converted to \\r\\n pairs.\n");
3667 /* Baseline test for just-enough buffer space for string */
3668 getText
.cb
= (lstrlenW(TestItem2
) + 1) * sizeof(WCHAR
);
3669 getText
.codepage
= 1200; /* no constant for unicode */
3670 getText
.flags
= GT_DEFAULT
;
3671 getText
.lpDefaultChar
= NULL
;
3672 getText
.lpUsedDefChar
= NULL
;
3673 memset(buf
, 0, MAX_BUF_LEN
);
3674 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3675 ok(lstrcmpW(buf
, TestItem2
) == 0,
3676 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
3678 /* When there is enough space for one character, but not both, of the CRLF
3679 pair at the end of the string, the CR is not copied at all. That is,
3680 the caller must not see CRLF pairs truncated to CR at the end of the
3683 getText
.cb
= (lstrlenW(TestItem2
) + 1) * sizeof(WCHAR
);
3684 getText
.codepage
= 1200; /* no constant for unicode */
3685 getText
.flags
= GT_USECRLF
; /* <-- asking for CR -> CRLF conversion */
3686 getText
.lpDefaultChar
= NULL
;
3687 getText
.lpUsedDefChar
= NULL
;
3688 memset(buf
, 0, MAX_BUF_LEN
);
3689 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3690 ok(lstrcmpW(buf
, TestItem1
) == 0,
3691 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
3694 /* \r\n pairs get changed into \r: !ST_SELECTION && Unicode && !\rtf */
3695 setText
.codepage
= 1200; /* no constant for unicode */
3696 getText
.codepage
= 1200; /* no constant for unicode */
3697 getText
.cb
= MAX_BUF_LEN
;
3698 getText
.flags
= GT_DEFAULT
;
3699 getText
.lpDefaultChar
= NULL
;
3700 getText
.lpUsedDefChar
= NULL
;
3702 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem3
);
3703 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3704 ok(lstrcmpW(buf
, TestItem3_after
) == 0,
3705 "EM_SETTEXTEX did not convert properly\n");
3707 /* \n also gets changed to \r: !ST_SELECTION && Unicode && !\rtf */
3708 setText
.codepage
= 1200; /* no constant for unicode */
3709 getText
.codepage
= 1200; /* no constant for unicode */
3710 getText
.cb
= MAX_BUF_LEN
;
3711 getText
.flags
= GT_DEFAULT
;
3712 getText
.lpDefaultChar
= NULL
;
3713 getText
.lpUsedDefChar
= NULL
;
3715 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem3alt
);
3716 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3717 ok(lstrcmpW(buf
, TestItem3_after
) == 0,
3718 "EM_SETTEXTEX did not convert properly\n");
3720 /* \r\r\n gets changed into single space: !ST_SELECTION && Unicode && !\rtf */
3721 setText
.codepage
= 1200; /* no constant for unicode */
3722 getText
.codepage
= 1200; /* no constant for unicode */
3723 getText
.cb
= MAX_BUF_LEN
;
3724 getText
.flags
= GT_DEFAULT
;
3725 getText
.lpDefaultChar
= NULL
;
3726 getText
.lpUsedDefChar
= NULL
;
3728 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem4
);
3729 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3730 ok(lstrcmpW(buf
, TestItem4_after
) == 0,
3731 "EM_SETTEXTEX did not convert properly\n");
3733 /* !ST_SELECTION && Unicode && !\rtf */
3734 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, 0);
3735 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3738 "EM_SETTEXTEX returned %d, instead of 1\n",result
);
3739 ok(lstrlenW(buf
) == 0,
3740 "EM_SETTEXTEX with NULL lParam should clear rich edit.\n");
3742 /* put some text back: !ST_SELECTION && Unicode && !\rtf */
3744 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
3745 /* select some text */
3748 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
3749 /* replace current selection: ST_SELECTION && Unicode && !\rtf */
3750 setText
.flags
= ST_SELECTION
;
3751 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, 0);
3753 "EM_SETTEXTEX with NULL lParam to replace selection"
3754 " with no text should return 0. Got %i\n",
3757 /* put some text back: !ST_SELECTION && Unicode && !\rtf */
3759 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
3760 /* select some text */
3763 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
3764 /* replace current selection: ST_SELECTION && Unicode && !\rtf */
3765 setText
.flags
= ST_SELECTION
;
3766 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
3768 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3769 ok(result
== lstrlenW(TestItem1
),
3770 "EM_SETTEXTEX with NULL lParam to replace selection"
3771 " with no text should return 0. Got %i\n",
3773 ok(lstrlenW(buf
) == 22,
3774 "EM_SETTEXTEX to replace selection with more text failed: %i.\n",
3777 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings */
3778 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"TestSomeText"); /* TestItem1 */
3780 es
.dwCookie
= (DWORD_PTR
)&p
;
3782 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3783 memset(buf
, 0, sizeof(buf
));
3784 SendMessageA(hwndRichEdit
, EM_STREAMOUT
,
3785 (WPARAM
)(SF_RTF
), (LPARAM
)&es
);
3786 trace("EM_STREAMOUT produced:\n%s\n", (char *)buf
);
3788 /* !ST_SELECTION && !Unicode && \rtf */
3789 setText
.codepage
= CP_ACP
;/* EM_STREAMOUT saved as ANSI string */
3790 getText
.codepage
= 1200; /* no constant for unicode */
3791 getText
.cb
= MAX_BUF_LEN
;
3792 getText
.flags
= GT_DEFAULT
;
3793 getText
.lpDefaultChar
= NULL
;
3794 getText
.lpUsedDefChar
= NULL
;
3797 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)buf
);
3798 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3799 ok(lstrcmpW(buf
, TestItem1
) == 0,
3800 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
3802 /* The following test demonstrates that EM_SETTEXTEX treats text as ASCII if it
3803 * starts with ASCII characters "{\rtf" even when the codepage is unicode. */
3804 setText
.codepage
= 1200; /* Lie about code page (actual ASCII) */
3805 getText
.codepage
= CP_ACP
;
3806 getText
.cb
= MAX_BUF_LEN
;
3807 getText
.flags
= GT_DEFAULT
;
3808 getText
.lpDefaultChar
= NULL
;
3809 getText
.lpUsedDefChar
= NULL
;
3811 setText
.flags
= ST_SELECTION
;
3812 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
3813 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"{\\rtf not unicode}");
3814 todo_wine
ok(result
== 11, "EM_SETTEXTEX incorrectly returned %d\n", result
);
3815 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)bufACP
);
3816 ok(lstrcmpA(bufACP
, "not unicode") == 0, "'%s' != 'not unicode'\n", bufACP
);
3818 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings with a selection */
3819 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"TestSomeText"); /* TestItem1 */
3821 es
.dwCookie
= (DWORD_PTR
)&p
;
3823 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3824 memset(buf
, 0, sizeof(buf
));
3825 SendMessageA(hwndRichEdit
, EM_STREAMOUT
,
3826 (WPARAM
)(SF_RTF
), (LPARAM
)&es
);
3827 trace("EM_STREAMOUT produced:\n%s\n", (char *)buf
);
3829 /* select some text */
3832 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
3834 /* ST_SELECTION && !Unicode && \rtf */
3835 setText
.codepage
= CP_ACP
;/* EM_STREAMOUT saved as ANSI string */
3836 getText
.codepage
= 1200; /* no constant for unicode */
3837 getText
.cb
= MAX_BUF_LEN
;
3838 getText
.flags
= GT_DEFAULT
;
3839 getText
.lpDefaultChar
= NULL
;
3840 getText
.lpUsedDefChar
= NULL
;
3842 setText
.flags
= ST_SELECTION
;
3843 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)buf
);
3844 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3845 ok_w3("Expected \"%s\" or \"%s\", got \"%s\"\n", TestItem1alt
, TestItem1altn
, buf
);
3847 /* The following test demonstrates that EM_SETTEXTEX replacing a selection */
3848 setText
.codepage
= 1200; /* no constant for unicode */
3849 getText
.codepage
= CP_ACP
;
3850 getText
.cb
= MAX_BUF_LEN
;
3853 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
); /* TestItem1 */
3854 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)bufACP
);
3856 /* select some text */
3859 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
3861 /* ST_SELECTION && !Unicode && !\rtf */
3862 setText
.codepage
= CP_ACP
;
3863 getText
.codepage
= 1200; /* no constant for unicode */
3864 getText
.cb
= MAX_BUF_LEN
;
3865 getText
.flags
= GT_DEFAULT
;
3866 getText
.lpDefaultChar
= NULL
;
3867 getText
.lpUsedDefChar
= NULL
;
3869 setText
.flags
= ST_SELECTION
;
3870 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)bufACP
);
3871 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3872 ok(lstrcmpW(buf
, TestItem1alt
) == 0,
3873 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX when"
3874 " using ST_SELECTION and non-Unicode\n");
3876 /* Test setting text using rich text format */
3878 setText
.codepage
= CP_ACP
;
3879 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"{\\rtf richtext}");
3880 getText
.codepage
= CP_ACP
;
3881 getText
.cb
= MAX_BUF_LEN
;
3882 getText
.flags
= GT_DEFAULT
;
3883 getText
.lpDefaultChar
= NULL
;
3884 getText
.lpUsedDefChar
= NULL
;
3885 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)bufACP
);
3886 ok(!strcmp(bufACP
, "richtext"), "expected 'richtext' but got '%s'\n", bufACP
);
3889 setText
.codepage
= CP_ACP
;
3890 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"{\\urtf morerichtext}");
3891 getText
.codepage
= CP_ACP
;
3892 getText
.cb
= MAX_BUF_LEN
;
3893 getText
.flags
= GT_DEFAULT
;
3894 getText
.lpDefaultChar
= NULL
;
3895 getText
.lpUsedDefChar
= NULL
;
3896 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)bufACP
);
3897 ok(!strcmp(bufACP
, "morerichtext"), "expected 'morerichtext' but got '%s'\n", bufACP
);
3899 /* test for utf8 text with BOM */
3901 setText
.codepage
= CP_ACP
;
3902 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"\xef\xbb\xbfTestUTF8WithBOM");
3903 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)bufACP
);
3904 todo_wine
ok(result
== 15, "EM_SETTEXTEX: Test UTF8 with BOM returned %d, expected 15\n", result
);
3905 result
= strcmp(bufACP
, "TestUTF8WithBOM");
3906 todo_wine
ok(result
== 0, "EM_SETTEXTEX: Test UTF8 with BOM set wrong text: Result: %s\n", bufACP
);
3909 setText
.codepage
= CP_UTF8
;
3910 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"\xef\xbb\xbfTestUTF8WithBOM");
3911 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)bufACP
);
3912 todo_wine
ok(result
== 15, "EM_SETTEXTEX: Test UTF8 with BOM returned %d, expected 15\n", result
);
3913 result
= strcmp(bufACP
, "TestUTF8WithBOM");
3914 todo_wine
ok(result
== 0, "EM_SETTEXTEX: Test UTF8 with BOM set wrong text: Result: %s\n", bufACP
);
3916 DestroyWindow(hwndRichEdit
);
3919 static void test_EM_LIMITTEXT(void)
3923 HWND hwndRichEdit
= new_richedit(NULL
);
3925 /* The main purpose of this test is to demonstrate that the nonsense in MSDN
3926 * about setting the length to -1 for multiline edit controls doesn't happen.
3929 /* Don't check default gettextlimit case. That's done in other tests */
3931 /* Set textlimit to 100 */
3932 SendMessageA(hwndRichEdit
, EM_LIMITTEXT
, 100, 0);
3933 ret
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3935 "EM_LIMITTEXT: set to 100, returned: %d, expected: 100\n", ret
);
3937 /* Set textlimit to 0 */
3938 SendMessageA(hwndRichEdit
, EM_LIMITTEXT
, 0, 0);
3939 ret
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3941 "EM_LIMITTEXT: set to 0, returned: %d, expected: 65536\n", ret
);
3943 /* Set textlimit to -1 */
3944 SendMessageA(hwndRichEdit
, EM_LIMITTEXT
, -1, 0);
3945 ret
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3947 "EM_LIMITTEXT: set to -1, returned: %d, expected: -1\n", ret
);
3949 /* Set textlimit to -2 */
3950 SendMessageA(hwndRichEdit
, EM_LIMITTEXT
, -2, 0);
3951 ret
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3953 "EM_LIMITTEXT: set to -2, returned: %d, expected: -2\n", ret
);
3955 DestroyWindow (hwndRichEdit
);
3959 static void test_EM_EXLIMITTEXT(void)
3961 int i
, selBegin
, selEnd
, len1
, len2
;
3963 char text
[1024 + 1];
3964 char buffer
[1024 + 1];
3965 int textlimit
= 0; /* multiple of 100 */
3966 HWND hwndRichEdit
= new_richedit(NULL
);
3968 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3969 ok(32767 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 32767, i
); /* default */
3972 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
3973 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3975 ok(textlimit
== i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit
, i
);
3978 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
3979 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3981 ok(textlimit
== i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit
, i
);
3983 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, 0);
3984 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3985 /* default for WParam = 0 */
3986 ok(65536 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 65536, i
);
3988 textlimit
= sizeof(text
)-1;
3989 memset(text
, 'W', textlimit
);
3990 text
[sizeof(text
)-1] = 0;
3991 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
3992 /* maxed out text */
3993 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3995 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1); /* select everything */
3996 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
3997 len1
= selEnd
- selBegin
;
3999 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, VK_BACK
, 1);
4000 SendMessageA(hwndRichEdit
, WM_CHAR
, VK_BACK
, 1);
4001 SendMessageA(hwndRichEdit
, WM_KEYUP
, VK_BACK
, 1);
4002 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4003 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
4004 len2
= selEnd
- selBegin
;
4007 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4010 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'A', 1);
4011 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 1);
4012 SendMessageA(hwndRichEdit
, WM_KEYUP
, 'A', 1);
4013 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4014 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
4015 len1
= selEnd
- selBegin
;
4018 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4021 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'A', 1);
4022 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 1);
4023 SendMessageA(hwndRichEdit
, WM_KEYUP
, 'A', 1); /* full; should be no effect */
4024 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4025 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
4026 len2
= selEnd
- selBegin
;
4029 "EM_EXLIMITTEXT: No Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4032 /* set text up to the limit, select all the text, then add a char */
4034 memset(text
, 'W', textlimit
);
4035 text
[textlimit
] = 0;
4036 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
4037 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
4038 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4039 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 1);
4040 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4041 result
= strcmp(buffer
, "A");
4042 ok(0 == result
, "got string = \"%s\"\n", buffer
);
4044 /* WM_SETTEXT not limited */
4046 memset(text
, 'W', textlimit
);
4047 text
[textlimit
] = 0;
4048 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
-5);
4049 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
4050 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4052 ok(10 == i
, "expected 10 chars\n");
4053 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4054 ok(10 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i
);
4056 /* try inserting more text at end */
4057 i
= SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4058 ok(0 == i
, "WM_CHAR wasn't processed\n");
4059 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4061 ok(10 == i
, "expected 10 chars, got %i\n", i
);
4062 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4063 ok(10 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i
);
4065 /* try inserting text at beginning */
4066 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 0);
4067 i
= SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4068 ok(0 == i
, "WM_CHAR wasn't processed\n");
4069 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4071 ok(10 == i
, "expected 10 chars, got %i\n", i
);
4072 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4073 ok(10 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i
);
4075 /* WM_CHAR is limited */
4077 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
4078 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1); /* select everything */
4079 i
= SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4080 ok(0 == i
, "WM_CHAR wasn't processed\n");
4081 i
= SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4082 ok(0 == i
, "WM_CHAR wasn't processed\n");
4083 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4085 ok(1 == i
, "expected 1 chars, got %i instead\n", i
);
4087 DestroyWindow(hwndRichEdit
);
4090 static void test_EM_GETLIMITTEXT(void)
4093 HWND hwndRichEdit
= new_richedit(NULL
);
4095 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4096 ok(32767 == i
, "expected: %d, actual: %d\n", 32767, i
); /* default value */
4098 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, 50000);
4099 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4100 ok(50000 == i
, "expected: %d, actual: %d\n", 50000, i
);
4102 DestroyWindow(hwndRichEdit
);
4105 static void test_WM_SETFONT(void)
4107 /* There is no invalid input or error conditions for this function.
4108 * NULL wParam and lParam just fall back to their default values
4109 * It should be noted that even if you use a gibberish name for your fonts
4110 * here, it will still work because the name is stored. They will display as
4111 * System, but will report their name to be whatever they were created as */
4113 HWND hwndRichEdit
= new_richedit(NULL
);
4114 HFONT testFont1
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4115 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4116 FF_DONTCARE
, "Marlett");
4117 HFONT testFont2
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4118 OUT_TT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4119 FF_DONTCARE
, "MS Sans Serif");
4120 HFONT testFont3
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4121 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4122 FF_DONTCARE
, "Courier");
4123 LOGFONTA sentLogFont
;
4124 CHARFORMAT2A returnedCF2A
;
4126 returnedCF2A
.cbSize
= sizeof(returnedCF2A
);
4128 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"x");
4129 SendMessageA(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont1
, MAKELPARAM(TRUE
, 0));
4130 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&returnedCF2A
);
4132 GetObjectA(testFont1
, sizeof(LOGFONTA
), &sentLogFont
);
4133 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
4134 "EM_GETCHARFORMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n",
4135 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
4137 SendMessageA(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont2
, MAKELPARAM(TRUE
, 0));
4138 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&returnedCF2A
);
4139 GetObjectA(testFont2
, sizeof(LOGFONTA
), &sentLogFont
);
4140 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
4141 "EM_GETCHARFORMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n",
4142 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
4144 SendMessageA(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont3
, MAKELPARAM(TRUE
, 0));
4145 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&returnedCF2A
);
4146 GetObjectA(testFont3
, sizeof(LOGFONTA
), &sentLogFont
);
4147 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
4148 "EM_GETCHARFORMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n",
4149 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
4151 /* This last test is special since we send in NULL. We clear the variables
4152 * and just compare to "System" instead of the sent in font name. */
4153 ZeroMemory(&returnedCF2A
,sizeof(returnedCF2A
));
4154 ZeroMemory(&sentLogFont
,sizeof(sentLogFont
));
4155 returnedCF2A
.cbSize
= sizeof(returnedCF2A
);
4157 SendMessageA(hwndRichEdit
, WM_SETFONT
, 0, MAKELPARAM((WORD
) TRUE
, 0));
4158 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&returnedCF2A
);
4159 GetObjectA(NULL
, sizeof(LOGFONTA
), &sentLogFont
);
4160 ok (!strcmp("System",returnedCF2A
.szFaceName
),
4161 "EM_GETCHARFORMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A
.szFaceName
);
4163 DestroyWindow(hwndRichEdit
);
4167 static DWORD CALLBACK
test_EM_GETMODIFY_esCallback(DWORD_PTR dwCookie
,
4172 const char** str
= (const char**)dwCookie
;
4173 int size
= strlen(*str
);
4174 if(size
> 3) /* let's make it piecemeal for fun */
4181 memcpy(pbBuff
, *str
, *pcb
);
4187 static void test_EM_GETMODIFY(void)
4189 HWND hwndRichEdit
= new_richedit(NULL
);
4192 WCHAR TestItem1
[] = {'T', 'e', 's', 't',
4194 'T', 'e', 'x', 't', 0};
4195 WCHAR TestItem2
[] = {'T', 'e', 's', 't',
4197 'O', 't', 'h', 'e', 'r',
4198 'T', 'e', 'x', 't', 0};
4199 const char* streamText
= "hello world";
4204 HFONT testFont
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4205 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4206 FF_DONTCARE
, "Courier");
4208 setText
.codepage
= 1200; /* no constant for unicode */
4209 setText
.flags
= ST_KEEPUNDO
;
4212 /* modify flag shouldn't be set when richedit is first created */
4213 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4215 "EM_GETMODIFY returned non-zero, instead of zero on create\n");
4217 /* setting modify flag should actually set it */
4218 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, TRUE
, 0);
4219 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4221 "EM_GETMODIFY returned zero, instead of non-zero on EM_SETMODIFY\n");
4223 /* clearing modify flag should actually clear it */
4224 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4225 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4227 "EM_GETMODIFY returned non-zero, instead of zero on EM_SETMODIFY\n");
4229 /* setting font doesn't change modify flag */
4230 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4231 SendMessageA(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont
, MAKELPARAM(TRUE
, 0));
4232 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4234 "EM_GETMODIFY returned non-zero, instead of zero on setting font\n");
4236 /* setting text should set modify flag */
4237 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4238 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
4239 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4241 "EM_GETMODIFY returned zero, instead of non-zero on setting text\n");
4243 /* undo previous text doesn't reset modify flag */
4244 SendMessageA(hwndRichEdit
, WM_UNDO
, 0, 0);
4245 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4247 "EM_GETMODIFY returned zero, instead of non-zero on undo after setting text\n");
4249 /* set text with no flag to keep undo stack should not set modify flag */
4250 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4252 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
4253 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4255 "EM_GETMODIFY returned non-zero, instead of zero when setting text while not keeping undo stack\n");
4257 /* WM_SETTEXT doesn't modify */
4258 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4259 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem2
);
4260 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4262 "EM_GETMODIFY returned non-zero for WM_SETTEXT\n");
4264 /* clear the text */
4265 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4266 SendMessageA(hwndRichEdit
, WM_CLEAR
, 0, 0);
4267 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4269 "EM_GETMODIFY returned non-zero, instead of zero for WM_CLEAR\n");
4272 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4273 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
4274 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
4275 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, TRUE
, (LPARAM
)TestItem2
);
4276 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4278 "EM_GETMODIFY returned zero, instead of non-zero when replacing text\n");
4280 /* copy/paste text 1 */
4281 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4282 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
4283 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
4284 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
4285 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4287 "EM_GETMODIFY returned zero, instead of non-zero when pasting identical text\n");
4289 /* copy/paste text 2 */
4290 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4291 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
4292 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
4293 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 3);
4294 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
4295 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4297 "EM_GETMODIFY returned zero, instead of non-zero when pasting different text\n");
4300 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4301 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 1);
4302 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4303 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4305 "EM_GETMODIFY returned zero, instead of non-zero for WM_CHAR\n");
4308 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4309 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4310 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, VK_BACK
, 0);
4311 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4313 "EM_GETMODIFY returned zero, instead of non-zero for backspace\n");
4315 /* set char format */
4316 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4317 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
4318 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
4319 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
4320 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
4321 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
4322 result
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
4323 ok(result
== 1, "EM_SETCHARFORMAT returned %ld instead of 1\n", result
);
4324 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4326 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETCHARFORMAT\n");
4328 /* set para format */
4329 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4330 pf2
.cbSize
= sizeof(PARAFORMAT2
);
4331 SendMessageA(hwndRichEdit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&pf2
);
4332 pf2
.dwMask
= PFM_ALIGNMENT
| pf2
.dwMask
;
4333 pf2
.wAlignment
= PFA_RIGHT
;
4334 SendMessageA(hwndRichEdit
, EM_SETPARAFORMAT
, 0, (LPARAM
)&pf2
);
4335 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4337 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETPARAFORMAT\n");
4340 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4341 es
.dwCookie
= (DWORD_PTR
)&streamText
;
4343 es
.pfnCallback
= test_EM_GETMODIFY_esCallback
;
4344 SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
4345 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4347 "EM_GETMODIFY returned zero, instead of non-zero for EM_STREAM\n");
4349 DestroyWindow(hwndRichEdit
);
4355 LRESULT expected_retval
;
4356 int expected_getsel_start
;
4357 int expected_getsel_end
;
4358 int _getsel_todo_wine
;
4361 const struct exsetsel_s exsetsel_tests
[] = {
4363 {5, 10, 10, 5, 10, 0},
4364 {15, 17, 17, 15, 17, 0},
4365 /* test cpMax > strlen() */
4366 {0, 100, 18, 0, 18, 1},
4367 /* test cpMin == cpMax */
4369 /* test cpMin < 0 && cpMax >= 0 (bug 4462) */
4370 {-1, 0, 5, 5, 5, 0},
4371 {-1, 17, 5, 5, 5, 0},
4372 {-1, 18, 5, 5, 5, 0},
4373 /* test cpMin < 0 && cpMax < 0 */
4374 {-1, -1, 17, 17, 17, 0},
4375 {-4, -5, 17, 17, 17, 0},
4376 /* test cMin >=0 && cpMax < 0 (bug 6814) */
4377 {0, -1, 18, 0, 18, 1},
4378 {17, -5, 18, 17, 18, 1},
4379 {18, -3, 17, 17, 17, 0},
4380 /* test if cpMin > cpMax */
4381 {15, 19, 18, 15, 18, 1},
4382 {19, 15, 18, 15, 18, 1}
4385 static void check_EM_EXSETSEL(HWND hwnd
, const struct exsetsel_s
*setsel
, int id
) {
4390 cr
.cpMin
= setsel
->min
;
4391 cr
.cpMax
= setsel
->max
;
4392 result
= SendMessageA(hwnd
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
4394 ok(result
== setsel
->expected_retval
, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id
, setsel
->expected_retval
, result
);
4396 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&start
, (LPARAM
)&end
);
4398 if (setsel
->_getsel_todo_wine
) {
4400 ok(start
== setsel
->expected_getsel_start
&& end
== setsel
->expected_getsel_end
, "EM_EXSETSEL(%d): expected (%d,%d) actual:(%d,%d)\n", id
, setsel
->expected_getsel_start
, setsel
->expected_getsel_end
, start
, end
);
4403 ok(start
== setsel
->expected_getsel_start
&& end
== setsel
->expected_getsel_end
, "EM_EXSETSEL(%d): expected (%d,%d) actual:(%d,%d)\n", id
, setsel
->expected_getsel_start
, setsel
->expected_getsel_end
, start
, end
);
4407 static void test_EM_EXSETSEL(void)
4409 HWND hwndRichEdit
= new_richedit(NULL
);
4411 const int num_tests
= sizeof(exsetsel_tests
)/sizeof(struct exsetsel_s
);
4413 /* sending some text to the window */
4414 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"testing selection");
4415 /* 01234567890123456*/
4418 for (i
= 0; i
< num_tests
; i
++) {
4419 check_EM_EXSETSEL(hwndRichEdit
, &exsetsel_tests
[i
], i
);
4422 DestroyWindow(hwndRichEdit
);
4425 static void test_EM_REPLACESEL(int redraw
)
4427 HWND hwndRichEdit
= new_richedit(NULL
);
4428 char buffer
[1024] = {0};
4433 /* sending some text to the window */
4434 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"testing selection");
4435 /* 01234567890123456*/
4438 /* FIXME add more tests */
4439 SendMessageA(hwndRichEdit
, EM_SETSEL
, 7, 17);
4440 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, 0);
4441 ok(0 == r
, "EM_REPLACESEL returned %d, expected 0\n", r
);
4442 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4443 r
= strcmp(buffer
, "testing");
4444 ok(0 == r
, "expected %d, got %d\n", 0, r
);
4446 DestroyWindow(hwndRichEdit
);
4448 hwndRichEdit
= new_richedit(NULL
);
4450 trace("Testing EM_REPLACESEL behavior with redraw=%d\n", redraw
);
4451 SendMessageA(hwndRichEdit
, WM_SETREDRAW
, redraw
, 0);
4453 /* Test behavior with carriage returns and newlines */
4454 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4455 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"RichEdit1");
4456 ok(9 == r
, "EM_REPLACESEL returned %d, expected 9\n", r
);
4457 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4458 r
= strcmp(buffer
, "RichEdit1");
4459 ok(0 == r
, "expected %d, got %d\n", 0, r
);
4461 getText
.codepage
= CP_ACP
;
4462 getText
.flags
= GT_DEFAULT
;
4463 getText
.lpDefaultChar
= NULL
;
4464 getText
.lpUsedDefChar
= NULL
;
4465 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4466 ok(strcmp(buffer
, "RichEdit1") == 0,
4467 "EM_GETTEXTEX results not what was set by EM_REPLACESEL\n");
4469 /* Test number of lines reported after EM_REPLACESEL */
4470 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4471 ok(r
== 1, "EM_GETLINECOUNT returned %d, expected 1\n", r
);
4473 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4474 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"RichEdit1\r");
4475 ok(10 == r
, "EM_REPLACESEL returned %d, expected 10\n", r
);
4476 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4477 r
= strcmp(buffer
, "RichEdit1\r\n");
4478 ok(0 == r
, "expected %d, got %d\n", 0, r
);
4480 getText
.codepage
= CP_ACP
;
4481 getText
.flags
= GT_DEFAULT
;
4482 getText
.lpDefaultChar
= NULL
;
4483 getText
.lpUsedDefChar
= NULL
;
4484 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4485 ok(strcmp(buffer
, "RichEdit1\r") == 0,
4486 "EM_GETTEXTEX returned incorrect string\n");
4488 /* Test number of lines reported after EM_REPLACESEL */
4489 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4490 ok(r
== 2, "EM_GETLINECOUNT returned %d, expected 2\n", r
);
4492 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4493 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"RichEdit1\r\n");
4494 ok(r
== 11, "EM_REPLACESEL returned %d, expected 11\n", r
);
4496 /* Test number of lines reported after EM_REPLACESEL */
4497 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4498 ok(r
== 2, "EM_GETLINECOUNT returned %d, expected 2\n", r
);
4500 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4501 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4502 ok(cr
.cpMin
== 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr
.cpMin
);
4503 ok(cr
.cpMax
== 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr
.cpMax
);
4505 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4506 r
= strcmp(buffer
, "RichEdit1\r\n");
4507 ok(0 == r
, "expected %d, got %d\n", 0, r
);
4509 getText
.codepage
= CP_ACP
;
4510 getText
.flags
= GT_DEFAULT
;
4511 getText
.lpDefaultChar
= NULL
;
4512 getText
.lpUsedDefChar
= NULL
;
4513 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4514 ok(strcmp(buffer
, "RichEdit1\r") == 0,
4515 "EM_GETTEXTEX returned incorrect string\n");
4517 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4518 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4519 ok(cr
.cpMin
== 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr
.cpMin
);
4520 ok(cr
.cpMax
== 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr
.cpMax
);
4522 /* The following tests show that richedit should handle the special \r\r\n
4523 sequence by turning it into a single space on insertion. However,
4524 EM_REPLACESEL on WinXP returns the number of characters in the original
4528 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4529 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r");
4530 ok(2 == r
, "EM_REPLACESEL returned %d, expected 4\n", r
);
4531 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4532 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4533 ok(cr
.cpMin
== 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr
.cpMin
);
4534 ok(cr
.cpMax
== 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr
.cpMax
);
4536 /* Test the actual string */
4538 getText
.codepage
= CP_ACP
;
4539 getText
.flags
= GT_DEFAULT
;
4540 getText
.lpDefaultChar
= NULL
;
4541 getText
.lpUsedDefChar
= NULL
;
4542 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4543 ok(strcmp(buffer
, "\r\r") == 0,
4544 "EM_GETTEXTEX returned incorrect string\n");
4546 /* Test number of lines reported after EM_REPLACESEL */
4547 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4548 ok(r
== 3, "EM_GETLINECOUNT returned %d, expected 3\n", r
);
4550 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4551 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r\n");
4552 ok(r
== 3, "EM_REPLACESEL returned %d, expected 3\n", r
);
4553 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4554 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4555 ok(cr
.cpMin
== 1, "EM_EXGETSEL returned cpMin=%d, expected 1\n", cr
.cpMin
);
4556 ok(cr
.cpMax
== 1, "EM_EXGETSEL returned cpMax=%d, expected 1\n", cr
.cpMax
);
4558 /* Test the actual string */
4560 getText
.codepage
= CP_ACP
;
4561 getText
.flags
= GT_DEFAULT
;
4562 getText
.lpDefaultChar
= NULL
;
4563 getText
.lpUsedDefChar
= NULL
;
4564 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4565 ok(strcmp(buffer
, " ") == 0,
4566 "EM_GETTEXTEX returned incorrect string\n");
4568 /* Test number of lines reported after EM_REPLACESEL */
4569 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4570 ok(r
== 1, "EM_GETLINECOUNT returned %d, expected 1\n", r
);
4572 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4573 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r\r\r\r\n\r\r\r");
4574 ok(r
== 9, "EM_REPLACESEL returned %d, expected 9\n", r
);
4575 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4576 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4577 ok(cr
.cpMin
== 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr
.cpMin
);
4578 ok(cr
.cpMax
== 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr
.cpMax
);
4580 /* Test the actual string */
4582 getText
.codepage
= CP_ACP
;
4583 getText
.flags
= GT_DEFAULT
;
4584 getText
.lpDefaultChar
= NULL
;
4585 getText
.lpUsedDefChar
= NULL
;
4586 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4587 ok(strcmp(buffer
, "\r\r\r \r\r\r") == 0,
4588 "EM_GETTEXTEX returned incorrect string\n");
4590 /* Test number of lines reported after EM_REPLACESEL */
4591 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4592 ok(r
== 7, "EM_GETLINECOUNT returned %d, expected 7\n", r
);
4594 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4595 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r\n\r\n");
4596 ok(r
== 5, "EM_REPLACESEL returned %d, expected 5\n", r
);
4597 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4598 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4599 ok(cr
.cpMin
== 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr
.cpMin
);
4600 ok(cr
.cpMax
== 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr
.cpMax
);
4602 /* Test the actual string */
4604 getText
.codepage
= CP_ACP
;
4605 getText
.flags
= GT_DEFAULT
;
4606 getText
.lpDefaultChar
= NULL
;
4607 getText
.lpUsedDefChar
= NULL
;
4608 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4609 ok(strcmp(buffer
, " \r") == 0,
4610 "EM_GETTEXTEX returned incorrect string\n");
4612 /* Test number of lines reported after EM_REPLACESEL */
4613 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4614 ok(r
== 2, "EM_GETLINECOUNT returned %d, expected 2\n", r
);
4616 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4617 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r\n\r\r");
4618 ok(r
== 5, "EM_REPLACESEL returned %d, expected 5\n", r
);
4619 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4620 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4621 ok(cr
.cpMin
== 3, "EM_EXGETSEL returned cpMin=%d, expected 3\n", cr
.cpMin
);
4622 ok(cr
.cpMax
== 3, "EM_EXGETSEL returned cpMax=%d, expected 3\n", cr
.cpMax
);
4624 /* Test the actual string */
4626 getText
.codepage
= CP_ACP
;
4627 getText
.flags
= GT_DEFAULT
;
4628 getText
.lpDefaultChar
= NULL
;
4629 getText
.lpUsedDefChar
= NULL
;
4630 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4631 ok(strcmp(buffer
, " \r\r") == 0,
4632 "EM_GETTEXTEX returned incorrect string\n");
4634 /* Test number of lines reported after EM_REPLACESEL */
4635 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4636 ok(r
== 3, "EM_GETLINECOUNT returned %d, expected 3\n", r
);
4638 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4639 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\rX\r\n\r\r");
4640 ok(r
== 6, "EM_REPLACESEL returned %d, expected 6\n", r
);
4641 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4642 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4643 ok(cr
.cpMin
== 5, "EM_EXGETSEL returned cpMin=%d, expected 5\n", cr
.cpMin
);
4644 ok(cr
.cpMax
== 5, "EM_EXGETSEL returned cpMax=%d, expected 5\n", cr
.cpMax
);
4646 /* Test the actual string */
4648 getText
.codepage
= CP_ACP
;
4649 getText
.flags
= GT_DEFAULT
;
4650 getText
.lpDefaultChar
= NULL
;
4651 getText
.lpUsedDefChar
= NULL
;
4652 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4653 ok(strcmp(buffer
, "\rX\r\r\r") == 0,
4654 "EM_GETTEXTEX returned incorrect string\n");
4656 /* Test number of lines reported after EM_REPLACESEL */
4657 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4658 ok(r
== 5, "EM_GETLINECOUNT returned %d, expected 5\n", r
);
4660 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4661 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\n\n");
4662 ok(2 == r
, "EM_REPLACESEL returned %d, expected 2\n", r
);
4663 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4664 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4665 ok(cr
.cpMin
== 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr
.cpMin
);
4666 ok(cr
.cpMax
== 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr
.cpMax
);
4668 /* Test the actual string */
4670 getText
.codepage
= CP_ACP
;
4671 getText
.flags
= GT_DEFAULT
;
4672 getText
.lpDefaultChar
= NULL
;
4673 getText
.lpUsedDefChar
= NULL
;
4674 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4675 ok(strcmp(buffer
, "\r\r") == 0,
4676 "EM_GETTEXTEX returned incorrect string\n");
4678 /* Test number of lines reported after EM_REPLACESEL */
4679 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4680 ok(r
== 3, "EM_GETLINECOUNT returned %d, expected 3\n", r
);
4682 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4683 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\n\n\n\n\r\r\r\r\n");
4684 ok(r
== 9, "EM_REPLACESEL returned %d, expected 9\n", r
);
4685 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4686 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4687 ok(cr
.cpMin
== 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr
.cpMin
);
4688 ok(cr
.cpMax
== 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr
.cpMax
);
4690 /* Test the actual string */
4692 getText
.codepage
= CP_ACP
;
4693 getText
.flags
= GT_DEFAULT
;
4694 getText
.lpDefaultChar
= NULL
;
4695 getText
.lpUsedDefChar
= NULL
;
4696 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4697 ok(strcmp(buffer
, "\r\r\r\r\r\r ") == 0,
4698 "EM_GETTEXTEX returned incorrect string\n");
4700 /* Test number of lines reported after EM_REPLACESEL */
4701 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4702 ok(r
== 7, "EM_GETLINECOUNT returned %d, expected 7\n", r
);
4705 /* This is needed to avoid interferring with keybd_event calls
4706 * on other tests that simulate keyboard events. */
4707 SendMessageA(hwndRichEdit
, WM_SETREDRAW
, TRUE
, 0);
4709 DestroyWindow(hwndRichEdit
);
4712 /* Native riched20 inspects the keyboard state (e.g. GetKeyState)
4713 * to test the state of the modifiers (Ctrl/Alt/Shift).
4715 * Therefore Ctrl-<key> keystrokes need to be simulated with
4716 * keybd_event or by using SetKeyboardState to set the modifiers
4717 * and SendMessage to simulate the keystrokes.
4719 static LRESULT
send_ctrl_key(HWND hwnd
, UINT key
)
4722 hold_key(VK_CONTROL
);
4723 result
= SendMessageA(hwnd
, WM_KEYDOWN
, key
, 1);
4724 release_key(VK_CONTROL
);
4728 static void test_WM_PASTE(void)
4731 char buffer
[1024] = {0};
4732 const char* text1
= "testing paste\r";
4733 const char* text1_step1
= "testing paste\r\ntesting paste\r\n";
4734 const char* text1_after
= "testing paste\r\n";
4735 const char* text2
= "testing paste\r\rtesting paste";
4736 const char* text2_after
= "testing paste\r\n\r\ntesting paste";
4737 const char* text3
= "testing paste\r\npaste\r\ntesting paste";
4738 HWND hwndRichEdit
= new_richedit(NULL
);
4740 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
4741 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 14);
4743 send_ctrl_key(hwndRichEdit
, 'C'); /* Copy */
4744 SendMessageA(hwndRichEdit
, EM_SETSEL
, 14, 14);
4745 send_ctrl_key(hwndRichEdit
, 'V'); /* Paste */
4746 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4747 /* Pasted text should be visible at this step */
4748 result
= strcmp(text1_step1
, buffer
);
4750 "test paste: strcmp = %i, text='%s'\n", result
, buffer
);
4752 send_ctrl_key(hwndRichEdit
, 'Z'); /* Undo */
4753 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4754 /* Text should be the same as before (except for \r -> \r\n conversion) */
4755 result
= strcmp(text1_after
, buffer
);
4757 "test paste: strcmp = %i, text='%s'\n", result
, buffer
);
4759 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
4760 SendMessageA(hwndRichEdit
, EM_SETSEL
, 8, 13);
4761 send_ctrl_key(hwndRichEdit
, 'C'); /* Copy */
4762 SendMessageA(hwndRichEdit
, EM_SETSEL
, 14, 14);
4763 send_ctrl_key(hwndRichEdit
, 'V'); /* Paste */
4764 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4765 /* Pasted text should be visible at this step */
4766 result
= strcmp(text3
, buffer
);
4768 "test paste: strcmp = %i\n", result
);
4769 send_ctrl_key(hwndRichEdit
, 'Z'); /* Undo */
4770 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4771 /* Text should be the same as before (except for \r -> \r\n conversion) */
4772 result
= strcmp(text2_after
, buffer
);
4774 "test paste: strcmp = %i\n", result
);
4775 send_ctrl_key(hwndRichEdit
, 'Y'); /* Redo */
4776 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4777 /* Text should revert to post-paste state */
4778 result
= strcmp(buffer
,text3
);
4780 "test paste: strcmp = %i\n", result
);
4782 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4783 /* Send WM_CHAR to simulates Ctrl-V */
4784 SendMessageA(hwndRichEdit
, WM_CHAR
, 22,
4785 (MapVirtualKeyA('V', MAPVK_VK_TO_VSC
) << 16) | 1);
4786 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4787 /* Shouldn't paste because pasting is handled by WM_KEYDOWN */
4788 result
= strcmp(buffer
,"");
4790 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4792 /* Send keystrokes with WM_KEYDOWN after setting the modifiers
4793 * with SetKeyboard state. */
4795 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4796 /* Simulates paste (Ctrl-V) */
4797 hold_key(VK_CONTROL
);
4798 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'V',
4799 (MapVirtualKeyA('V', MAPVK_VK_TO_VSC
) << 16) | 1);
4800 release_key(VK_CONTROL
);
4801 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4802 result
= strcmp(buffer
,"paste");
4804 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4806 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
4807 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 7);
4808 /* Simulates copy (Ctrl-C) */
4809 hold_key(VK_CONTROL
);
4810 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'C',
4811 (MapVirtualKeyA('C', MAPVK_VK_TO_VSC
) << 16) | 1);
4812 release_key(VK_CONTROL
);
4813 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4814 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
4815 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4816 result
= strcmp(buffer
,"testing");
4818 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4820 /* Cut with WM_KEYDOWN to simulate Ctrl-X */
4821 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"cut");
4822 /* Simulates select all (Ctrl-A) */
4823 hold_key(VK_CONTROL
);
4824 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'A',
4825 (MapVirtualKeyA('A', MAPVK_VK_TO_VSC
) << 16) | 1);
4826 /* Simulates select cut (Ctrl-X) */
4827 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'X',
4828 (MapVirtualKeyA('X', MAPVK_VK_TO_VSC
) << 16) | 1);
4829 release_key(VK_CONTROL
);
4830 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4831 result
= strcmp(buffer
,"");
4833 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4834 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4835 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
4836 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4837 result
= strcmp(buffer
,"cut\r\n");
4838 todo_wine
ok(result
== 0,
4839 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4840 /* Simulates undo (Ctrl-Z) */
4841 hold_key(VK_CONTROL
);
4842 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'Z',
4843 (MapVirtualKeyA('Z', MAPVK_VK_TO_VSC
) << 16) | 1);
4844 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4845 result
= strcmp(buffer
,"");
4847 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4848 /* Simulates redo (Ctrl-Y) */
4849 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'Y',
4850 (MapVirtualKeyA('Y', MAPVK_VK_TO_VSC
) << 16) | 1);
4851 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4852 result
= strcmp(buffer
,"cut\r\n");
4853 todo_wine
ok(result
== 0,
4854 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4855 release_key(VK_CONTROL
);
4857 DestroyWindow(hwndRichEdit
);
4860 static void test_EM_FORMATRANGE(void)
4862 int r
, i
, tpp_x
, tpp_y
;
4864 HWND hwndRichEdit
= new_richedit(NULL
);
4866 BOOL skip_non_english
;
4867 static const struct {
4868 const char *string
; /* The string */
4869 int first
; /* First 'pagebreak', 0 for don't care */
4870 int second
; /* Second 'pagebreak', 0 for don't care */
4872 {"WINE wine", 0, 0},
4873 {"WINE wineWine", 0, 0},
4874 {"WINE\r\nwine\r\nwine", 5, 10},
4875 {"WINE\r\nWINEwine\r\nWINEwine", 5, 14},
4876 {"WINE\r\n\r\nwine\r\nwine", 5, 6}
4879 skip_non_english
= (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH
);
4880 if (skip_non_english
)
4881 skip("Skipping some tests on non-English platform\n");
4883 hdc
= GetDC(hwndRichEdit
);
4884 ok(hdc
!= NULL
, "Could not get HDC\n");
4886 /* Calculate the twips per pixel */
4887 tpp_x
= 1440 / GetDeviceCaps(hdc
, LOGPIXELSX
);
4888 tpp_y
= 1440 / GetDeviceCaps(hdc
, LOGPIXELSY
);
4890 /* Test the simple case where all the text fits in the page rect. */
4891 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
4892 fr
.hdc
= fr
.hdcTarget
= hdc
;
4893 fr
.rc
.top
= fr
.rcPage
.top
= fr
.rc
.left
= fr
.rcPage
.left
= 0;
4894 fr
.rc
.right
= fr
.rcPage
.right
= 500 * tpp_x
;
4895 fr
.rc
.bottom
= fr
.rcPage
.bottom
= 500 * tpp_y
;
4898 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, FALSE
, (LPARAM
)&fr
);
4899 todo_wine
ok(r
== 2, "r=%d expected r=2\n", r
);
4901 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"ab");
4902 fr
.rc
.bottom
= fr
.rcPage
.bottom
;
4903 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, FALSE
, (LPARAM
)&fr
);
4904 todo_wine
ok(r
== 3, "r=%d expected r=3\n", r
);
4906 SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, FALSE
, 0);
4908 for (i
= 0; i
< sizeof(fmtstrings
)/sizeof(fmtstrings
[0]); i
++)
4910 GETTEXTLENGTHEX gtl
;
4914 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)fmtstrings
[i
].string
);
4916 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
4917 gtl
.codepage
= CP_ACP
;
4918 len
= SendMessageA(hwndRichEdit
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
4920 /* Get some size information for the string */
4921 GetTextExtentPoint32A(hdc
, fmtstrings
[i
].string
, strlen(fmtstrings
[i
].string
), &stringsize
);
4923 /* Define the box to be half the width needed and a bit larger than the height.
4924 * Changes to the width means we have at least 2 pages. Changes to the height
4925 * is done so we can check the changing of fr.rc.bottom.
4927 fr
.hdc
= fr
.hdcTarget
= hdc
;
4928 fr
.rc
.top
= fr
.rcPage
.top
= fr
.rc
.left
= fr
.rcPage
.left
= 0;
4929 fr
.rc
.right
= fr
.rcPage
.right
= (stringsize
.cx
/ 2) * tpp_x
;
4930 fr
.rc
.bottom
= fr
.rcPage
.bottom
= (stringsize
.cy
+ 10) * tpp_y
;
4932 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, 0);
4934 ok(r
== len
, "Expected %d, got %d\n", len
, r
);
4937 /* We know that the page can't hold the full string. See how many characters
4938 * are on the first one
4942 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, (LPARAM
)&fr
);
4944 if (! skip_non_english
)
4945 ok(fr
.rc
.bottom
== (stringsize
.cy
* tpp_y
), "Expected bottom to be %d, got %d\n", (stringsize
.cy
* tpp_y
), fr
.rc
.bottom
);
4947 if (fmtstrings
[i
].first
)
4949 ok(r
== fmtstrings
[i
].first
, "Expected %d, got %d\n", fmtstrings
[i
].first
, r
);
4952 ok(r
< len
, "Expected < %d, got %d\n", len
, r
);
4954 /* Do another page */
4956 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, (LPARAM
)&fr
);
4957 if (fmtstrings
[i
].second
)
4959 ok(r
== fmtstrings
[i
].second
, "Expected %d, got %d\n", fmtstrings
[i
].second
, r
);
4961 else if (! skip_non_english
)
4962 ok (r
< len
, "Expected < %d, got %d\n", len
, r
);
4964 /* There is at least on more page, but we don't care */
4966 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, 0);
4968 ok(r
== len
, "Expected %d, got %d\n", len
, r
);
4972 ReleaseDC(NULL
, hdc
);
4973 DestroyWindow(hwndRichEdit
);
4976 static int nCallbackCount
= 0;
4978 static DWORD CALLBACK
EditStreamCallback(DWORD_PTR dwCookie
, LPBYTE pbBuff
,
4981 const char text
[] = {'t','e','s','t'};
4983 if (sizeof(text
) <= cb
)
4985 if ((int)dwCookie
!= nCallbackCount
)
4991 memcpy (pbBuff
, text
, sizeof(text
));
4992 *pcb
= sizeof(text
);
4999 return 1; /* indicates callback failed */
5002 static DWORD CALLBACK
test_EM_STREAMIN_esCallback(DWORD_PTR dwCookie
,
5007 const char** str
= (const char**)dwCookie
;
5008 int size
= strlen(*str
);
5014 memcpy(pbBuff
, *str
, *pcb
);
5020 static DWORD CALLBACK
test_EM_STREAMIN_esCallback_UTF8Split(DWORD_PTR dwCookie
,
5025 DWORD
*phase
= (DWORD
*)dwCookie
;
5028 static const char first
[] = "\xef\xbb\xbf\xc3\x96\xc3";
5029 *pcb
= sizeof(first
) - 1;
5030 memcpy(pbBuff
, first
, *pcb
);
5031 }else if(*phase
== 1){
5032 static const char second
[] = "\x8f\xc3\x8b";
5033 *pcb
= sizeof(second
) - 1;
5034 memcpy(pbBuff
, second
, *pcb
);
5043 struct StringWithLength
{
5048 /* This callback is used to handled the null characters in a string. */
5049 static DWORD CALLBACK
test_EM_STREAMIN_esCallback2(DWORD_PTR dwCookie
,
5054 struct StringWithLength
* str
= (struct StringWithLength
*)dwCookie
;
5055 int size
= str
->length
;
5061 memcpy(pbBuff
, str
->buffer
, *pcb
);
5062 str
->buffer
+= *pcb
;
5063 str
->length
-= *pcb
;
5068 static void test_EM_STREAMIN(void)
5070 HWND hwndRichEdit
= new_richedit(NULL
);
5074 char buffer
[1024] = {0};
5076 const char * streamText0
= "{\\rtf1 TestSomeText}";
5077 const char * streamText0a
= "{\\rtf1 TestSomeText\\par}";
5078 const char * streamText0b
= "{\\rtf1 TestSomeText\\par\\par}";
5080 const char * streamText1
=
5081 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n"
5082 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n"
5085 /* In richedit 2.0 mode, this should NOT be accepted, unlike 1.0 */
5086 const char * streamText2
=
5087 "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;"
5088 "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255"
5089 "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 "
5090 "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 "
5091 "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 "
5092 "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 "
5093 "\\tx11448 \\tx11872 \\tx12296 \\tx12720 \\tx13144 \\cf2 RichEdit1\\line }";
5095 const char * streamText3
= "RichEdit1";
5097 const char * streamTextUTF8BOM
= "\xef\xbb\xbfTestUTF8WithBOM";
5099 const char * streamText4
=
5100 "This text just needs to be long enough to cause run to be split onto "
5101 "two separate lines and make sure the null terminating character is "
5102 "handled properly.\0";
5103 int length4
= strlen(streamText4
) + 1;
5104 struct StringWithLength cookieForStream4
= {
5106 (char *)streamText4
,
5109 const WCHAR streamText5
[] = { 'T', 'e', 's', 't', 'S', 'o', 'm', 'e', 'T', 'e', 'x', 't' };
5110 int length5
= sizeof(streamText5
) / sizeof(WCHAR
);
5111 struct StringWithLength cookieForStream5
= {
5112 sizeof(streamText5
),
5113 (char *)streamText5
,
5116 /* Minimal test without \par at the end */
5117 es
.dwCookie
= (DWORD_PTR
)&streamText0
;
5119 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5120 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5121 ok(result
== 12, "got %ld, expected %d\n", result
, 12);
5123 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5125 "EM_STREAMIN: Test 0 returned %ld, expected 12\n", result
);
5126 result
= strcmp (buffer
,"TestSomeText");
5128 "EM_STREAMIN: Test 0 set wrong text: Result: %s\n",buffer
);
5129 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es
.dwError
, 0);
5131 /* Native richedit 2.0 ignores last \par */
5132 es
.dwCookie
= (DWORD_PTR
)&streamText0a
;
5134 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5135 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5136 ok(result
== 12, "got %ld, expected %d\n", result
, 12);
5138 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5140 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result
);
5141 result
= strcmp (buffer
,"TestSomeText");
5143 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer
);
5144 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0-a set error %d, expected %d\n", es
.dwError
, 0);
5146 /* Native richedit 2.0 ignores last \par, next-to-last \par appears */
5147 es
.dwCookie
= (DWORD_PTR
)&streamText0b
;
5149 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5150 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5151 ok(result
== 13, "got %ld, expected %d\n", result
, 13);
5153 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5155 "EM_STREAMIN: Test 0-b returned %ld, expected 14\n", result
);
5156 result
= strcmp (buffer
,"TestSomeText\r\n");
5158 "EM_STREAMIN: Test 0-b set wrong text: Result: %s\n",buffer
);
5159 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0-b set error %d, expected %d\n", es
.dwError
, 0);
5161 es
.dwCookie
= (DWORD_PTR
)&streamText1
;
5163 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5164 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5165 ok(result
== 12, "got %ld, expected %d\n", result
, 12);
5167 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5169 "EM_STREAMIN: Test 1 returned %ld, expected 12\n", result
);
5170 result
= strcmp (buffer
,"TestSomeText");
5172 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer
);
5173 ok(es
.dwError
== 0, "EM_STREAMIN: Test 1 set error %d, expected %d\n", es
.dwError
, 0);
5175 es
.dwCookie
= (DWORD_PTR
)&streamText2
;
5177 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5178 ok(result
== 0, "got %ld, expected %d\n", result
, 0);
5180 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5182 "EM_STREAMIN: Test 2 returned %ld, expected 0\n", result
);
5183 ok (strlen(buffer
) == 0,
5184 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
5185 ok(es
.dwError
== -16, "EM_STREAMIN: Test 2 set error %d, expected %d\n", es
.dwError
, -16);
5187 es
.dwCookie
= (DWORD_PTR
)&streamText3
;
5189 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5190 ok(result
== 0, "got %ld, expected %d\n", result
, 0);
5192 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5194 "EM_STREAMIN: Test 3 returned %ld, expected 0\n", result
);
5195 ok (strlen(buffer
) == 0,
5196 "EM_STREAMIN: Test 3 set wrong text: Result: %s\n",buffer
);
5197 ok(es
.dwError
== -16, "EM_STREAMIN: Test 3 set error %d, expected %d\n", es
.dwError
, -16);
5199 es
.dwCookie
= (DWORD_PTR
)&streamTextUTF8BOM
;
5201 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5202 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
5203 ok(result
== 18, "got %ld, expected %d\n", result
, 18);
5205 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5207 "EM_STREAMIN: Test UTF8WithBOM returned %ld, expected 15\n", result
);
5208 result
= strcmp (buffer
,"TestUTF8WithBOM");
5210 "EM_STREAMIN: Test UTF8WithBOM set wrong text: Result: %s\n",buffer
);
5211 ok(es
.dwError
== 0, "EM_STREAMIN: Test UTF8WithBOM set error %d, expected %d\n", es
.dwError
, 0);
5214 es
.dwCookie
= (DWORD_PTR
)&phase
;
5216 es
.pfnCallback
= test_EM_STREAMIN_esCallback_UTF8Split
;
5217 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
5218 ok(result
== 8, "got %ld\n", result
);
5220 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5222 "EM_STREAMIN: Test UTF8Split returned %ld\n", result
);
5223 result
= memcmp (buffer
,"\xd6\xcf\xcb", 3);
5225 "EM_STREAMIN: Test UTF8Split set wrong text: Result: %s\n",buffer
);
5226 ok(es
.dwError
== 0, "EM_STREAMIN: Test UTF8Split set error %d, expected %d\n", es
.dwError
, 0);
5228 es
.dwCookie
= (DWORD_PTR
)&cookieForStream4
;
5230 es
.pfnCallback
= test_EM_STREAMIN_esCallback2
;
5231 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
5232 ok(result
== length4
, "got %ld, expected %d\n", result
, length4
);
5234 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5235 ok (result
== length4
,
5236 "EM_STREAMIN: Test 4 returned %ld, expected %d\n", result
, length4
);
5237 ok(es
.dwError
== 0, "EM_STREAMIN: Test 4 set error %d, expected %d\n", es
.dwError
, 0);
5239 es
.dwCookie
= (DWORD_PTR
)&cookieForStream5
;
5241 es
.pfnCallback
= test_EM_STREAMIN_esCallback2
;
5242 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
| SF_UNICODE
, (LPARAM
)&es
);
5243 ok(result
== sizeof(streamText5
), "got %ld, expected %u\n", result
, (UINT
)sizeof(streamText5
));
5245 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5246 ok (result
== length5
,
5247 "EM_STREAMIN: Test 5 returned %ld, expected %d\n", result
, length5
);
5248 ok(es
.dwError
== 0, "EM_STREAMIN: Test 5 set error %d, expected %d\n", es
.dwError
, 0);
5250 DestroyWindow(hwndRichEdit
);
5253 static void test_EM_StreamIn_Undo(void)
5255 /* The purpose of this test is to determine when a EM_StreamIn should be
5256 * undoable. This is important because WM_PASTE currently uses StreamIn and
5257 * pasting should always be undoable but streaming isn't always.
5260 * StreamIn plain text without SFF_SELECTION.
5261 * StreamIn plain text with SFF_SELECTION set but a zero-length selection
5262 * StreamIn plain text with SFF_SELECTION and a valid, normal selection
5263 * StreamIn plain text with SFF_SELECTION and a backwards-selection (from>to)
5264 * Feel free to add tests for other text modes or StreamIn things.
5268 HWND hwndRichEdit
= new_richedit(NULL
);
5271 char buffer
[1024] = {0};
5272 const char randomtext
[] = "Some text";
5274 es
.pfnCallback
= EditStreamCallback
;
5276 /* StreamIn, no SFF_SELECTION */
5277 es
.dwCookie
= nCallbackCount
;
5278 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
5279 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)randomtext
);
5280 SendMessageA(hwndRichEdit
, EM_SETSEL
,0,0);
5281 SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
5282 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5283 result
= strcmp (buffer
,"test");
5285 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer
);
5287 result
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
5288 ok (result
== FALSE
,
5289 "EM_STREAMIN without SFF_SELECTION wrongly allows undo\n");
5291 /* StreamIn, SFF_SELECTION, but nothing selected */
5292 es
.dwCookie
= nCallbackCount
;
5293 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
5294 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)randomtext
);
5295 SendMessageA(hwndRichEdit
, EM_SETSEL
,0,0);
5296 SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
|SFF_SELECTION
, (LPARAM
)&es
);
5297 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5298 result
= strcmp (buffer
,"testSome text");
5300 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
5302 result
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
5304 "EM_STREAMIN with SFF_SELECTION but no selection set "
5305 "should create an undo\n");
5307 /* StreamIn, SFF_SELECTION, with a selection */
5308 es
.dwCookie
= nCallbackCount
;
5309 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
5310 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)randomtext
);
5311 SendMessageA(hwndRichEdit
, EM_SETSEL
,4,5);
5312 SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
|SFF_SELECTION
, (LPARAM
)&es
);
5313 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5314 result
= strcmp (buffer
,"Sometesttext");
5316 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
5318 result
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
5320 "EM_STREAMIN with SFF_SELECTION and selection set "
5321 "should create an undo\n");
5323 DestroyWindow(hwndRichEdit
);
5326 static BOOL
is_em_settextex_supported(HWND hwnd
)
5328 SETTEXTEX stex
= { ST_DEFAULT
, CP_ACP
};
5329 return SendMessageA(hwnd
, EM_SETTEXTEX
, (WPARAM
)&stex
, 0) != 0;
5332 static void test_unicode_conversions(void)
5334 static const WCHAR tW
[] = {'t',0};
5335 static const WCHAR teW
[] = {'t','e',0};
5336 static const WCHAR textW
[] = {'t','e','s','t',0};
5337 static const char textA
[] = "test";
5341 int em_settextex_supported
, ret
;
5343 #define set_textA(hwnd, wm_set_text, txt) \
5345 SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; \
5346 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
5347 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
5348 ret = SendMessageA(hwnd, wm_set_text, wparam, (LPARAM)txt); \
5349 ok(ret, "SendMessageA(%02x) error %u\n", wm_set_text, GetLastError()); \
5351 #define expect_textA(hwnd, wm_get_text, txt) \
5353 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
5354 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
5355 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
5356 memset(bufA, 0xAA, sizeof(bufA)); \
5357 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
5358 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
5359 ret = lstrcmpA(bufA, txt); \
5360 ok(!ret, "%02x: strings do not match: expected %s got %s\n", wm_get_text, txt, bufA); \
5363 #define set_textW(hwnd, wm_set_text, txt) \
5365 SETTEXTEX stex = { ST_DEFAULT, 1200 }; \
5366 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
5367 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
5368 ret = SendMessageW(hwnd, wm_set_text, wparam, (LPARAM)txt); \
5369 ok(ret, "SendMessageW(%02x) error %u\n", wm_set_text, GetLastError()); \
5371 #define expect_textW(hwnd, wm_get_text, txt) \
5373 GETTEXTEX gtex = { 64, GT_DEFAULT, 1200, NULL, NULL }; \
5374 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
5375 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
5376 memset(bufW, 0xAA, sizeof(bufW)); \
5377 ret = SendMessageW(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
5378 ok(ret, "SendMessageW(%02x) error %u\n", wm_get_text, GetLastError()); \
5379 ret = lstrcmpW(bufW, txt); \
5380 ok(!ret, "%02x: strings do not match: expected[0] %x got[0] %x\n", wm_get_text, txt[0], bufW[0]); \
5382 #define expect_empty(hwnd, wm_get_text) \
5384 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
5385 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
5386 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
5387 memset(bufA, 0xAA, sizeof(bufA)); \
5388 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
5389 ok(!ret, "empty richedit should return 0, got %d\n", ret); \
5390 ok(!*bufA, "empty richedit should return empty string, got %s\n", bufA); \
5393 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
,
5394 0, 0, 200, 60, 0, 0, 0, 0);
5395 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5397 ret
= IsWindowUnicode(hwnd
);
5398 ok(ret
, "RichEdit20W should be unicode under NT\n");
5400 /* EM_SETTEXTEX is supported starting from version 3.0 */
5401 em_settextex_supported
= is_em_settextex_supported(hwnd
);
5402 trace("EM_SETTEXTEX is %ssupported on this platform\n",
5403 em_settextex_supported
? "" : "NOT ");
5405 expect_empty(hwnd
, WM_GETTEXT
);
5406 expect_empty(hwnd
, EM_GETTEXTEX
);
5408 ret
= SendMessageA(hwnd
, WM_CHAR
, textW
[0], 0);
5409 ok(!ret
, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret
);
5410 expect_textA(hwnd
, WM_GETTEXT
, "t");
5411 expect_textA(hwnd
, EM_GETTEXTEX
, "t");
5412 expect_textW(hwnd
, EM_GETTEXTEX
, tW
);
5414 ret
= SendMessageA(hwnd
, WM_CHAR
, textA
[1], 0);
5415 ok(!ret
, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret
);
5416 expect_textA(hwnd
, WM_GETTEXT
, "te");
5417 expect_textA(hwnd
, EM_GETTEXTEX
, "te");
5418 expect_textW(hwnd
, EM_GETTEXTEX
, teW
);
5420 set_textA(hwnd
, WM_SETTEXT
, NULL
);
5421 expect_empty(hwnd
, WM_GETTEXT
);
5422 expect_empty(hwnd
, EM_GETTEXTEX
);
5424 set_textA(hwnd
, WM_SETTEXT
, textA
);
5425 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5426 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5427 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5429 if (em_settextex_supported
)
5431 set_textA(hwnd
, EM_SETTEXTEX
, textA
);
5432 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5433 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5434 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5437 set_textW(hwnd
, WM_SETTEXT
, textW
);
5438 expect_textW(hwnd
, WM_GETTEXT
, textW
);
5439 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5440 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5441 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5443 if (em_settextex_supported
)
5445 set_textW(hwnd
, EM_SETTEXTEX
, textW
);
5446 expect_textW(hwnd
, WM_GETTEXT
, textW
);
5447 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5448 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5449 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5451 DestroyWindow(hwnd
);
5453 hwnd
= CreateWindowExA(0, "RichEdit20A", NULL
, WS_POPUP
,
5454 0, 0, 200, 60, 0, 0, 0, 0);
5455 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5457 ret
= IsWindowUnicode(hwnd
);
5458 ok(!ret
, "RichEdit20A should NOT be unicode\n");
5460 set_textA(hwnd
, WM_SETTEXT
, textA
);
5461 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5462 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5463 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5465 if (em_settextex_supported
)
5467 set_textA(hwnd
, EM_SETTEXTEX
, textA
);
5468 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5469 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5470 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5473 set_textW(hwnd
, WM_SETTEXT
, textW
);
5474 expect_textW(hwnd
, WM_GETTEXT
, textW
);
5475 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5476 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5477 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5479 if (em_settextex_supported
)
5481 set_textW(hwnd
, EM_SETTEXTEX
, textW
);
5482 expect_textW(hwnd
, WM_GETTEXT
, textW
);
5483 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5484 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5485 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5487 DestroyWindow(hwnd
);
5490 static void test_WM_CHAR(void)
5494 const char * char_list
= "abc\rabc\r";
5495 const char * expected_content_single
= "abcabc";
5496 const char * expected_content_multi
= "abc\r\nabc\r\n";
5497 char buffer
[64] = {0};
5500 /* single-line control must IGNORE carriage returns */
5501 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
,
5502 0, 0, 200, 60, 0, 0, 0, 0);
5503 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5506 while (*p
!= '\0') {
5507 SendMessageA(hwnd
, WM_KEYDOWN
, *p
, 1);
5508 ret
= SendMessageA(hwnd
, WM_CHAR
, *p
, 1);
5509 ok(ret
== 0, "WM_CHAR('%c') ret=%d\n", *p
, ret
);
5510 SendMessageA(hwnd
, WM_KEYUP
, *p
, 1);
5514 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5515 ret
= strcmp(buffer
, expected_content_single
);
5516 ok(ret
== 0, "WM_GETTEXT recovered incorrect string!\n");
5518 DestroyWindow(hwnd
);
5520 /* multi-line control inserts CR normally */
5521 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
|ES_MULTILINE
,
5522 0, 0, 200, 60, 0, 0, 0, 0);
5523 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5526 while (*p
!= '\0') {
5527 SendMessageA(hwnd
, WM_KEYDOWN
, *p
, 1);
5528 ret
= SendMessageA(hwnd
, WM_CHAR
, *p
, 1);
5529 ok(ret
== 0, "WM_CHAR('%c') ret=%d\n", *p
, ret
);
5530 SendMessageA(hwnd
, WM_KEYUP
, *p
, 1);
5534 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5535 ret
= strcmp(buffer
, expected_content_multi
);
5536 ok(ret
== 0, "WM_GETTEXT recovered incorrect string!\n");
5538 DestroyWindow(hwnd
);
5541 static void test_EM_GETTEXTLENGTHEX(void)
5544 GETTEXTLENGTHEX gtl
;
5546 const char * base_string
= "base string";
5547 const char * test_string
= "a\nb\n\n\r\n";
5548 const char * test_string_after
= "a";
5549 const char * test_string_2
= "a\rtest\rstring";
5550 char buffer
[64] = {0};
5553 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
,
5554 0, 0, 200, 60, 0, 0, 0, 0);
5555 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5557 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5558 gtl
.codepage
= CP_ACP
;
5559 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5560 ok(ret
== 0, "ret %d\n",ret
);
5562 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5563 gtl
.codepage
= CP_ACP
;
5564 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5565 ok(ret
== 0, "ret %d\n",ret
);
5567 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)base_string
);
5569 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5570 gtl
.codepage
= CP_ACP
;
5571 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5572 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
5574 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5575 gtl
.codepage
= CP_ACP
;
5576 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5577 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
5579 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)test_string
);
5581 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5582 gtl
.codepage
= CP_ACP
;
5583 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5584 ok(ret
== 1, "ret %d\n",ret
);
5586 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5587 gtl
.codepage
= CP_ACP
;
5588 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5589 ok(ret
== 1, "ret %d\n",ret
);
5591 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5592 ret
= strcmp(buffer
, test_string_after
);
5593 ok(ret
== 0, "WM_GETTEXT recovered incorrect string!\n");
5595 DestroyWindow(hwnd
);
5598 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
| ES_MULTILINE
,
5599 0, 0, 200, 60, 0, 0, 0, 0);
5600 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5602 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5603 gtl
.codepage
= CP_ACP
;
5604 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5605 ok(ret
== 0, "ret %d\n",ret
);
5607 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5608 gtl
.codepage
= CP_ACP
;
5609 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5610 ok(ret
== 0, "ret %d\n",ret
);
5612 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)base_string
);
5614 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5615 gtl
.codepage
= CP_ACP
;
5616 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5617 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
5619 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5620 gtl
.codepage
= CP_ACP
;
5621 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5622 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
5624 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)test_string_2
);
5626 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5627 gtl
.codepage
= CP_ACP
;
5628 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5629 ok(ret
== strlen(test_string_2
) + 2, "ret %d\n",ret
);
5631 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5632 gtl
.codepage
= CP_ACP
;
5633 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5634 ok(ret
== strlen(test_string_2
), "ret %d\n",ret
);
5636 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)test_string
);
5638 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5639 gtl
.codepage
= CP_ACP
;
5640 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5641 ok(ret
== 10, "ret %d\n",ret
);
5643 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5644 gtl
.codepage
= CP_ACP
;
5645 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5646 ok(ret
== 6, "ret %d\n",ret
);
5648 /* Unicode/NUMCHARS/NUMBYTES */
5649 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)test_string_2
);
5651 gtl
.flags
= GTL_DEFAULT
;
5652 gtl
.codepage
= 1200;
5653 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5654 ok(ret
== lstrlenA(test_string_2
),
5655 "GTL_DEFAULT gave %i, expected %i\n", ret
, lstrlenA(test_string_2
));
5657 gtl
.flags
= GTL_NUMCHARS
;
5658 gtl
.codepage
= 1200;
5659 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5660 ok(ret
== lstrlenA(test_string_2
),
5661 "GTL_NUMCHARS gave %i, expected %i\n", ret
, lstrlenA(test_string_2
));
5663 gtl
.flags
= GTL_NUMBYTES
;
5664 gtl
.codepage
= 1200;
5665 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5666 ok(ret
== lstrlenA(test_string_2
)*2,
5667 "GTL_NUMBYTES gave %i, expected %i\n", ret
, lstrlenA(test_string_2
)*2);
5669 gtl
.flags
= GTL_PRECISE
;
5670 gtl
.codepage
= 1200;
5671 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5672 ok(ret
== lstrlenA(test_string_2
)*2,
5673 "GTL_PRECISE gave %i, expected %i\n", ret
, lstrlenA(test_string_2
)*2);
5675 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5676 gtl
.codepage
= 1200;
5677 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5678 ok(ret
== lstrlenA(test_string_2
),
5679 "GTL_NUMCHAR | GTL_PRECISE gave %i, expected %i\n", ret
, lstrlenA(test_string_2
));
5681 gtl
.flags
= GTL_NUMCHARS
| GTL_NUMBYTES
;
5682 gtl
.codepage
= 1200;
5683 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5684 ok(ret
== E_INVALIDARG
,
5685 "GTL_NUMCHARS | GTL_NUMBYTES gave %i, expected %i\n", ret
, E_INVALIDARG
);
5687 DestroyWindow(hwnd
);
5691 /* globals that parent and child access when checking event masks & notifications */
5692 static HWND eventMaskEditHwnd
= 0;
5693 static int queriedEventMask
;
5694 static int watchForEventMask
= 0;
5696 /* parent proc that queries the edit's event mask when it gets a WM_COMMAND */
5697 static LRESULT WINAPI
ParentMsgCheckProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
5699 if(message
== WM_COMMAND
&& (watchForEventMask
& (wParam
>> 16)))
5701 queriedEventMask
= SendMessageA(eventMaskEditHwnd
, EM_GETEVENTMASK
, 0, 0);
5703 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
5706 /* test event masks in combination with WM_COMMAND */
5707 static void test_eventMask(void)
5712 const char text
[] = "foo bar\n";
5715 /* register class to capture WM_COMMAND */
5717 cls
.lpfnWndProc
= ParentMsgCheckProcA
;
5720 cls
.hInstance
= GetModuleHandleA(0);
5722 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
5723 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
5724 cls
.lpszMenuName
= NULL
;
5725 cls
.lpszClassName
= "EventMaskParentClass";
5726 if(!RegisterClassA(&cls
)) assert(0);
5728 parent
= CreateWindowA(cls
.lpszClassName
, NULL
, WS_POPUP
|WS_VISIBLE
,
5729 0, 0, 200, 60, NULL
, NULL
, NULL
, NULL
);
5730 ok (parent
!= 0, "Failed to create parent window\n");
5732 eventMaskEditHwnd
= new_richedit(parent
);
5733 ok(eventMaskEditHwnd
!= 0, "Failed to create edit window\n");
5735 eventMask
= ENM_CHANGE
| ENM_UPDATE
;
5736 ret
= SendMessageA(eventMaskEditHwnd
, EM_SETEVENTMASK
, 0, eventMask
);
5737 ok(ret
== ENM_NONE
, "wrong event mask\n");
5738 ret
= SendMessageA(eventMaskEditHwnd
, EM_GETEVENTMASK
, 0, 0);
5739 ok(ret
== eventMask
, "failed to set event mask\n");
5741 /* check what happens when we ask for EN_CHANGE and send WM_SETTEXT */
5742 queriedEventMask
= 0; /* initialize to something other than we expect */
5743 watchForEventMask
= EN_CHANGE
;
5744 ret
= SendMessageA(eventMaskEditHwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
5745 ok(ret
== TRUE
, "failed to set text\n");
5746 /* richedit should mask off ENM_CHANGE when it sends an EN_CHANGE
5747 notification in response to WM_SETTEXT */
5748 ok(queriedEventMask
== (eventMask
& ~ENM_CHANGE
),
5749 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
5751 /* check to see if EN_CHANGE is sent when redraw is turned off */
5752 SendMessageA(eventMaskEditHwnd
, WM_CLEAR
, 0, 0);
5753 ok(IsWindowVisible(eventMaskEditHwnd
), "Window should be visible.\n");
5754 SendMessageA(eventMaskEditHwnd
, WM_SETREDRAW
, FALSE
, 0);
5755 /* redraw is disabled by making the window invisible. */
5756 ok(!IsWindowVisible(eventMaskEditHwnd
), "Window shouldn't be visible.\n");
5757 queriedEventMask
= 0; /* initialize to something other than we expect */
5758 SendMessageA(eventMaskEditHwnd
, EM_REPLACESEL
, 0, (LPARAM
)text
);
5759 ok(queriedEventMask
== (eventMask
& ~ENM_CHANGE
),
5760 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
5761 SendMessageA(eventMaskEditHwnd
, WM_SETREDRAW
, TRUE
, 0);
5762 ok(IsWindowVisible(eventMaskEditHwnd
), "Window should be visible.\n");
5764 /* check to see if EN_UPDATE is sent when the editor isn't visible */
5765 SendMessageA(eventMaskEditHwnd
, WM_CLEAR
, 0, 0);
5766 style
= GetWindowLongA(eventMaskEditHwnd
, GWL_STYLE
);
5767 SetWindowLongA(eventMaskEditHwnd
, GWL_STYLE
, style
& ~WS_VISIBLE
);
5768 ok(!IsWindowVisible(eventMaskEditHwnd
), "Window shouldn't be visible.\n");
5769 watchForEventMask
= EN_UPDATE
;
5770 queriedEventMask
= 0; /* initialize to something other than we expect */
5771 SendMessageA(eventMaskEditHwnd
, EM_REPLACESEL
, 0, (LPARAM
)text
);
5772 ok(queriedEventMask
== 0,
5773 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
5774 SetWindowLongA(eventMaskEditHwnd
, GWL_STYLE
, style
);
5775 ok(IsWindowVisible(eventMaskEditHwnd
), "Window should be visible.\n");
5776 queriedEventMask
= 0; /* initialize to something other than we expect */
5777 SendMessageA(eventMaskEditHwnd
, EM_REPLACESEL
, 0, (LPARAM
)text
);
5778 ok(queriedEventMask
== eventMask
,
5779 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
5782 DestroyWindow(parent
);
5785 static int received_WM_NOTIFY
= 0;
5786 static int modify_at_WM_NOTIFY
= 0;
5787 static BOOL filter_on_WM_NOTIFY
= FALSE
;
5788 static HWND hwndRichedit_WM_NOTIFY
;
5790 static LRESULT WINAPI
WM_NOTIFY_ParentMsgCheckProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
5792 if(message
== WM_NOTIFY
)
5794 received_WM_NOTIFY
= 1;
5795 modify_at_WM_NOTIFY
= SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETMODIFY
, 0, 0);
5796 if (filter_on_WM_NOTIFY
) return TRUE
;
5798 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
5801 static void test_WM_NOTIFY(void)
5806 int sel_start
, sel_end
;
5808 /* register class to capture WM_NOTIFY */
5810 cls
.lpfnWndProc
= WM_NOTIFY_ParentMsgCheckProcA
;
5813 cls
.hInstance
= GetModuleHandleA(0);
5815 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
5816 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
5817 cls
.lpszMenuName
= NULL
;
5818 cls
.lpszClassName
= "WM_NOTIFY_ParentClass";
5819 if(!RegisterClassA(&cls
)) assert(0);
5821 parent
= CreateWindowA(cls
.lpszClassName
, NULL
, WS_POPUP
|WS_VISIBLE
,
5822 0, 0, 200, 60, NULL
, NULL
, NULL
, NULL
);
5823 ok (parent
!= 0, "Failed to create parent window\n");
5825 hwndRichedit_WM_NOTIFY
= new_richedit(parent
);
5826 ok(hwndRichedit_WM_NOTIFY
!= 0, "Failed to create edit window\n");
5828 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETEVENTMASK
, 0, ENM_SELCHANGE
);
5830 /* Notifications for selection change should only be sent when selection
5831 actually changes. EM_SETCHARFORMAT is one message that calls
5832 ME_CommitUndo, which should check whether message should be sent */
5833 received_WM_NOTIFY
= 0;
5834 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
5835 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
5836 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
5837 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
5838 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETCHARFORMAT
, 0, (LPARAM
)&cf2
);
5839 ok(received_WM_NOTIFY
== 0, "Unexpected WM_NOTIFY was sent!\n");
5841 /* WM_SETTEXT should NOT cause a WM_NOTIFY to be sent when selection is
5843 received_WM_NOTIFY
= 0;
5844 modify_at_WM_NOTIFY
= 0;
5845 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_SETTEXT
, 0, (LPARAM
)"sometext");
5846 ok(received_WM_NOTIFY
== 0, "Unexpected WM_NOTIFY was sent!\n");
5847 ok(modify_at_WM_NOTIFY
== 0, "WM_NOTIFY callback saw text flagged as modified!\n");
5849 received_WM_NOTIFY
= 0;
5850 modify_at_WM_NOTIFY
= 0;
5851 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETSEL
, 4, 4);
5852 ok(received_WM_NOTIFY
== 1, "Expected WM_NOTIFY was NOT sent!\n");
5854 received_WM_NOTIFY
= 0;
5855 modify_at_WM_NOTIFY
= 0;
5856 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_SETTEXT
, 0, (LPARAM
)"sometext");
5857 ok(received_WM_NOTIFY
== 1, "Expected WM_NOTIFY was NOT sent!\n");
5858 ok(modify_at_WM_NOTIFY
== 0, "WM_NOTIFY callback saw text flagged as modified!\n");
5860 /* Test for WM_NOTIFY messages with redraw disabled. */
5861 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETSEL
, 0, 0);
5862 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_SETREDRAW
, FALSE
, 0);
5863 received_WM_NOTIFY
= 0;
5864 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_REPLACESEL
, FALSE
, (LPARAM
)"inserted");
5865 ok(received_WM_NOTIFY
== 1, "Expected WM_NOTIFY was NOT sent!\n");
5866 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_SETREDRAW
, TRUE
, 0);
5868 /* Test filtering key events. */
5869 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETSEL
, 0, 0);
5870 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETEVENTMASK
, 0, ENM_KEYEVENTS
);
5871 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5872 received_WM_NOTIFY
= 0;
5873 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_KEYDOWN
, VK_RIGHT
, 0);
5874 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5875 ok(sel_start
== 1 && sel_end
== 1,
5876 "selections is incorrectly at (%d,%d)\n", sel_start
, sel_end
);
5877 filter_on_WM_NOTIFY
= TRUE
;
5878 received_WM_NOTIFY
= 0;
5879 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_KEYDOWN
, VK_RIGHT
, 0);
5880 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5881 ok(sel_start
== 1 && sel_end
== 1,
5882 "selections is incorrectly at (%d,%d)\n", sel_start
, sel_end
);
5884 /* test with owner set to NULL */
5885 SetWindowLongPtrA(hwndRichedit_WM_NOTIFY
, GWLP_HWNDPARENT
, 0);
5886 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_KEYDOWN
, VK_RIGHT
, 0);
5887 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5888 ok(sel_start
== 1 && sel_end
== 1,
5889 "selections is incorrectly at (%d,%d)\n", sel_start
, sel_end
);
5891 DestroyWindow(hwndRichedit_WM_NOTIFY
);
5892 DestroyWindow(parent
);
5895 static void test_undo_coalescing(void)
5899 char buffer
[64] = {0};
5901 /* multi-line control inserts CR normally */
5902 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
|ES_MULTILINE
,
5903 0, 0, 200, 60, 0, 0, 0, 0);
5904 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5906 result
= SendMessageA(hwnd
, EM_CANUNDO
, 0, 0);
5907 ok (result
== FALSE
, "Can undo after window creation.\n");
5908 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
5909 ok (result
== FALSE
, "Undo operation successful with nothing to undo.\n");
5910 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
5911 ok (result
== FALSE
, "Can redo after window creation.\n");
5912 result
= SendMessageA(hwnd
, EM_REDO
, 0, 0);
5913 ok (result
== FALSE
, "Redo operation successful with nothing undone.\n");
5915 /* Test the effect of arrows keys during typing on undo transactions*/
5916 simulate_typing_characters(hwnd
, "one two three");
5917 SendMessageA(hwnd
, WM_KEYDOWN
, VK_RIGHT
, 1);
5918 SendMessageA(hwnd
, WM_KEYUP
, VK_RIGHT
, 1);
5919 simulate_typing_characters(hwnd
, " four five six");
5921 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
5922 ok (result
== FALSE
, "Can redo before anything is undone.\n");
5923 result
= SendMessageA(hwnd
, EM_CANUNDO
, 0, 0);
5924 ok (result
== TRUE
, "Cannot undo typed characters.\n");
5925 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
5926 ok (result
== TRUE
, "EM_UNDO Failed to undo typed characters.\n");
5927 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
5928 ok (result
== TRUE
, "Cannot redo after undo.\n");
5929 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5930 result
= strcmp(buffer
, "one two three");
5931 ok (result
== 0, "expected '%s' but got '%s'\n", "one two three", buffer
);
5933 result
= SendMessageA(hwnd
, EM_CANUNDO
, 0, 0);
5934 ok (result
== TRUE
, "Cannot undo typed characters.\n");
5935 result
= SendMessageA(hwnd
, WM_UNDO
, 0, 0);
5936 ok (result
== TRUE
, "Failed to undo typed characters.\n");
5937 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5938 result
= strcmp(buffer
, "");
5939 ok (result
== 0, "expected '%s' but got '%s'\n", "", buffer
);
5941 /* Test the effect of focus changes during typing on undo transactions*/
5942 simulate_typing_characters(hwnd
, "one two three");
5943 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
5944 ok (result
== FALSE
, "Redo buffer should have been cleared by typing.\n");
5945 SendMessageA(hwnd
, WM_KILLFOCUS
, 0, 0);
5946 SendMessageA(hwnd
, WM_SETFOCUS
, 0, 0);
5947 simulate_typing_characters(hwnd
, " four five six");
5948 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
5949 ok (result
== TRUE
, "Failed to undo typed characters.\n");
5950 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5951 result
= strcmp(buffer
, "one two three");
5952 ok (result
== 0, "expected '%s' but got '%s'\n", "one two three", buffer
);
5954 /* Test the effect of the back key during typing on undo transactions */
5955 SendMessageA(hwnd
, EM_EMPTYUNDOBUFFER
, 0, 0);
5956 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"");
5957 ok (result
== TRUE
, "Failed to clear the text.\n");
5958 simulate_typing_characters(hwnd
, "one two threa");
5959 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
5960 ok (result
== FALSE
, "Redo buffer should have been cleared by typing.\n");
5961 SendMessageA(hwnd
, WM_KEYDOWN
, VK_BACK
, 1);
5962 SendMessageA(hwnd
, WM_KEYUP
, VK_BACK
, 1);
5963 simulate_typing_characters(hwnd
, "e four five six");
5964 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
5965 ok (result
== TRUE
, "Failed to undo typed characters.\n");
5966 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5967 result
= strcmp(buffer
, "");
5968 ok (result
== 0, "expected '%s' but got '%s'\n", "", buffer
);
5970 /* Test the effect of the delete key during typing on undo transactions */
5971 SendMessageA(hwnd
, EM_EMPTYUNDOBUFFER
, 0, 0);
5972 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"abcd");
5973 ok(result
== TRUE
, "Failed to set the text.\n");
5974 SendMessageA(hwnd
, EM_SETSEL
, 1, 1);
5975 SendMessageA(hwnd
, WM_KEYDOWN
, VK_DELETE
, 1);
5976 SendMessageA(hwnd
, WM_KEYUP
, VK_DELETE
, 1);
5977 SendMessageA(hwnd
, WM_KEYDOWN
, VK_DELETE
, 1);
5978 SendMessageA(hwnd
, WM_KEYUP
, VK_DELETE
, 1);
5979 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
5980 ok (result
== TRUE
, "Failed to undo typed characters.\n");
5981 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5982 result
= strcmp(buffer
, "acd");
5983 ok (result
== 0, "expected '%s' but got '%s'\n", "acd", buffer
);
5984 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
5985 ok (result
== TRUE
, "Failed to undo typed characters.\n");
5986 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5987 result
= strcmp(buffer
, "abcd");
5988 ok (result
== 0, "expected '%s' but got '%s'\n", "abcd", buffer
);
5990 /* Test the effect of EM_STOPGROUPTYPING on undo transactions*/
5991 SendMessageA(hwnd
, EM_EMPTYUNDOBUFFER
, 0, 0);
5992 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"");
5993 ok (result
== TRUE
, "Failed to clear the text.\n");
5994 simulate_typing_characters(hwnd
, "one two three");
5995 result
= SendMessageA(hwnd
, EM_STOPGROUPTYPING
, 0, 0);
5996 ok (result
== 0, "expected %d but got %d\n", 0, result
);
5997 simulate_typing_characters(hwnd
, " four five six");
5998 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
5999 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6000 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6001 result
= strcmp(buffer
, "one two three");
6002 ok (result
== 0, "expected '%s' but got '%s'\n", "one two three", buffer
);
6003 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6004 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6005 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6006 result
= strcmp(buffer
, "");
6007 ok (result
== 0, "expected '%s' but got '%s'\n", "", buffer
);
6009 DestroyWindow(hwnd
);
6012 static LONG CALLBACK
customWordBreakProc(WCHAR
*text
, int pos
, int bytes
, int code
)
6016 /* MSDN lied, length is actually the number of bytes. */
6017 length
= bytes
/ sizeof(WCHAR
);
6020 case WB_ISDELIMITER
:
6021 return text
[pos
] == 'X';
6023 case WB_MOVEWORDLEFT
:
6024 if (customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
6026 return min(customWordBreakProc(text
, pos
, bytes
, WB_LEFTBREAK
)-1, 0);
6029 while (pos
> 0 && !customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
6033 case WB_MOVEWORDRIGHT
:
6034 if (customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
6036 return min(customWordBreakProc(text
, pos
, bytes
, WB_RIGHTBREAK
)+1, length
);
6039 while (pos
< length
&& !customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
6043 ok(FALSE
, "Unexpected code %d\n", code
);
6049 static void test_word_movement(void)
6053 int sel_start
, sel_end
;
6054 const WCHAR textW
[] = {'o','n','e',' ','t','w','o','X','t','h','r','e','e',0};
6056 /* multi-line control inserts CR normally */
6057 hwnd
= new_richedit(NULL
);
6059 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"one two three");
6060 ok (result
== TRUE
, "Failed to clear the text.\n");
6061 SendMessageA(hwnd
, EM_SETSEL
, 0, 0);
6062 /* |one two three */
6064 send_ctrl_key(hwnd
, VK_RIGHT
);
6065 /* one |two three */
6066 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6067 ok(sel_start
== sel_end
, "Selection should be empty\n");
6068 ok(sel_start
== 4, "Cursor is at %d instead of %d\n", sel_start
, 4);
6070 send_ctrl_key(hwnd
, VK_RIGHT
);
6071 /* one two |three */
6072 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6073 ok(sel_start
== sel_end
, "Selection should be empty\n");
6074 ok(sel_start
== 9, "Cursor is at %d instead of %d\n", sel_start
, 9);
6076 send_ctrl_key(hwnd
, VK_LEFT
);
6077 /* one |two three */
6078 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6079 ok(sel_start
== sel_end
, "Selection should be empty\n");
6080 ok(sel_start
== 4, "Cursor is at %d instead of %d\n", sel_start
, 4);
6082 send_ctrl_key(hwnd
, VK_LEFT
);
6083 /* |one two three */
6084 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6085 ok(sel_start
== sel_end
, "Selection should be empty\n");
6086 ok(sel_start
== 0, "Cursor is at %d instead of %d\n", sel_start
, 0);
6088 SendMessageA(hwnd
, EM_SETSEL
, 8, 8);
6089 /* one two | three */
6090 send_ctrl_key(hwnd
, VK_RIGHT
);
6091 /* one two |three */
6092 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6093 ok(sel_start
== sel_end
, "Selection should be empty\n");
6094 ok(sel_start
== 9, "Cursor is at %d instead of %d\n", sel_start
, 9);
6096 SendMessageA(hwnd
, EM_SETSEL
, 11, 11);
6097 /* one two th|ree */
6098 send_ctrl_key(hwnd
, VK_LEFT
);
6099 /* one two |three */
6100 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6101 ok(sel_start
== sel_end
, "Selection should be empty\n");
6102 ok(sel_start
== 9, "Cursor is at %d instead of %d\n", sel_start
, 9);
6104 /* Test with a custom word break procedure that uses X as the delimiter. */
6105 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"one twoXthree");
6106 ok (result
== TRUE
, "Failed to clear the text.\n");
6107 SendMessageA(hwnd
, EM_SETWORDBREAKPROC
, 0, (LPARAM
)customWordBreakProc
);
6108 /* |one twoXthree */
6109 send_ctrl_key(hwnd
, VK_RIGHT
);
6110 /* one twoX|three */
6111 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6112 ok(sel_start
== sel_end
, "Selection should be empty\n");
6113 ok(sel_start
== 8, "Cursor is at %d instead of %d\n", sel_start
, 8);
6115 DestroyWindow(hwnd
);
6117 /* Make sure the behaviour is the same with a unicode richedit window,
6118 * and using unicode functions. */
6120 hwnd
= CreateWindowW(RICHEDIT_CLASS20W
, NULL
,
6121 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
6122 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6124 /* Test with a custom word break procedure that uses X as the delimiter. */
6125 result
= SendMessageW(hwnd
, WM_SETTEXT
, 0, (LPARAM
)textW
);
6126 ok (result
== TRUE
, "Failed to clear the text.\n");
6127 SendMessageW(hwnd
, EM_SETWORDBREAKPROC
, 0, (LPARAM
)customWordBreakProc
);
6128 /* |one twoXthree */
6129 send_ctrl_key(hwnd
, VK_RIGHT
);
6130 /* one twoX|three */
6131 SendMessageW(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6132 ok(sel_start
== sel_end
, "Selection should be empty\n");
6133 ok(sel_start
== 8, "Cursor is at %d instead of %d\n", sel_start
, 8);
6135 DestroyWindow(hwnd
);
6138 static void test_EM_CHARFROMPOS(void)
6147 /* multi-line control inserts CR normally */
6148 hwnd
= new_richedit(NULL
);
6149 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0,
6150 (LPARAM
)"one two three four five six seven\reight");
6151 ok(result
== 1, "Expected 1, got %d\n", result
);
6152 GetClientRect(hwnd
, &rcClient
);
6154 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6155 ok(result
== 34, "expected character index of 34 but got %d\n", result
);
6157 /* Test with points outside the bounds of the richedit control. */
6160 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6161 todo_wine
ok(result
== 34, "expected character index of 34 but got %d\n", result
);
6165 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6166 todo_wine
ok(result
== 33, "expected character index of 33 but got %d\n", result
);
6170 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6171 todo_wine
ok(result
== 39, "expected character index of 39 but got %d\n", result
);
6175 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6176 todo_wine
ok(result
== 0, "expected character index of 0 but got %d\n", result
);
6179 point
.y
= rcClient
.bottom
+ 1;
6180 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6181 todo_wine
ok(result
== 34, "expected character index of 34 but got %d\n", result
);
6184 point
.y
= rcClient
.bottom
;
6185 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6186 todo_wine
ok(result
== 39, "expected character index of 39 but got %d\n", result
);
6188 DestroyWindow(hwnd
);
6191 static void test_word_wrap(void)
6194 POINTL point
= {0, 60}; /* This point must be below the first line */
6195 const char *text
= "Must be long enough to test line wrapping";
6196 DWORD dwCommonStyle
= WS_VISIBLE
|WS_POPUP
|WS_VSCROLL
|ES_MULTILINE
;
6197 int res
, pos
, lines
;
6199 /* Test the effect of WS_HSCROLL and ES_AUTOHSCROLL styles on wrapping
6200 * when specified on window creation and set later. */
6201 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, dwCommonStyle
,
6202 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6203 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6204 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
6205 ok(res
, "WM_SETTEXT failed.\n");
6206 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6207 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
6208 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6209 ok(lines
> 1, "Line was expected to wrap (lines=%d).\n", lines
);
6211 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
|WS_HSCROLL
|ES_AUTOHSCROLL
);
6212 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6213 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
6214 DestroyWindow(hwnd
);
6216 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, dwCommonStyle
|WS_HSCROLL
,
6217 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6218 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6220 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
6221 ok(res
, "WM_SETTEXT failed.\n");
6222 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6223 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6224 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6225 ok(lines
== 1, "Line wasn't expected to wrap (lines=%d).\n", lines
);
6227 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
);
6228 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6229 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6230 DestroyWindow(hwnd
);
6232 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, dwCommonStyle
|ES_AUTOHSCROLL
,
6233 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6234 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6235 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
6236 ok(res
, "WM_SETTEXT failed.\n");
6237 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6238 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6240 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
);
6241 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6242 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6243 DestroyWindow(hwnd
);
6245 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
,
6246 dwCommonStyle
|WS_HSCROLL
|ES_AUTOHSCROLL
,
6247 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6248 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6249 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
6250 ok(res
, "WM_SETTEXT failed.\n");
6251 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6252 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6254 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
);
6255 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6256 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6258 /* Test the effect of EM_SETTARGETDEVICE on word wrap. */
6259 res
= SendMessageA(hwnd
, EM_SETTARGETDEVICE
, 0, 1);
6260 ok(res
, "EM_SETTARGETDEVICE failed (returned %d).\n", res
);
6261 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6262 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6264 res
= SendMessageA(hwnd
, EM_SETTARGETDEVICE
, 0, 0);
6265 ok(res
, "EM_SETTARGETDEVICE failed (returned %d).\n", res
);
6266 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6267 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
6268 DestroyWindow(hwnd
);
6270 /* Test to see if wrapping happens with redraw disabled. */
6271 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, dwCommonStyle
,
6272 0, 0, 400, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6273 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6274 SendMessageA(hwnd
, WM_SETREDRAW
, FALSE
, 0);
6275 res
= SendMessageA(hwnd
, EM_REPLACESEL
, FALSE
, (LPARAM
)text
);
6276 ok(res
, "EM_REPLACESEL failed.\n");
6277 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6278 ok(lines
== 1, "Line wasn't expected to wrap (lines=%d).\n", lines
);
6279 MoveWindow(hwnd
, 0, 0, 200, 80, FALSE
);
6280 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6281 ok(lines
> 1, "Line was expected to wrap (lines=%d).\n", lines
);
6283 SendMessageA(hwnd
, WM_SETREDRAW
, TRUE
, 0);
6284 DestroyWindow(hwnd
);
6287 static void test_autoscroll(void)
6289 HWND hwnd
= new_richedit(NULL
);
6290 int lines
, ret
, redraw
;
6293 for (redraw
= 0; redraw
<= 1; redraw
++) {
6294 trace("testing with WM_SETREDRAW=%d\n", redraw
);
6295 SendMessageA(hwnd
, WM_SETREDRAW
, redraw
, 0);
6296 SendMessageA(hwnd
, EM_REPLACESEL
, 0, (LPARAM
)"1\n2\n3\n4\n5\n6\n7\n8");
6297 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6298 ok(lines
== 8, "%d lines instead of 8\n", lines
);
6299 ret
= SendMessageA(hwnd
, EM_GETSCROLLPOS
, 0, (LPARAM
)&pt
);
6300 ok(ret
== 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret
);
6301 ok(pt
.y
!= 0, "Didn't scroll down after replacing text.\n");
6302 ret
= GetWindowLongA(hwnd
, GWL_STYLE
);
6303 ok(ret
& WS_VSCROLL
, "Scrollbar was not shown yet (style=%x).\n", (UINT
)ret
);
6305 SendMessageA(hwnd
, WM_SETTEXT
, 0, 0);
6306 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6307 ok(lines
== 1, "%d lines instead of 1\n", lines
);
6308 ret
= SendMessageA(hwnd
, EM_GETSCROLLPOS
, 0, (LPARAM
)&pt
);
6309 ok(ret
== 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret
);
6310 ok(pt
.y
== 0, "y scroll position is %d after clearing text.\n", pt
.y
);
6311 ret
= GetWindowLongA(hwnd
, GWL_STYLE
);
6312 ok(!(ret
& WS_VSCROLL
), "Scrollbar is still shown (style=%x).\n", (UINT
)ret
);
6315 SendMessageA(hwnd
, WM_SETREDRAW
, TRUE
, 0);
6316 DestroyWindow(hwnd
);
6318 /* The WS_VSCROLL and WS_HSCROLL styles implicitly set
6319 * auto vertical/horizontal scrolling options. */
6320 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6321 WS_POPUP
|ES_MULTILINE
|WS_VSCROLL
|WS_HSCROLL
,
6322 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6323 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6324 ret
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
6325 ok(ret
& ECO_AUTOVSCROLL
, "ECO_AUTOVSCROLL isn't set.\n");
6326 ok(ret
& ECO_AUTOHSCROLL
, "ECO_AUTOHSCROLL isn't set.\n");
6327 ret
= GetWindowLongA(hwnd
, GWL_STYLE
);
6328 ok(!(ret
& ES_AUTOVSCROLL
), "ES_AUTOVSCROLL is set.\n");
6329 ok(!(ret
& ES_AUTOHSCROLL
), "ES_AUTOHSCROLL is set.\n");
6330 DestroyWindow(hwnd
);
6332 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6333 WS_POPUP
|ES_MULTILINE
,
6334 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6335 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6336 ret
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
6337 ok(!(ret
& ECO_AUTOVSCROLL
), "ECO_AUTOVSCROLL is set.\n");
6338 ok(!(ret
& ECO_AUTOHSCROLL
), "ECO_AUTOHSCROLL is set.\n");
6339 ret
= GetWindowLongA(hwnd
, GWL_STYLE
);
6340 ok(!(ret
& ES_AUTOVSCROLL
), "ES_AUTOVSCROLL is set.\n");
6341 ok(!(ret
& ES_AUTOHSCROLL
), "ES_AUTOHSCROLL is set.\n");
6342 DestroyWindow(hwnd
);
6346 static void test_format_rect(void)
6349 RECT rc
, expected
, clientRect
;
6353 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6354 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
6355 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6356 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6358 GetClientRect(hwnd
, &clientRect
);
6360 expected
= clientRect
;
6362 expected
.right
-= 1;
6363 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6364 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6365 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6366 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6367 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6368 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6370 for (n
= -3; n
<= 3; n
++)
6377 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6380 expected
.top
= max(0, rc
.top
);
6381 expected
.left
= max(0, rc
.left
);
6382 expected
.bottom
= min(clientRect
.bottom
, rc
.bottom
);
6383 expected
.right
= min(clientRect
.right
, rc
.right
);
6384 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6385 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6386 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6387 "[n=%d] rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6388 n
, rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6389 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6393 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6394 expected
= clientRect
;
6395 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6396 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6397 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6398 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6399 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6400 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6402 /* Adding the selectionbar adds the selectionbar width to the left side. */
6403 SendMessageA(hwnd
, EM_SETOPTIONS
, ECOOP_OR
, ECO_SELECTIONBAR
);
6404 options
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
6405 ok(options
& ECO_SELECTIONBAR
, "EM_SETOPTIONS failed to add selectionbar.\n");
6406 expected
.left
+= 8; /* selection bar width */
6407 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6408 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6409 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6410 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6411 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6412 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6415 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6416 expected
= clientRect
;
6417 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6418 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6419 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6420 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6421 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6422 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6424 /* Removing the selectionbar subtracts the selectionbar width from the left side,
6425 * even if the left side is already 0. */
6426 SendMessageA(hwnd
, EM_SETOPTIONS
, ECOOP_AND
, ~ECO_SELECTIONBAR
);
6427 options
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
6428 ok(!(options
& ECO_SELECTIONBAR
), "EM_SETOPTIONS failed to remove selectionbar.\n");
6429 expected
.left
-= 8; /* selection bar width */
6430 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6431 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6432 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6433 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6434 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6435 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6437 /* Set the absolute value of the formatting rectangle. */
6439 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6440 expected
= clientRect
;
6441 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6442 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6443 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6444 "[n=%d] rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6445 n
, rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6446 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6448 /* MSDN documents the EM_SETRECT message as using the rectangle provided in
6449 * LPARAM as being a relative offset when the WPARAM value is 1, but these
6450 * tests show that this isn't true. */
6453 rc
.bottom
= clientRect
.bottom
- 15;
6454 rc
.right
= clientRect
.right
- 15;
6456 SendMessageA(hwnd
, EM_SETRECT
, 1, (LPARAM
)&rc
);
6457 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6458 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6459 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6460 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6461 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6462 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6464 /* For some reason it does not limit the values to the client rect with
6465 * a WPARAM value of 1. */
6468 rc
.bottom
= clientRect
.bottom
+ 15;
6469 rc
.right
= clientRect
.right
+ 15;
6471 SendMessageA(hwnd
, EM_SETRECT
, 1, (LPARAM
)&rc
);
6472 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6473 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6474 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6475 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6476 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6477 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6479 /* Reset to default rect and check how the format rect adjusts to window
6480 * resize and how it copes with very small windows */
6481 SendMessageA(hwnd
, EM_SETRECT
, 0, 0);
6483 MoveWindow(hwnd
, 0, 0, 100, 30, FALSE
);
6484 GetClientRect(hwnd
, &clientRect
);
6486 expected
= clientRect
;
6488 expected
.right
-= 1;
6489 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6490 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6491 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6492 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6493 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6494 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6496 MoveWindow(hwnd
, 0, 0, 0, 30, FALSE
);
6497 GetClientRect(hwnd
, &clientRect
);
6499 expected
= clientRect
;
6501 expected
.right
-= 1;
6502 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6503 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6504 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6505 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6506 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6507 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6509 MoveWindow(hwnd
, 0, 0, 100, 0, FALSE
);
6510 GetClientRect(hwnd
, &clientRect
);
6512 expected
= clientRect
;
6514 expected
.right
-= 1;
6515 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6516 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6517 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6518 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6519 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6520 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6522 DestroyWindow(hwnd
);
6524 /* The extended window style affects the formatting rectangle. */
6525 hwnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, RICHEDIT_CLASS20A
, NULL
,
6526 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
6527 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6528 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6530 GetClientRect(hwnd
, &clientRect
);
6532 expected
= clientRect
;
6535 expected
.right
-= 1;
6536 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6537 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6538 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6539 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6540 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6541 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6551 expected
.right
+= 1;
6552 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6553 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6554 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6555 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6556 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6557 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6558 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6560 DestroyWindow(hwnd
);
6563 static void test_WM_GETDLGCODE(void)
6569 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6571 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6572 ES_MULTILINE
|ES_WANTRETURN
|WS_POPUP
,
6573 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6574 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6576 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, 0);
6577 expected
= expected
| DLGC_WANTMESSAGE
;
6578 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6580 DestroyWindow(hwnd
);
6582 msg
.message
= WM_KEYDOWN
;
6583 msg
.wParam
= VK_RETURN
;
6584 msg
.lParam
= (MapVirtualKeyA(VK_RETURN
, MAPVK_VK_TO_VSC
) << 16) | 0x0001;
6587 msg
.time
= GetTickCount();
6589 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6590 ES_MULTILINE
|ES_WANTRETURN
|WS_POPUP
,
6591 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6592 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6594 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6595 expected
= expected
| DLGC_WANTMESSAGE
;
6596 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6598 DestroyWindow(hwnd
);
6600 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6601 ES_MULTILINE
|WS_POPUP
,
6602 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6603 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6605 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6606 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6607 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6609 DestroyWindow(hwnd
);
6611 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6612 ES_WANTRETURN
|WS_POPUP
,
6613 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6614 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6616 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6617 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6618 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6620 DestroyWindow(hwnd
);
6622 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6624 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6625 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6627 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6628 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6629 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6631 DestroyWindow(hwnd
);
6633 msg
.wParam
= VK_TAB
;
6634 msg
.lParam
= (MapVirtualKeyA(VK_TAB
, MAPVK_VK_TO_VSC
) << 16) | 0x0001;
6636 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6637 ES_MULTILINE
|WS_POPUP
,
6638 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6639 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6641 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6642 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6643 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6645 DestroyWindow(hwnd
);
6647 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6649 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6650 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6652 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6653 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6654 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6656 DestroyWindow(hwnd
);
6658 hold_key(VK_CONTROL
);
6660 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6661 ES_MULTILINE
|WS_POPUP
,
6662 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6663 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6665 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6666 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6667 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6669 DestroyWindow(hwnd
);
6671 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6673 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6674 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6676 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6677 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6678 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6680 DestroyWindow(hwnd
);
6682 release_key(VK_CONTROL
);
6685 msg
.lParam
= (MapVirtualKeyA('a', MAPVK_VK_TO_VSC
) << 16) | 0x0001;
6687 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6688 ES_MULTILINE
|WS_POPUP
,
6689 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6690 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6692 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6693 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6694 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6696 DestroyWindow(hwnd
);
6698 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6700 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6701 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6703 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6704 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6705 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6707 DestroyWindow(hwnd
);
6709 msg
.message
= WM_CHAR
;
6711 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6712 ES_MULTILINE
|WS_POPUP
,
6713 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6714 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6716 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6717 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6718 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6720 DestroyWindow(hwnd
);
6722 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6724 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6725 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6727 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6728 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6729 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6731 DestroyWindow(hwnd
);
6734 static void test_zoom(void)
6740 int numerator
, denominator
;
6742 hwnd
= new_richedit(NULL
);
6743 GetClientRect(hwnd
, &rc
);
6744 pt
.x
= (rc
.right
- rc
.left
) / 2;
6745 pt
.y
= (rc
.bottom
- rc
.top
) / 2;
6746 ClientToScreen(hwnd
, &pt
);
6748 /* Test initial zoom value */
6749 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6750 ok(numerator
== 0, "Numerator should be initialized to 0 (got %d).\n", numerator
);
6751 ok(denominator
== 0, "Denominator should be initialized to 0 (got %d).\n", denominator
);
6752 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6754 /* test scroll wheel */
6755 hold_key(VK_CONTROL
);
6756 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
6757 MAKELPARAM(pt
.x
, pt
.y
));
6758 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6759 release_key(VK_CONTROL
);
6761 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6762 ok(numerator
== 110, "incorrect numerator is %d\n", numerator
);
6763 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6764 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6766 /* Test how much the mouse wheel can zoom in and out. */
6767 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 490, 100);
6768 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6770 hold_key(VK_CONTROL
);
6771 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
6772 MAKELPARAM(pt
.x
, pt
.y
));
6773 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6774 release_key(VK_CONTROL
);
6776 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6777 ok(numerator
== 500, "incorrect numerator is %d\n", numerator
);
6778 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6779 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6781 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 491, 100);
6782 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6784 hold_key(VK_CONTROL
);
6785 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
6786 MAKELPARAM(pt
.x
, pt
.y
));
6787 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6788 release_key(VK_CONTROL
);
6790 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6791 ok(numerator
== 491, "incorrect numerator is %d\n", numerator
);
6792 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6793 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6795 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 20, 100);
6796 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6798 hold_key(VK_CONTROL
);
6799 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, -WHEEL_DELTA
),
6800 MAKELPARAM(pt
.x
, pt
.y
));
6801 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6802 release_key(VK_CONTROL
);
6804 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6805 ok(numerator
== 10, "incorrect numerator is %d\n", numerator
);
6806 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6807 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6809 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 19, 100);
6810 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6812 hold_key(VK_CONTROL
);
6813 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, -WHEEL_DELTA
),
6814 MAKELPARAM(pt
.x
, pt
.y
));
6815 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6816 release_key(VK_CONTROL
);
6818 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6819 ok(numerator
== 19, "incorrect numerator is %d\n", numerator
);
6820 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6821 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6823 /* Test how WM_SCROLLWHEEL treats our custom denominator. */
6824 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 50, 13);
6825 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6827 hold_key(VK_CONTROL
);
6828 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
6829 MAKELPARAM(pt
.x
, pt
.y
));
6830 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6831 release_key(VK_CONTROL
);
6833 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6834 ok(numerator
== 394, "incorrect numerator is %d\n", numerator
);
6835 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6836 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6838 /* Test bounds checking on EM_SETZOOM */
6839 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 2, 127);
6840 ok(ret
== TRUE
, "EM_SETZOOM rejected valid values (%d).\n", ret
);
6842 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 127, 2);
6843 ok(ret
== TRUE
, "EM_SETZOOM rejected valid values (%d).\n", ret
);
6845 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 2, 128);
6846 ok(ret
== FALSE
, "EM_SETZOOM accepted invalid values (%d).\n", ret
);
6848 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6849 ok(numerator
== 127, "incorrect numerator is %d\n", numerator
);
6850 ok(denominator
== 2, "incorrect denominator is %d\n", denominator
);
6851 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6853 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 128, 2);
6854 ok(ret
== FALSE
, "EM_SETZOOM accepted invalid values (%d).\n", ret
);
6856 /* See if negative numbers are accepted. */
6857 ret
= SendMessageA(hwnd
, EM_SETZOOM
, -100, -100);
6858 ok(ret
== FALSE
, "EM_SETZOOM accepted invalid values (%d).\n", ret
);
6860 /* See if negative numbers are accepted. */
6861 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 0, 100);
6862 ok(ret
== FALSE
, "EM_SETZOOM failed (%d).\n", ret
);
6864 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6865 ok(numerator
== 127, "incorrect numerator is %d\n", numerator
);
6866 ok(denominator
== 2, "incorrect denominator is %d\n", denominator
);
6867 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6869 /* Reset the zoom value */
6870 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 0, 0);
6871 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6873 DestroyWindow(hwnd
);
6876 struct dialog_mode_messages
6878 int wm_getdefid
, wm_close
, wm_nextdlgctl
;
6881 static struct dialog_mode_messages dm_messages
;
6883 #define test_dm_messages(wmclose, wmgetdefid, wmnextdlgctl) \
6884 ok(dm_messages.wm_close == wmclose, "expected %d WM_CLOSE message, " \
6885 "got %d\n", wmclose, dm_messages.wm_close); \
6886 ok(dm_messages.wm_getdefid == wmgetdefid, "expected %d WM_GETDIFID message, " \
6887 "got %d\n", wmgetdefid, dm_messages.wm_getdefid);\
6888 ok(dm_messages.wm_nextdlgctl == wmnextdlgctl, "expected %d WM_NEXTDLGCTL message, " \
6889 "got %d\n", wmnextdlgctl, dm_messages.wm_nextdlgctl)
6891 static LRESULT CALLBACK
dialog_mode_wnd_proc(HWND hwnd
, UINT iMsg
, WPARAM wParam
, LPARAM lParam
)
6896 dm_messages
.wm_getdefid
++;
6897 return MAKELONG(ID_RICHEDITTESTDBUTTON
, DC_HASDEFID
);
6899 dm_messages
.wm_nextdlgctl
++;
6902 dm_messages
.wm_close
++;
6906 return DefWindowProcA(hwnd
, iMsg
, wParam
, lParam
);
6909 static void test_dialogmode(void)
6911 HWND hwRichEdit
, hwParent
, hwButton
;
6917 cls
.lpfnWndProc
= dialog_mode_wnd_proc
;
6920 cls
.hInstance
= GetModuleHandleA(0);
6922 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
6923 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
6924 cls
.lpszMenuName
= NULL
;
6925 cls
.lpszClassName
= "DialogModeParentClass";
6926 if(!RegisterClassA(&cls
)) assert(0);
6928 hwParent
= CreateWindowA("DialogModeParentClass", NULL
, WS_OVERLAPPEDWINDOW
,
6929 CW_USEDEFAULT
, 0, 200, 120, NULL
, NULL
, GetModuleHandleA(0), NULL
);
6931 /* Test richedit(ES_MULTILINE) */
6933 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, hwParent
);
6935 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6936 ok(0 == r
, "expected 0, got %d\n", r
);
6937 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
6938 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
6940 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, 0);
6941 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
6943 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6944 ok(0 == r
, "expected 0, got %d\n", r
);
6945 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
6946 ok(3 == lcount
, "expected 3, got %d\n", lcount
);
6948 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
6949 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
6950 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6951 ok(0 == r
, "expected 0, got %d\n", r
);
6952 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
6953 ok(3 == lcount
, "expected 3, got %d\n", lcount
);
6955 DestroyWindow(hwRichEdit
);
6957 /* Test standalone richedit(ES_MULTILINE) */
6959 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, NULL
);
6961 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6962 ok(0 == r
, "expected 0, got %d\n", r
);
6963 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
6964 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
6966 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
6967 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
6969 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6970 ok(0 == r
, "expected 0, got %d\n", r
);
6971 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
6972 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
6974 DestroyWindow(hwRichEdit
);
6976 /* Check a destination for messages */
6978 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, hwParent
);
6980 SetWindowLongA(hwRichEdit
, GWL_STYLE
, GetWindowLongA(hwRichEdit
, GWL_STYLE
)& ~WS_POPUP
);
6981 SetParent( hwRichEdit
, NULL
);
6983 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
6984 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
6986 memset(&dm_messages
, 0, sizeof(dm_messages
));
6987 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6988 ok(0 == r
, "expected 0, got %d\n", r
);
6989 test_dm_messages(0, 1, 0);
6991 memset(&dm_messages
, 0, sizeof(dm_messages
));
6992 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
6993 ok(0 == r
, "expected 0, got %d\n", r
);
6994 test_dm_messages(0, 0, 1);
6996 DestroyWindow(hwRichEdit
);
6998 /* Check messages from richedit(ES_MULTILINE) */
7000 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, hwParent
);
7002 memset(&dm_messages
, 0, sizeof(dm_messages
));
7003 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7004 ok(0 == r
, "expected 0, got %d\n", r
);
7005 test_dm_messages(0, 0, 0);
7007 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7008 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7010 memset(&dm_messages
, 0, sizeof(dm_messages
));
7011 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7012 ok(0 == r
, "expected 0, got %d\n", r
);
7013 test_dm_messages(0, 0, 0);
7015 memset(&dm_messages
, 0, sizeof(dm_messages
));
7016 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7017 ok(0 == r
, "expected 0, got %d\n", r
);
7018 test_dm_messages(0, 0, 0);
7020 memset(&dm_messages
, 0, sizeof(dm_messages
));
7021 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7022 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
7023 test_dm_messages(0, 0, 0);
7025 memset(&dm_messages
, 0, sizeof(dm_messages
));
7026 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7027 ok(0 == r
, "expected 0, got %d\n", r
);
7028 test_dm_messages(0, 1, 0);
7030 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7031 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7033 memset(&dm_messages
, 0, sizeof(dm_messages
));
7034 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7035 ok(0 == r
, "expected 0, got %d\n", r
);
7036 test_dm_messages(0, 0, 0);
7038 memset(&dm_messages
, 0, sizeof(dm_messages
));
7039 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7040 ok(0 == r
, "expected 0, got %d\n", r
);
7041 test_dm_messages(0, 0, 1);
7043 hwButton
= CreateWindowA("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
7044 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
7045 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
7047 memset(&dm_messages
, 0, sizeof(dm_messages
));
7048 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7049 ok(0 == r
, "expected 0, got %d\n", r
);
7050 test_dm_messages(0, 1, 1);
7052 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7053 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7055 DestroyWindow(hwButton
);
7056 DestroyWindow(hwRichEdit
);
7058 /* Check messages from richedit(ES_MULTILINE|ES_WANTRETURN) */
7060 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
|ES_WANTRETURN
, hwParent
);
7062 memset(&dm_messages
, 0, sizeof(dm_messages
));
7063 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7064 ok(0 == r
, "expected 0, got %d\n", r
);
7065 test_dm_messages(0, 0, 0);
7067 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7068 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7070 memset(&dm_messages
, 0, sizeof(dm_messages
));
7071 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7072 ok(0 == r
, "expected 0, got %d\n", r
);
7073 test_dm_messages(0, 0, 0);
7075 memset(&dm_messages
, 0, sizeof(dm_messages
));
7076 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7077 ok(0 == r
, "expected 0, got %d\n", r
);
7078 test_dm_messages(0, 0, 0);
7080 memset(&dm_messages
, 0, sizeof(dm_messages
));
7081 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7082 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
7083 test_dm_messages(0, 0, 0);
7085 memset(&dm_messages
, 0, sizeof(dm_messages
));
7086 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7087 ok(0 == r
, "expected 0, got %d\n", r
);
7088 test_dm_messages(0, 0, 0);
7090 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7091 ok(3 == lcount
, "expected 3, got %d\n", lcount
);
7093 memset(&dm_messages
, 0, sizeof(dm_messages
));
7094 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7095 ok(0 == r
, "expected 0, got %d\n", r
);
7096 test_dm_messages(0, 0, 0);
7098 memset(&dm_messages
, 0, sizeof(dm_messages
));
7099 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7100 ok(0 == r
, "expected 0, got %d\n", r
);
7101 test_dm_messages(0, 0, 1);
7103 hwButton
= CreateWindowA("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
7104 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
7105 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
7107 memset(&dm_messages
, 0, sizeof(dm_messages
));
7108 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7109 ok(0 == r
, "expected 0, got %d\n", r
);
7110 test_dm_messages(0, 0, 0);
7112 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7113 ok(4 == lcount
, "expected 4, got %d\n", lcount
);
7115 DestroyWindow(hwButton
);
7116 DestroyWindow(hwRichEdit
);
7118 /* Check messages from richedit(0) */
7120 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, 0, hwParent
);
7122 memset(&dm_messages
, 0, sizeof(dm_messages
));
7123 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7124 ok(0 == r
, "expected 0, got %d\n", r
);
7125 test_dm_messages(0, 0, 0);
7127 memset(&dm_messages
, 0, sizeof(dm_messages
));
7128 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7129 ok(0 == r
, "expected 0, got %d\n", r
);
7130 test_dm_messages(0, 0, 0);
7132 memset(&dm_messages
, 0, sizeof(dm_messages
));
7133 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7134 ok(0 == r
, "expected 0, got %d\n", r
);
7135 test_dm_messages(0, 0, 0);
7137 memset(&dm_messages
, 0, sizeof(dm_messages
));
7138 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7139 ok(0x8b == r
, "expected 0x8b, got 0x%x\n", r
);
7140 test_dm_messages(0, 0, 0);
7142 memset(&dm_messages
, 0, sizeof(dm_messages
));
7143 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7144 ok(0 == r
, "expected 0, got %d\n", r
);
7145 test_dm_messages(0, 1, 0);
7147 memset(&dm_messages
, 0, sizeof(dm_messages
));
7148 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7149 ok(0 == r
, "expected 0, got %d\n", r
);
7150 test_dm_messages(0, 0, 0);
7152 memset(&dm_messages
, 0, sizeof(dm_messages
));
7153 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7154 ok(0 == r
, "expected 0, got %d\n", r
);
7155 test_dm_messages(0, 0, 1);
7157 hwButton
= CreateWindowA("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
7158 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
7159 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
7161 memset(&dm_messages
, 0, sizeof(dm_messages
));
7162 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7163 ok(0 == r
, "expected 0, got %d\n", r
);
7164 test_dm_messages(0, 1, 1);
7166 DestroyWindow(hwRichEdit
);
7168 /* Check messages from richedit(ES_WANTRETURN) */
7170 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_WANTRETURN
, hwParent
);
7172 memset(&dm_messages
, 0, sizeof(dm_messages
));
7173 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7174 ok(0 == r
, "expected 0, got %d\n", r
);
7175 test_dm_messages(0, 0, 0);
7177 memset(&dm_messages
, 0, sizeof(dm_messages
));
7178 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7179 ok(0x8b == r
, "expected 0x8b, got 0x%x\n", r
);
7180 test_dm_messages(0, 0, 0);
7182 memset(&dm_messages
, 0, sizeof(dm_messages
));
7183 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7184 ok(0 == r
, "expected 0, got %d\n", r
);
7185 test_dm_messages(0, 0, 0);
7187 hwButton
= CreateWindowA("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
7188 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
7189 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
7191 memset(&dm_messages
, 0, sizeof(dm_messages
));
7192 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7193 ok(0 == r
, "expected 0, got %d\n", r
);
7194 test_dm_messages(0, 0, 0);
7196 DestroyWindow(hwRichEdit
);
7197 DestroyWindow(hwParent
);
7200 static void test_EM_FINDWORDBREAK_W(void)
7202 static const struct {
7204 BOOL isdelimiter
; /* expected result of WB_ISDELIMITER */
7205 } delimiter_tests
[] = {
7206 {0x0a, FALSE
}, /* newline */
7207 {0x0b, FALSE
}, /* vertical tab */
7208 {0x0c, FALSE
}, /* form feed */
7209 {0x0d, FALSE
}, /* carriage return */
7210 {0x20, TRUE
}, /* space */
7211 {0x61, FALSE
}, /* capital letter a */
7212 {0xa0, FALSE
}, /* no-break space */
7213 {0x2000, FALSE
}, /* en quad */
7214 {0x3000, FALSE
}, /* Ideographic space */
7215 {0x1100, FALSE
}, /* Hangul Choseong Kiyeok (G sound) Ordinary Letter*/
7216 {0x11ff, FALSE
}, /* Hangul Jongseoung Kiyeok-Hieuh (Hard N sound) Ordinary Letter*/
7217 {0x115f, FALSE
}, /* Hangul Choseong Filler (no sound, used with two letter Hangul words) Ordinary Letter */
7218 {0xac00, FALSE
}, /* Hangul character GA*/
7219 {0xd7af, FALSE
}, /* End of Hangul character chart */
7220 {0xf020, TRUE
}, /* MS private for CP_SYMBOL round trip?, see kb897872 */
7221 {0xff20, FALSE
}, /* fullwidth commercial @ */
7222 {WCH_EMBEDDING
, FALSE
}, /* object replacement character*/
7225 HWND hwndRichEdit
= new_richeditW(NULL
);
7226 ok(IsWindowUnicode(hwndRichEdit
), "window should be unicode\n");
7227 for (i
= 0; i
< sizeof(delimiter_tests
)/sizeof(delimiter_tests
[0]); i
++)
7232 wbuf
[0] = delimiter_tests
[i
].c
;
7234 SendMessageW(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)wbuf
);
7235 result
= SendMessageW(hwndRichEdit
, EM_FINDWORDBREAK
, WB_ISDELIMITER
,0);
7236 if (wbuf
[0] == 0x20 || wbuf
[0] == 0xf020)
7238 ok(result
== delimiter_tests
[i
].isdelimiter
,
7239 "wanted ISDELIMITER_W(0x%x) %d, got %d\n",
7240 delimiter_tests
[i
].c
, delimiter_tests
[i
].isdelimiter
,result
);
7242 ok(result
== delimiter_tests
[i
].isdelimiter
,
7243 "wanted ISDELIMITER_W(0x%x) %d, got %d\n",
7244 delimiter_tests
[i
].c
, delimiter_tests
[i
].isdelimiter
, result
);
7246 DestroyWindow(hwndRichEdit
);
7249 static void test_EM_FINDWORDBREAK_A(void)
7251 static const struct {
7253 BOOL isdelimiter
; /* expected result of WB_ISDELIMITER */
7254 } delimiter_tests
[] = {
7255 {0x0a, FALSE
}, /* newline */
7256 {0x0b, FALSE
}, /* vertical tab */
7257 {0x0c, FALSE
}, /* form feed */
7258 {0x0d, FALSE
}, /* carriage return */
7259 {0x20, TRUE
}, /* space */
7260 {0x61, FALSE
}, /* capital letter a */
7263 HWND hwndRichEdit
= new_richedit(NULL
);
7265 ok(!IsWindowUnicode(hwndRichEdit
), "window should not be unicode\n");
7266 for (i
= 0; i
< sizeof(delimiter_tests
)/sizeof(delimiter_tests
[0]); i
++)
7270 buf
[0] = delimiter_tests
[i
].c
;
7272 SendMessageW(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buf
);
7273 result
= SendMessageA(hwndRichEdit
, EM_FINDWORDBREAK
, WB_ISDELIMITER
, 0);
7276 ok(result
== delimiter_tests
[i
].isdelimiter
,
7277 "wanted ISDELIMITER_A(0x%x) %d, got %d\n",
7278 delimiter_tests
[i
].c
, delimiter_tests
[i
].isdelimiter
,result
);
7280 ok(result
== delimiter_tests
[i
].isdelimiter
,
7281 "wanted ISDELIMITER_A(0x%x) %d, got %d\n",
7282 delimiter_tests
[i
].c
, delimiter_tests
[i
].isdelimiter
, result
);
7284 DestroyWindow(hwndRichEdit
);
7288 * This test attempts to show the effect of enter on a richedit
7289 * control v1.0 inserts CRLF whereas for higher versions it only
7290 * inserts CR. If shows that EM_GETTEXTEX with GT_USECRLF == WM_GETTEXT
7291 * and also shows that GT_USECRLF has no effect in richedit 1.0, but
7292 * does for higher. The same test is cloned in riched32 and riched20.
7294 static void test_enter(void)
7296 static const struct {
7297 const char *initialtext
;
7299 const char *expectedwmtext
;
7300 const char *expectedemtext
;
7301 const char *expectedemtextcrlf
;
7302 } testenteritems
[] = {
7303 { "aaabbb\r\n", 3, "aaa\r\nbbb\r\n", "aaa\rbbb\r", "aaa\r\nbbb\r\n"},
7304 { "aaabbb\r\n", 6, "aaabbb\r\n\r\n", "aaabbb\r\r", "aaabbb\r\n\r\n"},
7305 { "aa\rabbb\r\n", 7, "aa\r\nabbb\r\n\r\n", "aa\rabbb\r\r", "aa\r\nabbb\r\n\r\n"},
7306 { "aa\rabbb\r\n", 3, "aa\r\n\r\nabbb\r\n", "aa\r\rabbb\r", "aa\r\n\r\nabbb\r\n"},
7307 { "aa\rabbb\r\n", 2, "aa\r\n\r\nabbb\r\n", "aa\r\rabbb\r", "aa\r\n\r\nabbb\r\n"}
7310 char expectedbuf
[1024];
7311 char resultbuf
[1024];
7312 HWND hwndRichEdit
= new_richedit(NULL
);
7315 for (i
= 0; i
< sizeof(testenteritems
)/sizeof(testenteritems
[0]); i
++) {
7317 char buf
[1024] = {0};
7320 const char *expected
;
7322 /* Set the text to the initial text */
7323 result
= SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)testenteritems
[i
].initialtext
);
7324 ok (result
== 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i
, result
);
7327 SendMessageA(hwndRichEdit
, EM_SETSEL
, testenteritems
[i
].cursor
, testenteritems
[i
].cursor
);
7328 simulate_typing_characters(hwndRichEdit
, "\r");
7330 /* 1. Retrieve with WM_GETTEXT */
7332 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buf
);
7333 expected
= testenteritems
[i
].expectedwmtext
;
7336 for (j
= 0; j
< (UINT
)result
; j
++)
7337 sprintf(resultbuf
+strlen(resultbuf
), "%02x", buf
[j
] & 0xFF);
7338 expectedbuf
[0] = '\0';
7339 for (j
= 0; j
< strlen(expected
); j
++)
7340 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", expected
[j
] & 0xFF);
7342 result
= strcmp(expected
, buf
);
7344 "[%d] WM_GETTEXT unexpected '%s' expected '%s'\n",
7345 i
, resultbuf
, expectedbuf
);
7347 /* 2. Retrieve with EM_GETTEXTEX, GT_DEFAULT */
7348 getText
.cb
= sizeof(buf
);
7349 getText
.flags
= GT_DEFAULT
;
7350 getText
.codepage
= CP_ACP
;
7351 getText
.lpDefaultChar
= NULL
;
7352 getText
.lpUsedDefChar
= NULL
;
7354 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
7355 expected
= testenteritems
[i
].expectedemtext
;
7358 for (j
= 0; j
< (UINT
)result
; j
++)
7359 sprintf(resultbuf
+strlen(resultbuf
), "%02x", buf
[j
] & 0xFF);
7360 expectedbuf
[0] = '\0';
7361 for (j
= 0; j
< strlen(expected
); j
++)
7362 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", expected
[j
] & 0xFF);
7364 result
= strcmp(expected
, buf
);
7366 "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n",
7367 i
, resultbuf
, expectedbuf
);
7369 /* 3. Retrieve with EM_GETTEXTEX, GT_USECRLF */
7370 getText
.cb
= sizeof(buf
);
7371 getText
.flags
= GT_USECRLF
;
7372 getText
.codepage
= CP_ACP
;
7373 getText
.lpDefaultChar
= NULL
;
7374 getText
.lpUsedDefChar
= NULL
;
7376 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
7377 expected
= testenteritems
[i
].expectedemtextcrlf
;
7380 for (j
= 0; j
< (UINT
)result
; j
++)
7381 sprintf(resultbuf
+strlen(resultbuf
), "%02x", buf
[j
] & 0xFF);
7382 expectedbuf
[0] = '\0';
7383 for (j
= 0; j
< strlen(expected
); j
++)
7384 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", expected
[j
] & 0xFF);
7386 result
= strcmp(expected
, buf
);
7388 "[%d] EM_GETTEXTEX, GT_USECRLF unexpected '%s', expected '%s'\n",
7389 i
, resultbuf
, expectedbuf
);
7392 DestroyWindow(hwndRichEdit
);
7395 static void test_WM_CREATE(void)
7397 static const WCHAR titleW
[] = {'l','i','n','e','1','\n','l','i','n','e','2',0};
7398 static const char title
[] = "line1\nline2";
7405 rich_edit
= CreateWindowA(RICHEDIT_CLASS20A
, title
, WS_POPUP
|WS_VISIBLE
,
7406 0, 0, 200, 80, NULL
, NULL
, NULL
, NULL
);
7407 ok(rich_edit
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7409 len
= GetWindowTextA(rich_edit
, buf
, sizeof(buf
));
7410 ok(len
== 5, "GetWindowText returned %d\n", len
);
7411 ok(!strcmp(buf
, "line1"), "buf = %s\n", buf
);
7413 res
= SendMessageA(rich_edit
, EM_GETSEL
, 0, 0);
7414 ok(res
== 0, "SendMessage(EM_GETSEL) returned %lx\n", res
);
7416 DestroyWindow(rich_edit
);
7418 rich_edit
= CreateWindowW(RICHEDIT_CLASS20W
, titleW
, WS_POPUP
|WS_VISIBLE
|ES_MULTILINE
,
7419 0, 0, 200, 80, NULL
, NULL
, NULL
, NULL
);
7420 ok(rich_edit
!= NULL
, "class: %s, error: %d\n", wine_dbgstr_w(RICHEDIT_CLASS20W
), (int) GetLastError());
7422 len
= GetWindowTextA(rich_edit
, buf
, sizeof(buf
));
7423 ok(len
== 12, "GetWindowText returned %d\n", len
);
7424 ok(!strcmp(buf
, "line1\r\nline2"), "buf = %s\n", buf
);
7426 res
= SendMessageA(rich_edit
, EM_GETSEL
, 0, 0);
7427 ok(res
== 0, "SendMessage(EM_GETSEL) returned %lx\n", res
);
7429 DestroyWindow(rich_edit
);
7432 START_TEST( editor
)
7435 /* Must explicitly LoadLibrary(). The test has no references to functions in
7436 * RICHED20.DLL, so the linker doesn't actually link to it. */
7437 hmoduleRichEdit
= LoadLibraryA("riched20.dll");
7438 ok(hmoduleRichEdit
!= NULL
, "error: %d\n", (int) GetLastError());
7441 test_EM_FINDTEXT(FALSE
);
7442 test_EM_FINDTEXT(TRUE
);
7444 test_EM_POSFROMCHAR();
7445 test_EM_SCROLLCARET();
7447 test_scrollbar_visibility();
7449 test_EM_LINELENGTH();
7450 test_EM_SETCHARFORMAT();
7451 test_EM_SETTEXTMODE();
7452 test_TM_PLAINTEXT();
7453 test_EM_SETOPTIONS();
7455 test_EM_GETTEXTRANGE();
7456 test_EM_GETSELTEXT();
7457 test_EM_SETUNDOLIMIT();
7459 test_EM_SETTEXTEX();
7460 test_EM_LIMITTEXT();
7461 test_EM_EXLIMITTEXT();
7462 test_EM_GETLIMITTEXT();
7464 test_EM_GETMODIFY();
7468 test_EM_STREAMOUT();
7469 test_EM_STREAMOUT_FONTTBL();
7470 test_EM_StreamIn_Undo();
7471 test_EM_FORMATRANGE();
7472 test_unicode_conversions();
7473 test_EM_GETTEXTLENGTHEX();
7474 test_EM_REPLACESEL(1);
7475 test_EM_REPLACESEL(0);
7477 test_EM_AUTOURLDETECT();
7479 test_undo_coalescing();
7480 test_word_movement();
7481 test_EM_CHARFROMPOS();
7482 test_SETPARAFORMAT();
7486 test_WM_GETDLGCODE();
7489 test_EM_FINDWORDBREAK_W();
7490 test_EM_FINDWORDBREAK_A();
7494 /* Set the environment variable WINETEST_RICHED20 to keep windows
7495 * responsive and open for 30 seconds. This is useful for debugging.
7497 if (getenv( "WINETEST_RICHED20" )) {
7498 keep_responsive(30);
7501 OleFlushClipboard();
7502 ret
= FreeLibrary(hmoduleRichEdit
);
7503 ok(ret
, "error: %d\n", (int) GetLastError());