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
34 #include <wine/test.h>
36 #define ID_RICHEDITTESTDBUTTON 0x123
38 static CHAR string1
[MAX_PATH
], string2
[MAX_PATH
], string3
[MAX_PATH
];
40 #define ok_w3(format, szString1, szString2, szString3) \
41 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
42 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
43 WideCharToMultiByte(CP_ACP, 0, szString3, -1, string3, MAX_PATH, NULL, NULL); \
44 ok(!lstrcmpW(szString3, szString1) || !lstrcmpW(szString3, szString2), \
45 format, string1, string2, string3);
47 static HMODULE hmoduleRichEdit
;
49 static HWND
new_window(LPCSTR lpClassName
, DWORD dwStyle
, HWND parent
) {
51 hwnd
= CreateWindowA(lpClassName
, NULL
, dwStyle
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
52 |WS_VISIBLE
, 0, 0, 200, 60, parent
, NULL
,
53 hmoduleRichEdit
, NULL
);
54 ok(hwnd
!= NULL
, "class: %s, error: %d\n", lpClassName
, (int) GetLastError());
58 static HWND
new_windowW(LPCWSTR lpClassName
, DWORD dwStyle
, HWND parent
) {
60 hwnd
= CreateWindowW(lpClassName
, NULL
, dwStyle
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
61 |WS_VISIBLE
, 0, 0, 200, 60, parent
, NULL
,
62 hmoduleRichEdit
, NULL
);
63 ok(hwnd
!= NULL
, "class: %s, error: %d\n", wine_dbgstr_w(lpClassName
), (int) GetLastError());
67 static HWND
new_richedit(HWND parent
) {
68 return new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, parent
);
71 static HWND
new_richeditW(HWND parent
) {
72 return new_windowW(RICHEDIT_CLASS20W
, ES_MULTILINE
, parent
);
75 /* Keeps the window reponsive for the deley_time in seconds.
76 * This is useful for debugging a test to see what is happening. */
77 static void keep_responsive(time_t delay_time
)
82 /* The message pump uses PeekMessage() to empty the queue and then
83 * sleeps for 50ms before retrying the queue. */
84 end
= time(NULL
) + delay_time
;
85 while (time(NULL
) < end
) {
86 if (PeekMessageA(&msg
, NULL
, 0, 0, PM_REMOVE
)) {
87 TranslateMessage(&msg
);
88 DispatchMessageA(&msg
);
95 static void simulate_typing_characters(HWND hwnd
, const char* szChars
)
99 while (*szChars
!= '\0') {
100 SendMessageA(hwnd
, WM_KEYDOWN
, *szChars
, 1);
101 ret
= SendMessageA(hwnd
, WM_CHAR
, *szChars
, 1);
102 ok(ret
== 0, "WM_CHAR('%c') ret=%d\n", *szChars
, ret
);
103 SendMessageA(hwnd
, WM_KEYUP
, *szChars
, 1);
108 static BOOL
hold_key(int vk
)
113 result
= GetKeyboardState(key_state
);
114 ok(result
, "GetKeyboardState failed.\n");
115 if (!result
) return FALSE
;
116 key_state
[vk
] |= 0x80;
117 result
= SetKeyboardState(key_state
);
118 ok(result
, "SetKeyboardState failed.\n");
122 static BOOL
release_key(int vk
)
127 result
= GetKeyboardState(key_state
);
128 ok(result
, "GetKeyboardState failed.\n");
129 if (!result
) return FALSE
;
130 key_state
[vk
] &= ~0x80;
131 result
= SetKeyboardState(key_state
);
132 ok(result
, "SetKeyboardState failed.\n");
136 static const char haystack
[] = "WINEWine wineWine wine WineWine";
148 static struct find_s find_tests
[] = {
149 /* Find in empty text */
150 {0, -1, "foo", FR_DOWN
, -1},
151 {0, -1, "foo", 0, -1},
152 {0, -1, "", FR_DOWN
, -1},
153 {20, 5, "foo", FR_DOWN
, -1},
154 {5, 20, "foo", FR_DOWN
, -1}
157 static struct find_s find_tests2
[] = {
159 {0, -1, "foo", FR_DOWN
| FR_MATCHCASE
, -1},
160 {5, 20, "WINE", FR_DOWN
| FR_MATCHCASE
, -1},
162 /* Subsequent finds */
163 {0, -1, "Wine", FR_DOWN
| FR_MATCHCASE
, 4},
164 {5, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 13},
165 {14, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 23},
166 {24, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 27},
169 {19, 20, "Wine", FR_MATCHCASE
, 13},
170 {10, 20, "Wine", FR_MATCHCASE
, 4},
171 {20, 10, "Wine", FR_MATCHCASE
, 13},
173 /* Case-insensitive */
174 {1, 31, "wInE", FR_DOWN
, 4},
175 {1, 31, "Wine", FR_DOWN
, 4},
177 /* High-to-low ranges */
178 {20, 5, "Wine", FR_DOWN
, -1},
179 {2, 1, "Wine", FR_DOWN
, -1},
180 {30, 29, "Wine", FR_DOWN
, -1},
181 {20, 5, "Wine", 0, 13},
184 {5, 10, "", FR_DOWN
, -1},
185 {10, 5, "", FR_DOWN
, -1},
186 {0, -1, "", FR_DOWN
, -1},
189 /* Whole-word search */
190 {0, -1, "wine", FR_DOWN
| FR_WHOLEWORD
, 18},
191 {0, -1, "win", FR_DOWN
| FR_WHOLEWORD
, -1},
192 {13, -1, "wine", FR_DOWN
| FR_WHOLEWORD
, 18},
193 {0, -1, "winewine", FR_DOWN
| FR_WHOLEWORD
, 0},
194 {10, -1, "winewine", FR_DOWN
| FR_WHOLEWORD
, 23},
195 {11, -1, "winewine", FR_WHOLEWORD
, 0},
196 {31, -1, "winewine", FR_WHOLEWORD
, 23},
199 {5, 200, "XXX", FR_DOWN
, -1},
200 {-20, 20, "Wine", FR_DOWN
, -1},
201 {-20, 20, "Wine", FR_DOWN
, -1},
202 {-15, -20, "Wine", FR_DOWN
, -1},
203 {1<<12, 1<<13, "Wine", FR_DOWN
, -1},
205 /* Check the case noted in bug 4479 where matches at end aren't recognized */
206 {23, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 23},
207 {27, 31, "Wine", FR_DOWN
| FR_MATCHCASE
, 27},
208 {27, 32, "Wine", FR_DOWN
| FR_MATCHCASE
, 27},
209 {13, 31, "WineWine", FR_DOWN
| FR_MATCHCASE
, 23},
210 {13, 32, "WineWine", FR_DOWN
| FR_MATCHCASE
, 23},
212 /* The backwards case of bug 4479; bounds look right
213 * Fails because backward find is wrong */
214 {19, 20, "WINE", FR_MATCHCASE
, 0},
215 {0, 20, "WINE", FR_MATCHCASE
, -1},
217 {0, -1, "wineWine wine", 0, -1},
220 static WCHAR
*atowstr(const char *str
)
224 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
225 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
226 MultiByteToWideChar(CP_ACP
, 0, str
, -1, ret
, len
);
230 static void check_EM_FINDTEXT(HWND hwnd
, const char *name
, struct find_s
*f
, int id
, BOOL unicode
)
236 memset(&ftw
, 0, sizeof(ftw
));
237 ftw
.chrg
.cpMin
= f
->start
;
238 ftw
.chrg
.cpMax
= f
->end
;
239 ftw
.lpstrText
= atowstr(f
->needle
);
241 findloc
= SendMessageA(hwnd
, EM_FINDTEXT
, f
->flags
, (LPARAM
)&ftw
);
242 ok(findloc
== f
->expected_loc
,
243 "EM_FINDTEXT(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
244 name
, id
, unicode
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
, f
->expected_loc
);
246 findloc
= SendMessageA(hwnd
, EM_FINDTEXTW
, f
->flags
, (LPARAM
)&ftw
);
247 ok(findloc
== f
->expected_loc
,
248 "EM_FINDTEXTW(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
249 name
, id
, unicode
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
, f
->expected_loc
);
251 HeapFree(GetProcessHeap(), 0, (void*)ftw
.lpstrText
);
254 memset(&fta
, 0, sizeof(fta
));
255 fta
.chrg
.cpMin
= f
->start
;
256 fta
.chrg
.cpMax
= f
->end
;
257 fta
.lpstrText
= f
->needle
;
259 findloc
= SendMessageA(hwnd
, EM_FINDTEXT
, f
->flags
, (LPARAM
)&fta
);
260 ok(findloc
== f
->expected_loc
,
261 "EM_FINDTEXT(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
262 name
, id
, unicode
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
, f
->expected_loc
);
266 static void check_EM_FINDTEXTEX(HWND hwnd
, const char *name
, struct find_s
*f
,
267 int id
, BOOL unicode
)
270 int expected_end_loc
;
274 memset(&ftw
, 0, sizeof(ftw
));
275 ftw
.chrg
.cpMin
= f
->start
;
276 ftw
.chrg
.cpMax
= f
->end
;
277 ftw
.lpstrText
= atowstr(f
->needle
);
278 findloc
= SendMessageA(hwnd
, EM_FINDTEXTEX
, f
->flags
, (LPARAM
)&ftw
);
279 ok(findloc
== f
->expected_loc
,
280 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
281 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
);
282 ok(ftw
.chrgText
.cpMin
== f
->expected_loc
,
283 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
284 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, ftw
.chrgText
.cpMin
);
285 expected_end_loc
= ((f
->expected_loc
== -1) ? -1
286 : f
->expected_loc
+ strlen(f
->needle
));
287 ok(ftw
.chrgText
.cpMax
== expected_end_loc
,
288 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n",
289 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, ftw
.chrgText
.cpMax
, expected_end_loc
);
290 HeapFree(GetProcessHeap(), 0, (void*)ftw
.lpstrText
);
293 memset(&fta
, 0, sizeof(fta
));
294 fta
.chrg
.cpMin
= f
->start
;
295 fta
.chrg
.cpMax
= f
->end
;
296 fta
.lpstrText
= f
->needle
;
297 findloc
= SendMessageA(hwnd
, EM_FINDTEXTEX
, f
->flags
, (LPARAM
)&fta
);
298 ok(findloc
== f
->expected_loc
,
299 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
300 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
);
301 ok(fta
.chrgText
.cpMin
== f
->expected_loc
,
302 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
303 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, fta
.chrgText
.cpMin
);
304 expected_end_loc
= ((f
->expected_loc
== -1) ? -1
305 : f
->expected_loc
+ strlen(f
->needle
));
306 ok(fta
.chrgText
.cpMax
== expected_end_loc
,
307 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n",
308 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, fta
.chrgText
.cpMax
, expected_end_loc
);
312 static void run_tests_EM_FINDTEXT(HWND hwnd
, const char *name
, struct find_s
*find
,
313 int num_tests
, BOOL unicode
)
317 for (i
= 0; i
< num_tests
; i
++) {
318 check_EM_FINDTEXT(hwnd
, name
, &find
[i
], i
, unicode
);
319 check_EM_FINDTEXTEX(hwnd
, name
, &find
[i
], i
, unicode
);
323 static void test_EM_FINDTEXT(BOOL unicode
)
329 hwndRichEdit
= new_richeditW(NULL
);
331 hwndRichEdit
= new_richedit(NULL
);
333 /* Empty rich edit control */
334 run_tests_EM_FINDTEXT(hwndRichEdit
, "1", find_tests
,
335 sizeof(find_tests
)/sizeof(struct find_s
), unicode
);
337 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)haystack
);
340 run_tests_EM_FINDTEXT(hwndRichEdit
, "2", find_tests2
,
341 sizeof(find_tests2
)/sizeof(struct find_s
), unicode
);
343 /* Setting a format on an arbitrary range should have no effect in search
344 results. This tests correct offset reporting across runs. */
345 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
346 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
347 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
348 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
349 SendMessageA(hwndRichEdit
, EM_SETSEL
, 6, 20);
350 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
352 /* Haystack text, again */
353 run_tests_EM_FINDTEXT(hwndRichEdit
, "2-bis", find_tests2
,
354 sizeof(find_tests2
)/sizeof(struct find_s
), unicode
);
356 /* Yet another range */
357 cf2
.dwMask
= CFM_BOLD
| cf2
.dwMask
;
358 cf2
.dwEffects
= CFE_BOLD
^ cf2
.dwEffects
;
359 SendMessageA(hwndRichEdit
, EM_SETSEL
, 11, 15);
360 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
362 /* Haystack text, again */
363 run_tests_EM_FINDTEXT(hwndRichEdit
, "2-bisbis", find_tests2
,
364 sizeof(find_tests2
)/sizeof(struct find_s
), unicode
);
366 DestroyWindow(hwndRichEdit
);
369 static const struct getline_s
{
374 {0, 10, "foo bar\r"},
379 /* Buffer smaller than line length */
385 static void test_EM_GETLINE(void)
388 HWND hwndRichEdit
= new_richedit(NULL
);
389 static const int nBuf
= 1024;
390 char dest
[1024], origdest
[1024];
391 const char text
[] = "foo bar\n"
395 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
397 memset(origdest
, 0xBB, nBuf
);
398 for (i
= 0; i
< sizeof(gl
)/sizeof(struct getline_s
); i
++)
401 int expected_nCopied
= min(gl
[i
].buffer_len
, strlen(gl
[i
].text
));
402 int expected_bytes_written
= min(gl
[i
].buffer_len
, strlen(gl
[i
].text
));
403 memset(dest
, 0xBB, nBuf
);
404 *(WORD
*) dest
= gl
[i
].buffer_len
;
406 /* EM_GETLINE appends a "\r\0" to the end of the line
407 * nCopied counts up to and including the '\r' */
408 nCopied
= SendMessageA(hwndRichEdit
, EM_GETLINE
, gl
[i
].line
, (LPARAM
)dest
);
409 ok(nCopied
== expected_nCopied
, "%d: %d!=%d\n", i
, nCopied
,
411 /* two special cases since a parameter is passed via dest */
412 if (gl
[i
].buffer_len
== 0)
413 ok(!dest
[0] && !dest
[1] && !strncmp(dest
+2, origdest
+2, nBuf
-2),
415 else if (gl
[i
].buffer_len
== 1)
416 ok(dest
[0] == gl
[i
].text
[0] && !dest
[1] &&
417 !strncmp(dest
+2, origdest
+2, nBuf
-2), "buffer_len=1\n");
420 /* Prepare hex strings of buffers to dump on failure. */
421 char expectedbuf
[1024];
422 char resultbuf
[1024];
425 for (j
= 0; j
< 32; j
++)
426 sprintf(resultbuf
+strlen(resultbuf
), "%02x", dest
[j
] & 0xFF);
427 expectedbuf
[0] = '\0';
428 for (j
= 0; j
< expected_bytes_written
; j
++) /* Written bytes */
429 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", gl
[i
].text
[j
] & 0xFF);
430 for (; j
< gl
[i
].buffer_len
; j
++) /* Ignored bytes */
431 sprintf(expectedbuf
+strlen(expectedbuf
), "??");
432 for (; j
< 32; j
++) /* Bytes after declared buffer size */
433 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", origdest
[j
] & 0xFF);
435 /* Test the part of the buffer that is expected to be written according
436 * to the MSDN documentation fo EM_GETLINE, which does not state that
437 * a NULL terminating character will be added unless no text is copied.
439 * Windows NT does not append a NULL terminating character, but
440 * Windows 2000 and up do append a NULL terminating character if there
441 * is space in the buffer. The test will ignore this difference. */
442 ok(!strncmp(dest
, gl
[i
].text
, expected_bytes_written
),
443 "%d: expected_bytes_written=%d\n" "expected=0x%s\n" "but got= 0x%s\n",
444 i
, expected_bytes_written
, expectedbuf
, resultbuf
);
445 /* Test the part of the buffer after the declared length to make sure
446 * there are no buffer overruns. */
447 ok(!strncmp(dest
+ gl
[i
].buffer_len
, origdest
+ gl
[i
].buffer_len
,
448 nBuf
- gl
[i
].buffer_len
),
449 "%d: expected_bytes_written=%d\n" "expected=0x%s\n" "but got= 0x%s\n",
450 i
, expected_bytes_written
, expectedbuf
, resultbuf
);
454 DestroyWindow(hwndRichEdit
);
457 static void test_EM_LINELENGTH(void)
459 HWND hwndRichEdit
= new_richedit(NULL
);
465 int offset_test
[10][2] = {
480 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
482 for (i
= 0; i
< 10; i
++) {
483 result
= SendMessageA(hwndRichEdit
, EM_LINELENGTH
, offset_test
[i
][0], 0);
484 ok(result
== offset_test
[i
][1], "Length of line at offset %d is %ld, expected %d\n",
485 offset_test
[i
][0], result
, offset_test
[i
][1]);
488 DestroyWindow(hwndRichEdit
);
491 static int get_scroll_pos_y(HWND hwnd
)
494 SendMessageA(hwnd
, EM_GETSCROLLPOS
, 0, (LPARAM
)&p
);
495 ok(p
.x
!= -1 && p
.y
!= -1, "p.x:%d p.y:%d\n", p
.x
, p
.y
);
499 static void move_cursor(HWND hwnd
, LONG charindex
)
502 cr
.cpMax
= charindex
;
503 cr
.cpMin
= charindex
;
504 SendMessageA(hwnd
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
507 static void line_scroll(HWND hwnd
, int amount
)
509 SendMessageA(hwnd
, EM_LINESCROLL
, 0, amount
);
512 static void test_EM_SCROLLCARET(void)
515 const char text
[] = "aa\n"
516 "this is a long line of text that should be longer than the "
524 /* The richedit window height needs to be large enough vertically to fit in
525 * more than two lines of text, so the new_richedit function can't be used
526 * since a height of 60 was not large enough on some systems.
528 HWND hwndRichEdit
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
,
529 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
530 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
531 ok(hwndRichEdit
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
533 /* Can't verify this */
534 SendMessageA(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
536 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
538 /* Caret above visible window */
539 line_scroll(hwndRichEdit
, 3);
540 prevY
= get_scroll_pos_y(hwndRichEdit
);
541 SendMessageA(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
542 curY
= get_scroll_pos_y(hwndRichEdit
);
543 ok(prevY
!= curY
, "%d == %d\n", prevY
, curY
);
545 /* Caret below visible window */
546 move_cursor(hwndRichEdit
, sizeof(text
) - 1);
547 line_scroll(hwndRichEdit
, -3);
548 prevY
= get_scroll_pos_y(hwndRichEdit
);
549 SendMessageA(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
550 curY
= get_scroll_pos_y(hwndRichEdit
);
551 ok(prevY
!= curY
, "%d == %d\n", prevY
, curY
);
553 /* Caret in visible window */
554 move_cursor(hwndRichEdit
, sizeof(text
) - 2);
555 prevY
= get_scroll_pos_y(hwndRichEdit
);
556 SendMessageA(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
557 curY
= get_scroll_pos_y(hwndRichEdit
);
558 ok(prevY
== curY
, "%d != %d\n", prevY
, curY
);
560 /* Caret still in visible window */
561 line_scroll(hwndRichEdit
, -1);
562 prevY
= get_scroll_pos_y(hwndRichEdit
);
563 SendMessageA(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
564 curY
= get_scroll_pos_y(hwndRichEdit
);
565 ok(prevY
== curY
, "%d != %d\n", prevY
, curY
);
567 DestroyWindow(hwndRichEdit
);
570 static void test_EM_POSFROMCHAR(void)
572 HWND hwndRichEdit
= new_richedit(NULL
);
575 unsigned int height
= 0;
580 static const char text
[] = "aa\n"
581 "this is a long line of text that should be longer than the "
590 rtl
= (GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_FONTSIGNATURE
,
591 (LPSTR
) &sig
, sizeof(LOCALESIGNATURE
)) &&
592 (sig
.lsUsb
[3] & 0x08000000) != 0);
594 /* Fill the control to lines to ensure that most of them are offscreen */
595 for (i
= 0; i
< 50; i
++)
597 /* Do not modify the string; it is exactly 16 characters long. */
598 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 0);
599 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"0123456789ABCDE\n");
603 Richedit 1.0 receives a POINTL* on wParam and character offset on lParam, returns void.
604 Richedit 2.0 receives character offset on wParam, ignores lParam, returns MAKELONG(x,y)
605 Richedit 3.0 accepts either of the above API conventions.
608 /* Testing Richedit 2.0 API format */
610 /* Testing start of lines. X-offset should be constant on all cases (native is 1).
611 Since all lines are identical and drawn with the same font,
612 they should have the same height... right?
614 for (i
= 0; i
< 50; i
++)
616 /* All the lines are 16 characters long */
617 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, i
* 16, 0);
620 ok(HIWORD(result
) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result
));
621 ok(LOWORD(result
) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
622 xpos
= LOWORD(result
);
626 ok(HIWORD(result
) > 0, "EM_POSFROMCHAR reports y=%d, expected > 0\n", HIWORD(result
));
627 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
628 height
= HIWORD(result
);
632 ok(HIWORD(result
) == i
* height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), i
* height
);
633 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
637 /* Testing position at end of text */
638 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 50 * 16, 0);
639 ok(HIWORD(result
) == 50 * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), 50 * height
);
640 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
642 /* Testing position way past end of text */
643 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 55 * 16, 0);
644 ok(HIWORD(result
) == 50 * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), 50 * height
);
645 expected
= (rtl
? 8 : 1);
646 ok(LOWORD(result
) == expected
, "EM_POSFROMCHAR reports x=%d, expected %d\n", LOWORD(result
), expected
);
648 /* Testing that vertical scrolling does, in fact, have an effect on EM_POSFROMCHAR */
649 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0); /* line down */
650 for (i
= 0; i
< 50; i
++)
652 /* All the lines are 16 characters long */
653 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, i
* 16, 0);
654 ok((signed short)(HIWORD(result
)) == (i
- 1) * height
,
655 "EM_POSFROMCHAR reports y=%hd, expected %d\n",
656 (signed short)(HIWORD(result
)), (i
- 1) * height
);
657 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
660 /* Testing position at end of text */
661 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 50 * 16, 0);
662 ok(HIWORD(result
) == (50 - 1) * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), (50 - 1) * height
);
663 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
665 /* Testing position way past end of text */
666 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 55 * 16, 0);
667 ok(HIWORD(result
) == (50 - 1) * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), (50 - 1) * height
);
668 expected
= (rtl
? 8 : 1);
669 ok(LOWORD(result
) == expected
, "EM_POSFROMCHAR reports x=%d, expected %d\n", LOWORD(result
), expected
);
671 /* Testing that horizontal scrolling does, in fact, have an effect on EM_POSFROMCHAR */
672 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
673 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0); /* line up */
675 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 0, 0);
676 ok(HIWORD(result
) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result
));
677 ok(LOWORD(result
) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
678 xpos
= LOWORD(result
);
680 SendMessageA(hwndRichEdit
, WM_HSCROLL
, SB_LINERIGHT
, 0);
681 result
= SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, 0, 0);
682 ok(HIWORD(result
) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result
));
683 ok((signed short)(LOWORD(result
)) < xpos
,
684 "EM_POSFROMCHAR reports x=%hd, expected value less than %d\n",
685 (signed short)(LOWORD(result
)), xpos
);
686 SendMessageA(hwndRichEdit
, WM_HSCROLL
, SB_LINELEFT
, 0);
688 /* Test around end of text that doesn't end in a newline. */
689 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"12345678901234");
690 SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
,
691 SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0)-1);
692 ok(pt
.x
> 1, "pt.x = %d\n", pt
.x
);
694 SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
,
695 SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0));
696 ok(pt
.x
> xpos
, "pt.x = %d\n", pt
.x
);
697 xpos
= (rtl
? pt
.x
+ 7 : pt
.x
);
698 SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
,
699 SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0)+1);
700 ok(pt
.x
== xpos
, "pt.x = %d\n", pt
.x
);
702 /* Try a negative position. */
703 SendMessageA(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
, -1);
704 ok(pt
.x
== 1, "pt.x = %d\n", pt
.x
);
706 DestroyWindow(hwndRichEdit
);
709 static void test_EM_SETCHARFORMAT(void)
711 HWND hwndRichEdit
= new_richedit(NULL
);
714 int tested_effects
[] = {
730 rtl
= (GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_FONTSIGNATURE
,
731 (LPSTR
) &sig
, sizeof(LOCALESIGNATURE
)) &&
732 (sig
.lsUsb
[3] & 0x08000000) != 0);
734 /* Invalid flags, CHARFORMAT2 structure blanked out */
735 memset(&cf2
, 0, sizeof(cf2
));
736 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)0xfffffff0, (LPARAM
)&cf2
);
737 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
739 /* A valid flag, CHARFORMAT2 structure blanked out */
740 memset(&cf2
, 0, sizeof(cf2
));
741 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
742 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
744 /* A valid flag, CHARFORMAT2 structure blanked out */
745 memset(&cf2
, 0, sizeof(cf2
));
746 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2
);
747 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
749 /* A valid flag, CHARFORMAT2 structure blanked out */
750 memset(&cf2
, 0, sizeof(cf2
));
751 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_WORD
, (LPARAM
)&cf2
);
752 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
754 /* A valid flag, CHARFORMAT2 structure blanked out */
755 memset(&cf2
, 0, sizeof(cf2
));
756 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
757 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
759 /* Invalid flags, CHARFORMAT2 structure minimally filled */
760 memset(&cf2
, 0, sizeof(cf2
));
761 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
762 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)0xfffffff0, (LPARAM
)&cf2
);
763 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
764 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
765 ok(rc
== FALSE
, "Should not be able to undo here.\n");
766 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
768 /* A valid flag, CHARFORMAT2 structure minimally filled */
769 memset(&cf2
, 0, sizeof(cf2
));
770 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
771 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
772 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
773 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
774 ok(rc
== FALSE
, "Should not be able to undo here.\n");
775 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
777 /* A valid flag, CHARFORMAT2 structure minimally filled */
778 memset(&cf2
, 0, sizeof(cf2
));
779 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
780 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2
);
781 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
782 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
783 ok(rc
== FALSE
, "Should not be able to undo here.\n");
784 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
786 /* A valid flag, CHARFORMAT2 structure minimally filled */
787 memset(&cf2
, 0, sizeof(cf2
));
788 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
789 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_WORD
, (LPARAM
)&cf2
);
790 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
791 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
792 todo_wine
ok(rc
== TRUE
, "Should not be able to undo here.\n");
793 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
795 /* A valid flag, CHARFORMAT2 structure minimally filled */
796 memset(&cf2
, 0, sizeof(cf2
));
797 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
798 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
799 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
800 rc
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
801 ok(rc
== TRUE
, "Should not be able to undo here.\n");
802 SendMessageA(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
804 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
805 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
807 /* Test state of modify flag before and after valid EM_SETCHARFORMAT */
808 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
809 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
810 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
811 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
813 /* wParam==0 is default char format, does not set modify */
814 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
815 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
816 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
817 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, 0, (LPARAM
)&cf2
);
818 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
821 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
822 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
825 skip("RTL language found\n");
827 /* wParam==SCF_SELECTION sets modify if nonempty selection */
828 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
829 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
830 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
831 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
832 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
833 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
834 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
836 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
837 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
838 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
839 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
840 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
841 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
842 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
843 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
844 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
845 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
846 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
847 ok(rc
== -1, "Text not marked as modified, expected modified! (%d)\n", rc
);
849 /* wParam==SCF_ALL sets modify regardless of whether text is present */
850 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
851 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
852 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
853 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
854 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
855 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
856 ok(rc
== -1, "Text not marked as modified, expected modified! (%d)\n", rc
);
858 DestroyWindow(hwndRichEdit
);
860 /* EM_GETCHARFORMAT tests */
861 for (i
= 0; tested_effects
[i
]; i
++)
863 hwndRichEdit
= new_richedit(NULL
);
864 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
866 /* Need to set a TrueType font to get consistent CFM_BOLD results */
867 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
868 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
869 cf2
.dwMask
= CFM_FACE
|CFM_WEIGHT
;
871 strcpy(cf2
.szFaceName
, "Courier New");
872 cf2
.wWeight
= FW_DONTCARE
;
873 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
875 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
876 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
877 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 4);
878 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
879 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
880 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
882 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
883 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
884 ok((cf2
.dwEffects
& tested_effects
[i
]) == 0,
885 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
887 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
888 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
889 cf2
.dwMask
= tested_effects
[i
];
890 if (cf2
.dwMask
== CFE_SUBSCRIPT
|| cf2
.dwMask
== CFE_SUPERSCRIPT
)
891 cf2
.dwMask
= CFM_SUPERSCRIPT
;
892 cf2
.dwEffects
= tested_effects
[i
];
893 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
894 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
896 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
897 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
898 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
899 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
900 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
901 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
903 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
904 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
905 ok((cf2
.dwEffects
& tested_effects
[i
]) == tested_effects
[i
],
906 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
908 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
909 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
910 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 4);
911 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
912 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
913 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
915 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
916 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
917 ok((cf2
.dwEffects
& tested_effects
[i
]) == 0,
918 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
920 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
921 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
922 SendMessageA(hwndRichEdit
, EM_SETSEL
, 1, 3);
923 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
924 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
925 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == 0)
927 (cf2
.dwMask
& tested_effects
[i
]) == 0),
928 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i
, cf2
.dwMask
, tested_effects
[i
]);
930 DestroyWindow(hwndRichEdit
);
933 for (i
= 0; tested_effects
[i
]; i
++)
935 hwndRichEdit
= new_richedit(NULL
);
936 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
938 /* Need to set a TrueType font to get consistent CFM_BOLD results */
939 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
940 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
941 cf2
.dwMask
= CFM_FACE
|CFM_WEIGHT
;
943 strcpy(cf2
.szFaceName
, "Courier New");
944 cf2
.wWeight
= FW_DONTCARE
;
945 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
947 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
948 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
949 cf2
.dwMask
= tested_effects
[i
];
950 if (cf2
.dwMask
== CFE_SUBSCRIPT
|| cf2
.dwMask
== CFE_SUPERSCRIPT
)
951 cf2
.dwMask
= CFM_SUPERSCRIPT
;
952 cf2
.dwEffects
= tested_effects
[i
];
953 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 4);
954 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
956 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
957 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
958 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
959 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
960 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
961 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
963 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
964 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
965 ok((cf2
.dwEffects
& tested_effects
[i
]) == 0,
966 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
968 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
969 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
970 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 4);
971 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
972 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
973 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
975 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
976 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
977 ok((cf2
.dwEffects
& tested_effects
[i
]) == tested_effects
[i
],
978 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
980 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
981 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
982 SendMessageA(hwndRichEdit
, EM_SETSEL
, 1, 3);
983 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
984 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
985 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == 0)
987 (cf2
.dwMask
& tested_effects
[i
]) == 0),
988 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i
, cf2
.dwMask
, tested_effects
[i
]);
989 ok((cf2
.dwEffects
& tested_effects
[i
]) == tested_effects
[i
],
990 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x set\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
992 DestroyWindow(hwndRichEdit
);
995 /* Effects applied on an empty selection should take effect when selection is
996 replaced with text */
997 hwndRichEdit
= new_richedit(NULL
);
998 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
999 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 2); /* Empty selection */
1001 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1002 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1003 cf2
.dwMask
= CFM_BOLD
;
1004 cf2
.dwEffects
= CFE_BOLD
;
1005 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1007 /* Selection is now nonempty */
1008 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1010 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1011 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1012 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 6);
1013 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1015 ok (((cf2
.dwMask
& CFM_BOLD
) == CFM_BOLD
),
1016 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, CFM_BOLD
);
1017 ok((cf2
.dwEffects
& CFE_BOLD
) == CFE_BOLD
,
1018 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, CFE_BOLD
);
1021 /* Set two effects on an empty selection */
1022 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1023 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 2); /* Empty selection */
1025 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1026 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1027 cf2
.dwMask
= CFM_BOLD
;
1028 cf2
.dwEffects
= CFE_BOLD
;
1029 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1030 cf2
.dwMask
= CFM_ITALIC
;
1031 cf2
.dwEffects
= CFE_ITALIC
;
1032 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1034 /* Selection is now nonempty */
1035 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1037 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1038 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1039 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 6);
1040 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1042 ok (((cf2
.dwMask
& (CFM_BOLD
|CFM_ITALIC
)) == (CFM_BOLD
|CFM_ITALIC
)),
1043 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, (CFM_BOLD
|CFM_ITALIC
));
1044 ok((cf2
.dwEffects
& (CFE_BOLD
|CFE_ITALIC
)) == (CFE_BOLD
|CFE_ITALIC
),
1045 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, (CFE_BOLD
|CFE_ITALIC
));
1047 /* Setting the (empty) selection to exactly the same place as before should
1048 NOT clear the insertion style! */
1049 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1050 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 2); /* Empty selection */
1052 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1053 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1054 cf2
.dwMask
= CFM_BOLD
;
1055 cf2
.dwEffects
= CFE_BOLD
;
1056 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1058 /* Empty selection in same place, insert style should NOT be forgotten here. */
1059 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 2);
1061 /* Selection is now nonempty */
1062 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1064 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1065 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1066 SendMessageA(hwndRichEdit
, EM_SETSEL
, 2, 6);
1067 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1069 ok (((cf2
.dwMask
& CFM_BOLD
) == CFM_BOLD
),
1070 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, CFM_BOLD
);
1071 ok((cf2
.dwEffects
& CFE_BOLD
) == CFE_BOLD
,
1072 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, CFE_BOLD
);
1074 /* Ditto with EM_EXSETSEL */
1075 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1076 cr
.cpMin
= 2; cr
.cpMax
= 2;
1077 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
); /* Empty selection */
1079 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1080 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1081 cf2
.dwMask
= CFM_BOLD
;
1082 cf2
.dwEffects
= CFE_BOLD
;
1083 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1085 /* Empty selection in same place, insert style should NOT be forgotten here. */
1086 cr
.cpMin
= 2; cr
.cpMax
= 2;
1087 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
); /* Empty selection */
1089 /* Selection is now nonempty */
1090 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1092 memset(&cf2
, 0, sizeof(CHARFORMAT2A
));
1093 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1094 cr
.cpMin
= 2; cr
.cpMax
= 6;
1095 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
); /* Empty selection */
1096 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1098 ok (((cf2
.dwMask
& CFM_BOLD
) == CFM_BOLD
),
1099 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, CFM_BOLD
);
1100 ok((cf2
.dwEffects
& CFE_BOLD
) == CFE_BOLD
,
1101 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, CFE_BOLD
);
1103 DestroyWindow(hwndRichEdit
);
1106 static void test_EM_SETTEXTMODE(void)
1108 HWND hwndRichEdit
= new_richedit(NULL
);
1109 CHARFORMAT2A cf2
, cf2test
;
1113 /*Attempt to use mutually exclusive modes*/
1114 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_PLAINTEXT
|TM_RICHTEXT
, 0);
1115 ok(rc
== E_INVALIDARG
,
1116 "EM_SETTEXTMODE: using mutually exclusive mode flags - returned: %x\n", rc
);
1118 /*Test that EM_SETTEXTMODE fails if text exists within the control*/
1119 /*Insert text into the control*/
1121 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1123 /*Attempt to change the control to plain text mode*/
1124 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_PLAINTEXT
, 0);
1125 ok(rc
== E_UNEXPECTED
,
1126 "EM_SETTEXTMODE: changed text mode in control containing text - returned: %x\n", rc
);
1128 /*Test that EM_SETTEXTMODE does not allow rich edit text to be pasted.
1129 If rich text is pasted, it should have the same formatting as the rest
1130 of the text in the control*/
1132 /*Italicize the text
1133 *NOTE: If the default text was already italicized, the test will simply
1134 reverse; in other words, it will copy a regular "wine" into a plain
1135 text window that uses an italicized format*/
1136 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1137 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_DEFAULT
, (LPARAM
)&cf2
);
1139 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
1140 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
1142 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1143 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
1145 /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine;
1146 however, SCF_ALL has been implemented*/
1147 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
1148 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1150 rc
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1151 ok(rc
== -1, "Text not marked as modified, expected modified! (%d)\n", rc
);
1153 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1155 /*Select the string "wine"*/
1158 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1160 /*Copy the italicized "wine" to the clipboard*/
1161 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
1163 /*Reset the formatting to default*/
1164 cf2
.dwEffects
= CFE_ITALIC
^cf2
.dwEffects
;
1165 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
)SCF_ALL
, (LPARAM
)&cf2
);
1166 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1168 /*Clear the text in the control*/
1169 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
1171 /*Switch to Plain Text Mode*/
1172 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_PLAINTEXT
, 0);
1173 ok(rc
== 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control: returned: %d\n", rc
);
1175 /*Input "wine" again in normal format*/
1176 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1178 /*Paste the italicized "wine" into the control*/
1179 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
1181 /*Select a character from the first "wine" string*/
1184 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1186 /*Retrieve its formatting*/
1187 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2
);
1189 /*Select a character from the second "wine" string*/
1192 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1194 /*Retrieve its formatting*/
1195 cf2test
.cbSize
= sizeof(CHARFORMAT2A
);
1196 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2test
);
1198 /*Compare the two formattings*/
1199 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
1200 "two formats found in plain text mode - cf2.dwEffects: %x cf2test.dwEffects: %x\n",
1201 cf2
.dwEffects
, cf2test
.dwEffects
);
1202 /*Test TM_RICHTEXT by: switching back to Rich Text mode
1203 printing "wine" in the current format(normal)
1204 pasting "wine" from the clipboard(italicized)
1205 comparing the two formats(should differ)*/
1207 /*Attempt to switch with text in control*/
1208 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_RICHTEXT
, 0);
1209 ok(rc
!= 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc
);
1212 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
1214 /*Switch into Rich Text mode*/
1215 rc
= SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
)TM_RICHTEXT
, 0);
1216 ok(rc
== 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc
);
1218 /*Print "wine" in normal formatting into the control*/
1219 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1221 /*Paste italicized "wine" into the control*/
1222 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
1224 /*Select text from the first "wine" string*/
1227 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1229 /*Retrieve its formatting*/
1230 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2
);
1232 /*Select text from the second "wine" string*/
1235 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1237 /*Retrieve its formatting*/
1238 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
)SCF_SELECTION
, (LPARAM
)&cf2test
);
1240 /*Test that the two formattings are not the same*/
1241 todo_wine
ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
!= cf2test
.dwEffects
),
1242 "expected different formats - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1243 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
1245 DestroyWindow(hwndRichEdit
);
1248 static void test_SETPARAFORMAT(void)
1250 HWND hwndRichEdit
= new_richedit(NULL
);
1253 LONG expectedMask
= PFM_ALL2
& ~PFM_TABLEROWDELIMITER
;
1254 fmt
.cbSize
= sizeof(PARAFORMAT2
);
1255 fmt
.dwMask
= PFM_ALIGNMENT
;
1256 fmt
.wAlignment
= PFA_LEFT
;
1258 ret
= SendMessageA(hwndRichEdit
, EM_SETPARAFORMAT
, 0, (LPARAM
)&fmt
);
1259 ok(ret
!= 0, "expected non-zero got %d\n", ret
);
1261 fmt
.cbSize
= sizeof(PARAFORMAT2
);
1263 ret
= SendMessageA(hwndRichEdit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
1264 /* Ignore the PFM_TABLEROWDELIMITER bit because it changes
1265 * between richedit different native builds of riched20.dll
1266 * used on different Windows versions. */
1267 ret
&= ~PFM_TABLEROWDELIMITER
;
1268 fmt
.dwMask
&= ~PFM_TABLEROWDELIMITER
;
1270 ok(ret
== expectedMask
, "expected %x got %x\n", expectedMask
, ret
);
1271 ok(fmt
.dwMask
== expectedMask
, "expected %x got %x\n", expectedMask
, fmt
.dwMask
);
1273 DestroyWindow(hwndRichEdit
);
1276 static void test_TM_PLAINTEXT(void)
1278 /*Tests plain text properties*/
1280 HWND hwndRichEdit
= new_richedit(NULL
);
1281 CHARFORMAT2A cf2
, cf2test
;
1285 /*Switch to plain text mode*/
1287 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
1288 SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, TM_PLAINTEXT
, 0);
1290 /*Fill control with text*/
1292 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"Is Wine an emulator? No it's not");
1294 /*Select some text and bold it*/
1298 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1299 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
1300 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
1302 cf2
.dwMask
= CFM_BOLD
| cf2
.dwMask
;
1303 cf2
.dwEffects
= CFE_BOLD
^ cf2
.dwEffects
;
1305 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1306 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
1308 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_WORD
| SCF_SELECTION
, (LPARAM
)&cf2
);
1309 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
1311 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
1312 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1314 /*Get the formatting of those characters*/
1316 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1318 /*Get the formatting of some other characters*/
1319 cf2test
.cbSize
= sizeof(CHARFORMAT2A
);
1322 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1323 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2test
);
1325 /*Test that they are the same as plain text allows only one formatting*/
1327 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
1328 "two selections' formats differ - cf2.dwMask: %x, cf2test.dwMask %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1329 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
1331 /*Fill the control with a "wine" string, which when inserted will be bold*/
1333 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1335 /*Copy the bolded "wine" string*/
1339 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1340 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
1342 /*Swap back to rich text*/
1344 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
1345 SendMessageA(hwndRichEdit
, EM_SETTEXTMODE
, TM_RICHTEXT
, 0);
1347 /*Set the default formatting to bold italics*/
1349 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
1350 cf2
.dwMask
|= CFM_ITALIC
;
1351 cf2
.dwEffects
^= CFE_ITALIC
;
1352 rc
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
1353 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1355 /*Set the text in the control to "wine", which will be bold and italicized*/
1357 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1359 /*Paste the plain text "wine" string, which should take the insert
1360 formatting, which at the moment is bold italics*/
1362 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
1364 /*Select the first "wine" string and retrieve its formatting*/
1368 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1369 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1371 /*Select the second "wine" string and retrieve its formatting*/
1375 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
1376 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2test
);
1378 /*Compare the two formattings. They should be the same.*/
1380 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
1381 "Copied text retained formatting - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1382 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
1383 DestroyWindow(hwndRichEdit
);
1386 static void test_WM_GETTEXT(void)
1388 HWND hwndRichEdit
= new_richedit(NULL
);
1389 static const char text
[] = "Hello. My name is RichEdit!";
1390 static const char text2
[] = "Hello. My name is RichEdit!\r";
1391 static const char text2_after
[] = "Hello. My name is RichEdit!\r\n";
1392 char buffer
[1024] = {0};
1395 /* Baseline test with normal-sized buffer */
1396 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
1397 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1398 ok(result
== lstrlenA(buffer
),
1399 "WM_GETTEXT returned %d, expected %d\n", result
, lstrlenA(buffer
));
1400 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1401 result
= strcmp(buffer
,text
);
1403 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1405 /* Test for returned value of WM_GETTEXTLENGTH */
1406 result
= SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0);
1407 ok(result
== lstrlenA(text
),
1408 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
1409 result
, lstrlenA(text
));
1411 /* Test for behavior in overflow case */
1412 memset(buffer
, 0, 1024);
1413 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, strlen(text
), (LPARAM
)buffer
);
1415 result
== lstrlenA(text
) - 1, /* XP, win2k3 */
1416 "WM_GETTEXT returned %d, expected 0 or %d\n", result
, lstrlenA(text
) - 1);
1417 result
= strcmp(buffer
,text
);
1419 result
= strncmp(buffer
, text
, lstrlenA(text
) - 1); /* XP, win2k3 */
1421 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1423 /* Baseline test with normal-sized buffer and carriage return */
1424 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
1425 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1426 ok(result
== lstrlenA(buffer
),
1427 "WM_GETTEXT returned %d, expected %d\n", result
, lstrlenA(buffer
));
1428 result
= strcmp(buffer
,text2_after
);
1430 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1432 /* Test for returned value of WM_GETTEXTLENGTH */
1433 result
= SendMessageA(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0);
1434 ok(result
== lstrlenA(text2_after
),
1435 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
1436 result
, lstrlenA(text2_after
));
1438 /* Test for behavior of CRLF conversion in case of overflow */
1439 memset(buffer
, 0, 1024);
1440 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, strlen(text2
), (LPARAM
)buffer
);
1442 result
== lstrlenA(text2
) - 1, /* XP, win2k3 */
1443 "WM_GETTEXT returned %d, expected 0 or %d\n", result
, lstrlenA(text2
) - 1);
1444 result
= strcmp(buffer
,text2
);
1446 result
= strncmp(buffer
, text2
, lstrlenA(text2
) - 1); /* XP, win2k3 */
1448 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1450 DestroyWindow(hwndRichEdit
);
1453 static void test_EM_GETTEXTRANGE(void)
1455 HWND hwndRichEdit
= new_richedit(NULL
);
1456 const char * text1
= "foo bar\r\nfoo bar";
1457 const char * text2
= "foo bar\rfoo bar";
1458 const char * expect
= "bar\rfoo";
1459 char buffer
[1024] = {0};
1461 TEXTRANGEA textRange
;
1463 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
1465 textRange
.lpstrText
= buffer
;
1466 textRange
.chrg
.cpMin
= 4;
1467 textRange
.chrg
.cpMax
= 11;
1468 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1469 ok(result
== 7, "EM_GETTEXTRANGE returned %ld\n", result
);
1470 ok(!strcmp(expect
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1472 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
1474 textRange
.lpstrText
= buffer
;
1475 textRange
.chrg
.cpMin
= 4;
1476 textRange
.chrg
.cpMax
= 11;
1477 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1478 ok(result
== 7, "EM_GETTEXTRANGE returned %ld\n", result
);
1479 ok(!strcmp(expect
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1481 /* cpMax of text length is used instead of -1 in this case */
1482 textRange
.lpstrText
= buffer
;
1483 textRange
.chrg
.cpMin
= 0;
1484 textRange
.chrg
.cpMax
= -1;
1485 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1486 ok(result
== strlen(text2
), "EM_GETTEXTRANGE returned %ld\n", result
);
1487 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1489 /* cpMin < 0 causes no text to be copied, and 0 to be returned */
1490 textRange
.lpstrText
= buffer
;
1491 textRange
.chrg
.cpMin
= -1;
1492 textRange
.chrg
.cpMax
= 1;
1493 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1494 ok(result
== 0, "EM_GETTEXTRANGE returned %ld\n", result
);
1495 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1497 /* cpMax of -1 is not replaced with text length if cpMin != 0 */
1498 textRange
.lpstrText
= buffer
;
1499 textRange
.chrg
.cpMin
= 1;
1500 textRange
.chrg
.cpMax
= -1;
1501 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1502 ok(result
== 0, "EM_GETTEXTRANGE returned %ld\n", result
);
1503 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1505 /* no end character is copied if cpMax - cpMin < 0 */
1506 textRange
.lpstrText
= buffer
;
1507 textRange
.chrg
.cpMin
= 5;
1508 textRange
.chrg
.cpMax
= 5;
1509 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1510 ok(result
== 0, "EM_GETTEXTRANGE returned %ld\n", result
);
1511 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1513 /* cpMax of text length is used if cpMax > text length*/
1514 textRange
.lpstrText
= buffer
;
1515 textRange
.chrg
.cpMin
= 0;
1516 textRange
.chrg
.cpMax
= 1000;
1517 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1518 ok(result
== strlen(text2
), "EM_GETTEXTRANGE returned %ld\n", result
);
1519 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1521 DestroyWindow(hwndRichEdit
);
1524 static void test_EM_GETSELTEXT(void)
1526 HWND hwndRichEdit
= new_richedit(NULL
);
1527 const char * text1
= "foo bar\r\nfoo bar";
1528 const char * text2
= "foo bar\rfoo bar";
1529 const char * expect
= "bar\rfoo";
1530 char buffer
[1024] = {0};
1533 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
1535 SendMessageA(hwndRichEdit
, EM_SETSEL
, 4, 11);
1536 result
= SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, 0, (LPARAM
)buffer
);
1537 ok(result
== 7, "EM_GETTEXTRANGE returned %ld\n", result
);
1538 ok(!strcmp(expect
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1540 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
1542 SendMessageA(hwndRichEdit
, EM_SETSEL
, 4, 11);
1543 result
= SendMessageA(hwndRichEdit
, EM_GETSELTEXT
, 0, (LPARAM
)buffer
);
1544 ok(result
== 7, "EM_GETTEXTRANGE returned %ld\n", result
);
1545 ok(!strcmp(expect
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1547 DestroyWindow(hwndRichEdit
);
1550 /* FIXME: need to test unimplemented options and robustly test wparam */
1551 static void test_EM_SETOPTIONS(void)
1554 static const char text
[] = "Hello. My name is RichEdit!";
1555 char buffer
[1024] = {0};
1556 DWORD dwStyle
, options
, oldOptions
;
1557 DWORD optionStyles
= ES_AUTOVSCROLL
|ES_AUTOHSCROLL
|ES_NOHIDESEL
|
1558 ES_READONLY
|ES_WANTRETURN
|ES_SAVESEL
|
1559 ES_SELECTIONBAR
|ES_VERTICAL
;
1561 /* Test initial options. */
1562 hwndRichEdit
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, WS_POPUP
,
1563 0, 0, 200, 60, NULL
, NULL
,
1564 hmoduleRichEdit
, NULL
);
1565 ok(hwndRichEdit
!= NULL
, "class: %s, error: %d\n",
1566 RICHEDIT_CLASS20A
, (int) GetLastError());
1567 options
= SendMessageA(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1568 ok(options
== 0, "Incorrect initial options %x\n", options
);
1569 DestroyWindow(hwndRichEdit
);
1571 hwndRichEdit
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
,
1572 WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
1573 0, 0, 200, 60, NULL
, NULL
,
1574 hmoduleRichEdit
, NULL
);
1575 ok(hwndRichEdit
!= NULL
, "class: %s, error: %d\n",
1576 RICHEDIT_CLASS20A
, (int) GetLastError());
1577 options
= SendMessageA(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1578 /* WS_[VH]SCROLL cause the ECO_AUTO[VH]SCROLL options to be set */
1579 ok(options
== (ECO_AUTOVSCROLL
|ECO_AUTOHSCROLL
),
1580 "Incorrect initial options %x\n", options
);
1582 /* NEGATIVE TESTING - NO OPTIONS SET */
1583 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
1584 SendMessageA(hwndRichEdit
, EM_SETOPTIONS
, ECOOP_SET
, 0);
1586 /* testing no readonly by sending 'a' to the control*/
1587 SendMessageA(hwndRichEdit
, WM_CHAR
, 'a', 0x1E0001);
1588 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1590 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text
, buffer
);
1591 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
1593 /* READONLY - sending 'a' to the control */
1594 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
1595 SendMessageA(hwndRichEdit
, EM_SETOPTIONS
, ECOOP_SET
, ECO_READONLY
);
1596 SendMessageA(hwndRichEdit
, WM_CHAR
, 'a', 0x1E0001);
1597 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1598 ok(buffer
[0]==text
[0],
1599 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text
, buffer
);
1601 /* EM_SETOPTIONS changes the window style, but changing the
1602 * window style does not change the options. */
1603 dwStyle
= GetWindowLongA(hwndRichEdit
, GWL_STYLE
);
1604 ok(dwStyle
& ES_READONLY
, "Readonly style not set by EM_SETOPTIONS\n");
1605 SetWindowLongA(hwndRichEdit
, GWL_STYLE
, dwStyle
& ~ES_READONLY
);
1606 options
= SendMessageA(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1607 ok(options
& ES_READONLY
, "Readonly option set by SetWindowLong\n");
1608 /* Confirm that the text is still read only. */
1609 SendMessageA(hwndRichEdit
, WM_CHAR
, 'a', ('a' << 16) | 0x0001);
1610 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
1611 ok(buffer
[0]==text
[0],
1612 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text
, buffer
);
1614 oldOptions
= options
;
1615 SetWindowLongA(hwndRichEdit
, GWL_STYLE
, dwStyle
|optionStyles
);
1616 options
= SendMessageA(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1617 ok(options
== oldOptions
,
1618 "Options set by SetWindowLong (%x -> %x)\n", oldOptions
, options
);
1620 DestroyWindow(hwndRichEdit
);
1623 static BOOL
check_CFE_LINK_selection(HWND hwnd
, int sel_start
, int sel_end
)
1625 CHARFORMAT2A text_format
;
1626 text_format
.cbSize
= sizeof(text_format
);
1627 SendMessageA(hwnd
, EM_SETSEL
, sel_start
, sel_end
);
1628 SendMessageA(hwnd
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&text_format
);
1629 return (text_format
.dwEffects
& CFE_LINK
) != 0;
1632 static void check_CFE_LINK_rcvd(HWND hwnd
, BOOL is_url
, const char * url
)
1634 BOOL link_present
= FALSE
;
1636 link_present
= check_CFE_LINK_selection(hwnd
, 0, 1);
1638 { /* control text is url; should get CFE_LINK */
1639 ok(link_present
, "URL Case: CFE_LINK not set for [%s].\n", url
);
1643 ok(!link_present
, "Non-URL Case: CFE_LINK set for [%s].\n", url
);
1647 static HWND
new_static_wnd(HWND parent
) {
1648 return new_window("Static", 0, parent
);
1651 static void test_EM_AUTOURLDETECT(void)
1653 /* DO NOT change the properties of the first two elements. To shorten the
1654 tests, all tests after WM_SETTEXT test just the first two elements -
1655 one non-URL and one URL */
1660 {"winehq.org", FALSE
},
1661 {"http://www.winehq.org", TRUE
},
1662 {"http//winehq.org", FALSE
},
1663 {"ww.winehq.org", FALSE
},
1664 {"www.winehq.org", TRUE
},
1665 {"ftp://192.168.1.1", TRUE
},
1666 {"ftp//192.168.1.1", FALSE
},
1667 {"mailto:your@email.com", TRUE
},
1668 {"prospero:prosperoserver", TRUE
},
1669 {"telnet:test", TRUE
},
1670 {"news:newserver", TRUE
},
1671 {"wais:waisserver", TRUE
}
1676 HWND hwndRichEdit
, parent
;
1678 /* All of the following should cause the URL to be detected */
1679 const char * templates_delim
[] = {
1680 "This is some text with X on it",
1681 "This is some text with (X) on it",
1682 "This is some text with X\r on it",
1683 "This is some text with ---X--- 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",
1689 "This text ends with X",
1691 "This is some text with X) on it",
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",
1697 "This is some text with (X on it",
1698 "This is some text with \rX on it",
1699 "This is some text with ---X 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",
1704 /* None of these should cause the URL to be detected */
1705 const char * templates_non_delim
[] = {
1706 "This is some text with |X| on it",
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",
1723 /* All of these cause the URL detection to be extended by one more byte,
1724 thus demonstrating that the tested character is considered as part
1726 const char * templates_xten_delim
[] = {
1727 "This is some text with X| on it",
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",
1738 parent
= new_static_wnd(NULL
);
1739 hwndRichEdit
= new_richedit(parent
);
1740 /* Try and pass EM_AUTOURLDETECT some test wParam values */
1741 urlRet
=SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, FALSE
, 0);
1742 ok(urlRet
==0, "Good wParam: urlRet is: %d\n", urlRet
);
1743 urlRet
=SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, 1, 0);
1744 ok(urlRet
==0, "Good wParam2: urlRet is: %d\n", urlRet
);
1745 /* Windows returns -2147024809 (0x80070057) on bad wParam values */
1746 urlRet
=SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, 8, 0);
1747 ok(urlRet
==E_INVALIDARG
, "Bad wParam: urlRet is: %d\n", urlRet
);
1748 urlRet
=SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, (WPARAM
)"h", (LPARAM
)"h");
1749 ok(urlRet
==E_INVALIDARG
, "Bad wParam2: urlRet is: %d\n", urlRet
);
1750 /* for each url, check the text to see if CFE_LINK effect is present */
1751 for (i
= 0; i
< sizeof(urls
)/sizeof(struct urls_s
); i
++) {
1753 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, FALSE
, 0);
1754 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)urls
[i
].text
);
1755 check_CFE_LINK_rcvd(hwndRichEdit
, FALSE
, urls
[i
].text
);
1757 /* Link detection should happen immediately upon WM_SETTEXT */
1758 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1759 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)urls
[i
].text
);
1760 check_CFE_LINK_rcvd(hwndRichEdit
, urls
[i
].is_url
, urls
[i
].text
);
1762 DestroyWindow(hwndRichEdit
);
1764 /* Test detection of URLs within normal text - WM_SETTEXT case. */
1765 for (i
= 0; i
< sizeof(urls
)/sizeof(struct urls_s
); i
++) {
1766 hwndRichEdit
= new_richedit(parent
);
1768 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
1773 at_pos
= strchr(templates_delim
[j
], 'X');
1774 at_offset
= at_pos
- templates_delim
[j
];
1775 memcpy(buffer
, templates_delim
[j
], at_offset
);
1776 buffer
[at_offset
] = '\0';
1777 strcat(buffer
, urls
[i
].text
);
1778 strcat(buffer
, templates_delim
[j
] + at_offset
+ 1);
1779 end_offset
= at_offset
+ strlen(urls
[i
].text
);
1781 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1782 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buffer
);
1784 /* This assumes no templates start with the URL itself, and that they
1785 have at least two characters before the URL text */
1786 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1787 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1788 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1789 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1790 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1791 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
1795 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1796 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
1797 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1798 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1802 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1803 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
1804 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1805 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1807 if (buffer
[end_offset
] != '\0')
1809 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1810 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
1811 if (buffer
[end_offset
+1] != '\0')
1813 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
1814 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
1819 for (j
= 0; j
< sizeof(templates_non_delim
) / sizeof(const char *); j
++) {
1824 at_pos
= strchr(templates_non_delim
[j
], 'X');
1825 at_offset
= at_pos
- templates_non_delim
[j
];
1826 memcpy(buffer
, templates_non_delim
[j
], at_offset
);
1827 buffer
[at_offset
] = '\0';
1828 strcat(buffer
, urls
[i
].text
);
1829 strcat(buffer
, templates_non_delim
[j
] + at_offset
+ 1);
1830 end_offset
= at_offset
+ strlen(urls
[i
].text
);
1832 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1833 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buffer
);
1835 /* This assumes no templates start with the URL itself, and that they
1836 have at least two characters before the URL text */
1837 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1838 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1839 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1840 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1841 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1842 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
1844 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1845 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
1846 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1847 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1848 if (buffer
[end_offset
] != '\0')
1850 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1851 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
1852 if (buffer
[end_offset
+1] != '\0')
1854 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
1855 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
1860 for (j
= 0; j
< sizeof(templates_xten_delim
) / sizeof(const char *); j
++) {
1865 at_pos
= strchr(templates_xten_delim
[j
], 'X');
1866 at_offset
= at_pos
- templates_xten_delim
[j
];
1867 memcpy(buffer
, templates_xten_delim
[j
], at_offset
);
1868 buffer
[at_offset
] = '\0';
1869 strcat(buffer
, urls
[i
].text
);
1870 strcat(buffer
, templates_xten_delim
[j
] + at_offset
+ 1);
1871 end_offset
= at_offset
+ strlen(urls
[i
].text
);
1873 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1874 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buffer
);
1876 /* This assumes no templates start with the URL itself, and that they
1877 have at least two characters before the URL text */
1878 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1879 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1880 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1881 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1882 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1883 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
1887 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1888 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
1889 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1890 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1891 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1892 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
, end_offset
+1, buffer
);
1896 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1897 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
1898 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1899 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1900 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1901 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+1, buffer
);
1903 if (buffer
[end_offset
+1] != '\0')
1905 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
1906 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+ 2, buffer
);
1907 if (buffer
[end_offset
+2] != '\0')
1909 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+2, end_offset
+3),
1910 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+2, end_offset
+3, buffer
);
1915 DestroyWindow(hwndRichEdit
);
1916 hwndRichEdit
= NULL
;
1919 /* Test detection of URLs within normal text - WM_CHAR case. */
1920 /* Test only the first two URL examples for brevity */
1921 for (i
= 0; i
< 2; i
++) {
1922 hwndRichEdit
= new_richedit(parent
);
1924 /* Also for brevity, test only the first three delimiters */
1925 for (j
= 0; j
< 3; j
++) {
1931 at_pos
= strchr(templates_delim
[j
], 'X');
1932 at_offset
= at_pos
- templates_delim
[j
];
1933 end_offset
= at_offset
+ strlen(urls
[i
].text
);
1935 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1936 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
1937 for (u
= 0; templates_delim
[j
][u
]; u
++) {
1938 if (templates_delim
[j
][u
] == '\r') {
1939 simulate_typing_characters(hwndRichEdit
, "\r");
1940 } else if (templates_delim
[j
][u
] != 'X') {
1941 SendMessageA(hwndRichEdit
, WM_CHAR
, templates_delim
[j
][u
], 1);
1943 for (v
= 0; urls
[i
].text
[v
]; v
++) {
1944 SendMessageA(hwndRichEdit
, WM_CHAR
, urls
[i
].text
[v
], 1);
1948 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
1950 /* This assumes no templates start with the URL itself, and that they
1951 have at least two characters before the URL text */
1952 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1953 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1954 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1955 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1956 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1957 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
1961 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1962 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
1963 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1964 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1968 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1969 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
1970 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1971 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1973 if (buffer
[end_offset
] != '\0')
1975 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1976 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
1977 if (buffer
[end_offset
+1] != '\0')
1979 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
1980 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
1984 /* The following will insert a paragraph break after the first character
1985 of the URL candidate, thus breaking the URL. It is expected that the
1986 CFE_LINK attribute should break across both pieces of the URL */
1987 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
+1, at_offset
+1);
1988 simulate_typing_characters(hwndRichEdit
, "\r");
1989 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
1991 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1992 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1993 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1994 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1995 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1996 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
1998 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1999 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2000 /* end_offset moved because of paragraph break */
2001 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2002 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+1, buffer
);
2003 ok(buffer
[end_offset
], "buffer \"%s\" ended prematurely. Is it missing a newline character?\n", buffer
);
2004 if (buffer
[end_offset
] != 0 && buffer
[end_offset
+1] != '\0')
2006 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2007 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2008 if (buffer
[end_offset
+2] != '\0')
2010 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+2, end_offset
+3),
2011 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+2, end_offset
+3, buffer
);
2015 /* The following will remove the just-inserted paragraph break, thus
2016 restoring the URL */
2017 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
+2, at_offset
+2);
2018 simulate_typing_characters(hwndRichEdit
, "\b");
2019 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2021 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2022 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2023 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2024 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2025 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2026 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2030 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2031 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2032 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2033 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2037 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2038 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2039 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2040 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2042 if (buffer
[end_offset
] != '\0')
2044 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2045 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2046 if (buffer
[end_offset
+1] != '\0')
2048 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2049 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2053 DestroyWindow(hwndRichEdit
);
2054 hwndRichEdit
= NULL
;
2057 /* Test detection of URLs within normal text - EM_SETTEXTEX case. */
2058 /* Test just the first two URL examples for brevity */
2059 for (i
= 0; i
< 2; i
++) {
2062 hwndRichEdit
= new_richedit(parent
);
2064 /* There are at least three ways in which EM_SETTEXTEX must cause URLs to
2066 1) Set entire text, a la WM_SETTEXT
2067 2) Set a selection of the text to the URL
2068 3) Set a portion of the text at a time, which eventually results in
2070 All of them should give equivalent results
2073 /* Set entire text in one go, like WM_SETTEXT */
2074 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2079 st
.codepage
= CP_ACP
;
2080 st
.flags
= ST_DEFAULT
;
2082 at_pos
= strchr(templates_delim
[j
], 'X');
2083 at_offset
= at_pos
- templates_delim
[j
];
2084 memcpy(buffer
, templates_delim
[j
], at_offset
);
2085 buffer
[at_offset
] = '\0';
2086 strcat(buffer
, urls
[i
].text
);
2087 strcat(buffer
, templates_delim
[j
] + at_offset
+ 1);
2088 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2090 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2091 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)buffer
);
2093 /* This assumes no templates start with the URL itself, and that they
2094 have at least two characters before the URL text */
2095 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2096 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2097 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2098 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2099 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2100 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2104 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2105 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2106 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2107 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2111 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2112 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2113 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2114 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2116 if (buffer
[end_offset
] != '\0')
2118 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2119 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2120 if (buffer
[end_offset
+1] != '\0')
2122 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2123 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2128 /* Set selection with X to the URL */
2129 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2134 at_pos
= strchr(templates_delim
[j
], 'X');
2135 at_offset
= at_pos
- templates_delim
[j
];
2136 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2138 st
.codepage
= CP_ACP
;
2139 st
.flags
= ST_DEFAULT
;
2140 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2141 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)templates_delim
[j
]);
2142 st
.flags
= ST_SELECTION
;
2143 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2144 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)urls
[i
].text
);
2145 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2147 /* This assumes no templates start with the URL itself, and that they
2148 have at least two characters before the URL text */
2149 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2150 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2151 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2152 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2153 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2154 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2158 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2159 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2160 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2161 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2165 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2166 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2167 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2168 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2170 if (buffer
[end_offset
] != '\0')
2172 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2173 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2174 if (buffer
[end_offset
+1] != '\0')
2176 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2177 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2182 /* Set selection with X to the first character of the URL, then the rest */
2183 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2188 at_pos
= strchr(templates_delim
[j
], 'X');
2189 at_offset
= at_pos
- templates_delim
[j
];
2190 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2192 strcpy(buffer
, "YY");
2193 buffer
[0] = urls
[i
].text
[0];
2195 st
.codepage
= CP_ACP
;
2196 st
.flags
= ST_DEFAULT
;
2197 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2198 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)templates_delim
[j
]);
2199 st
.flags
= ST_SELECTION
;
2200 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2201 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)buffer
);
2202 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
+1, at_offset
+2);
2203 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)(urls
[i
].text
+ 1));
2204 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2206 /* This assumes no templates start with the URL itself, and that they
2207 have at least two characters before the URL text */
2208 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2209 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2210 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2211 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2212 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2213 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2217 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2218 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2219 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2220 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2224 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2225 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2226 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2227 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2229 if (buffer
[end_offset
] != '\0')
2231 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2232 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2233 if (buffer
[end_offset
+1] != '\0')
2235 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2236 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2241 DestroyWindow(hwndRichEdit
);
2242 hwndRichEdit
= NULL
;
2245 /* Test detection of URLs within normal text - EM_REPLACESEL case. */
2246 /* Test just the first two URL examples for brevity */
2247 for (i
= 0; i
< 2; i
++) {
2248 hwndRichEdit
= new_richedit(parent
);
2250 /* Set selection with X to the URL */
2251 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2256 at_pos
= strchr(templates_delim
[j
], 'X');
2257 at_offset
= at_pos
- templates_delim
[j
];
2258 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2260 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2261 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)templates_delim
[j
]);
2262 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2263 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)urls
[i
].text
);
2264 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2266 /* This assumes no templates start with the URL itself, and that they
2267 have at least two characters before the URL text */
2268 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2269 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2270 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2271 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2272 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2273 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2277 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2278 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2279 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2280 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2284 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2285 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2286 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2287 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2289 if (buffer
[end_offset
] != '\0')
2291 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2292 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2293 if (buffer
[end_offset
+1] != '\0')
2295 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2296 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2301 /* Set selection with X to the first character of the URL, then the rest */
2302 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2307 at_pos
= strchr(templates_delim
[j
], 'X');
2308 at_offset
= at_pos
- templates_delim
[j
];
2309 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2311 strcpy(buffer
, "YY");
2312 buffer
[0] = urls
[i
].text
[0];
2314 SendMessageA(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2315 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)templates_delim
[j
]);
2316 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2317 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)buffer
);
2318 SendMessageA(hwndRichEdit
, EM_SETSEL
, at_offset
+1, at_offset
+2);
2319 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)(urls
[i
].text
+ 1));
2320 SendMessageA(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2322 /* This assumes no templates start with the URL itself, and that they
2323 have at least two characters before the URL text */
2324 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2325 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2326 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2327 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2328 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2329 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2333 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2334 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2335 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2336 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2340 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2341 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2342 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2343 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2345 if (buffer
[end_offset
] != '\0')
2347 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2348 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2349 if (buffer
[end_offset
+1] != '\0')
2351 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2352 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2357 DestroyWindow(hwndRichEdit
);
2358 hwndRichEdit
= NULL
;
2361 DestroyWindow(parent
);
2364 static void test_EM_SCROLL(void)
2367 int r
; /* return value */
2368 int expr
; /* expected return value */
2369 HWND hwndRichEdit
= new_richedit(NULL
);
2370 int y_before
, y_after
; /* units of lines of text */
2372 /* test a richedit box containing a single line of text */
2373 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");/* one line of text */
2375 for (i
= 0; i
< 4; i
++) {
2376 static const int cmd
[4] = { SB_PAGEDOWN
, SB_PAGEUP
, SB_LINEDOWN
, SB_LINEUP
};
2378 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, cmd
[i
], 0);
2379 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2380 ok(expr
== r
, "EM_SCROLL improper return value returned (i == %d). "
2381 "Got 0x%08x, expected 0x%08x\n", i
, r
, expr
);
2382 ok(y_after
== 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 "
2383 "(i == %d)\n", y_after
, i
);
2387 * test a richedit box that will scroll. There are two general
2388 * cases: the case without any long lines and the case with a long
2391 for (i
= 0; i
< 2; i
++) { /* iterate through different bodies of text */
2393 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a\nb\nc\nd\ne");
2395 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)
2396 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
2397 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
2398 "LONG LINE \nb\nc\nd\ne");
2399 for (j
= 0; j
< 12; j
++) /* reset scroll position to top */
2400 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_PAGEUP
, 0);
2402 /* get first visible line */
2403 y_before
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2404 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_PAGEDOWN
, 0); /* page down */
2406 /* get new current first visible line */
2407 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2409 ok(((r
& 0xffffff00) == 0x00010000) &&
2410 ((r
& 0x000000ff) != 0x00000000),
2411 "EM_SCROLL page down didn't scroll by a small positive number of "
2412 "lines (r == 0x%08x)\n", r
);
2413 ok(y_after
> y_before
, "EM_SCROLL page down not functioning "
2414 "(line %d scrolled to line %d\n", y_before
, y_after
);
2418 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_PAGEUP
, 0); /* page up */
2419 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2420 ok(((r
& 0xffffff00) == 0x0001ff00),
2421 "EM_SCROLL page up didn't scroll by a small negative number of lines "
2422 "(r == 0x%08x)\n", r
);
2423 ok(y_after
< y_before
, "EM_SCROLL page up not functioning (line "
2424 "%d scrolled to line %d\n", y_before
, y_after
);
2428 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0); /* line down */
2430 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2432 ok(r
== 0x00010001, "EM_SCROLL line down didn't scroll by one line "
2433 "(r == 0x%08x)\n", r
);
2434 ok(y_after
-1 == y_before
, "EM_SCROLL line down didn't go down by "
2435 "1 line (%d scrolled to %d)\n", y_before
, y_after
);
2439 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0); /* line up */
2441 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2443 ok(r
== 0x0001ffff, "EM_SCROLL line up didn't scroll by one line "
2444 "(r == 0x%08x)\n", r
);
2445 ok(y_after
+1 == y_before
, "EM_SCROLL line up didn't go up by 1 "
2446 "line (%d scrolled to %d)\n", y_before
, y_after
);
2450 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
,
2451 SB_LINEUP
, 0); /* lineup beyond top */
2453 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2456 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r
);
2457 ok(y_before
== y_after
,
2458 "EM_SCROLL line up beyond top worked (%d)\n", y_after
);
2462 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
,
2463 SB_PAGEUP
, 0);/*page up beyond top */
2465 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2468 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r
);
2469 ok(y_before
== y_after
,
2470 "EM_SCROLL page up beyond top worked (%d)\n", y_after
);
2472 for (j
= 0; j
< 12; j
++) /* page down all the way to the bottom */
2473 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_PAGEDOWN
, 0);
2474 y_before
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2475 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
,
2476 SB_PAGEDOWN
, 0); /* page down beyond bot */
2477 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2480 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r
);
2481 ok(y_before
== y_after
,
2482 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n",
2485 y_before
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2486 r
= SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0); /* line down beyond bot */
2487 y_after
= SendMessageA(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2490 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r
);
2491 ok(y_before
== y_after
,
2492 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n",
2495 DestroyWindow(hwndRichEdit
);
2498 static unsigned int recursionLevel
= 0;
2499 static unsigned int WM_SIZE_recursionLevel
= 0;
2500 static BOOL bailedOutOfRecursion
= FALSE
;
2501 static LRESULT (WINAPI
*richeditProc
)(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
);
2503 static LRESULT WINAPI
RicheditStupidOverrideProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
2507 if (bailedOutOfRecursion
) return 0;
2508 if (recursionLevel
>= 32) {
2509 bailedOutOfRecursion
= TRUE
;
2516 WM_SIZE_recursionLevel
++;
2517 r
= richeditProc(hwnd
, message
, wParam
, lParam
);
2518 /* Because, uhhhh... I never heard of ES_DISABLENOSCROLL */
2519 ShowScrollBar(hwnd
, SB_VERT
, TRUE
);
2520 WM_SIZE_recursionLevel
--;
2523 r
= richeditProc(hwnd
, message
, wParam
, lParam
);
2530 static void test_scrollbar_visibility(void)
2533 const char * text
="a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n";
2538 /* These tests show that richedit should temporarily refrain from automatically
2539 hiding or showing its scrollbars (vertical at least) when an explicit request
2540 is made via ShowScrollBar() or similar, outside of standard richedit logic.
2541 Some applications depend on forced showing (when otherwise richedit would
2542 hide the vertical scrollbar) and are thrown on an endless recursive loop
2543 if richedit auto-hides the scrollbar again. Apparently they never heard of
2544 the ES_DISABLENOSCROLL style... */
2546 hwndRichEdit
= new_richedit(NULL
);
2548 /* Test default scrollbar visibility behavior */
2549 memset(&si
, 0, sizeof(si
));
2550 si
.cbSize
= sizeof(si
);
2551 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2552 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2553 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2554 "Vertical scrollbar is visible, should be invisible.\n");
2555 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2556 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2557 si
.nPage
, si
.nMin
, si
.nMax
);
2559 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2560 memset(&si
, 0, sizeof(si
));
2561 si
.cbSize
= sizeof(si
);
2562 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2563 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2564 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2565 "Vertical scrollbar is visible, should be invisible.\n");
2566 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2567 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2568 si
.nPage
, si
.nMin
, si
.nMax
);
2570 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2571 memset(&si
, 0, sizeof(si
));
2572 si
.cbSize
= sizeof(si
);
2573 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2574 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2575 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2576 "Vertical scrollbar is invisible, should be visible.\n");
2577 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2578 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2579 si
.nPage
, si
.nMin
, si
.nMax
);
2581 /* Oddly, setting text to NULL does *not* reset the scrollbar range,
2582 even though it hides the scrollbar */
2583 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2584 memset(&si
, 0, sizeof(si
));
2585 si
.cbSize
= sizeof(si
);
2586 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2587 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2588 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2589 "Vertical scrollbar is visible, should be invisible.\n");
2590 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2591 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2592 si
.nPage
, si
.nMin
, si
.nMax
);
2594 /* Setting non-scrolling text again does *not* reset scrollbar range */
2595 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2596 memset(&si
, 0, sizeof(si
));
2597 si
.cbSize
= sizeof(si
);
2598 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2599 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2600 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2601 "Vertical scrollbar is visible, should be invisible.\n");
2602 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2603 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2604 si
.nPage
, si
.nMin
, si
.nMax
);
2606 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2607 memset(&si
, 0, sizeof(si
));
2608 si
.cbSize
= sizeof(si
);
2609 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2610 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2611 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2612 "Vertical scrollbar is visible, should be invisible.\n");
2613 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2614 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2615 si
.nPage
, si
.nMin
, si
.nMax
);
2617 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2618 memset(&si
, 0, sizeof(si
));
2619 si
.cbSize
= sizeof(si
);
2620 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2621 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2622 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2623 "Vertical scrollbar is visible, should be invisible.\n");
2624 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2625 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2626 si
.nPage
, si
.nMin
, si
.nMax
);
2628 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
2629 memset(&si
, 0, sizeof(si
));
2630 si
.cbSize
= sizeof(si
);
2631 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2632 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2633 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2634 "Vertical scrollbar is visible, should be invisible.\n");
2635 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2636 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2637 si
.nPage
, si
.nMin
, si
.nMax
);
2639 DestroyWindow(hwndRichEdit
);
2641 /* Test again, with ES_DISABLENOSCROLL style */
2642 hwndRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
|ES_DISABLENOSCROLL
, NULL
);
2644 /* Test default scrollbar visibility behavior */
2645 memset(&si
, 0, sizeof(si
));
2646 si
.cbSize
= sizeof(si
);
2647 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2648 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2649 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2650 "Vertical scrollbar is invisible, should be visible.\n");
2651 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 1,
2652 "reported page/range is %d (%d..%d) expected 0 (0..1)\n",
2653 si
.nPage
, si
.nMin
, si
.nMax
);
2655 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2656 memset(&si
, 0, sizeof(si
));
2657 si
.cbSize
= sizeof(si
);
2658 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2659 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2660 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2661 "Vertical scrollbar is invisible, should be visible.\n");
2662 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 1,
2663 "reported page/range is %d (%d..%d) expected 0 (0..1)\n",
2664 si
.nPage
, si
.nMin
, si
.nMax
);
2666 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2667 memset(&si
, 0, sizeof(si
));
2668 si
.cbSize
= sizeof(si
);
2669 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2670 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2671 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2672 "Vertical scrollbar is invisible, should be visible.\n");
2673 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2674 "reported page/range is %d (%d..%d)\n",
2675 si
.nPage
, si
.nMin
, si
.nMax
);
2677 /* Oddly, setting text to NULL does *not* reset the scrollbar range */
2678 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2679 memset(&si
, 0, sizeof(si
));
2680 si
.cbSize
= sizeof(si
);
2681 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2682 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2683 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2684 "Vertical scrollbar is invisible, should be visible.\n");
2685 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2686 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2687 si
.nPage
, si
.nMin
, si
.nMax
);
2689 /* Setting non-scrolling text again does *not* reset scrollbar range */
2690 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2691 memset(&si
, 0, sizeof(si
));
2692 si
.cbSize
= sizeof(si
);
2693 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2694 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2695 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2696 "Vertical scrollbar is invisible, should be visible.\n");
2697 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2698 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2699 si
.nPage
, si
.nMin
, si
.nMax
);
2701 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2702 memset(&si
, 0, sizeof(si
));
2703 si
.cbSize
= sizeof(si
);
2704 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2705 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2706 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2707 "Vertical scrollbar is invisible, should be visible.\n");
2708 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2709 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2710 si
.nPage
, si
.nMin
, si
.nMax
);
2712 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2713 memset(&si
, 0, sizeof(si
));
2714 si
.cbSize
= sizeof(si
);
2715 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2716 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2717 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2718 "Vertical scrollbar is invisible, should be visible.\n");
2719 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2720 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2721 si
.nPage
, si
.nMin
, si
.nMax
);
2723 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
2724 memset(&si
, 0, sizeof(si
));
2725 si
.cbSize
= sizeof(si
);
2726 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2727 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2728 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2729 "Vertical scrollbar is invisible, should be visible.\n");
2730 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2731 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2732 si
.nPage
, si
.nMin
, si
.nMax
);
2734 DestroyWindow(hwndRichEdit
);
2736 /* Test behavior with explicit visibility request, using ShowScrollBar() */
2737 hwndRichEdit
= new_richedit(NULL
);
2739 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */
2740 ShowScrollBar(hwndRichEdit
, SB_VERT
, TRUE
);
2741 memset(&si
, 0, sizeof(si
));
2742 si
.cbSize
= sizeof(si
);
2743 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2744 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2745 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2746 "Vertical scrollbar is invisible, should be visible.\n");
2748 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2749 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2750 si
.nPage
, si
.nMin
, si
.nMax
);
2753 /* Ditto, see above */
2754 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2755 memset(&si
, 0, sizeof(si
));
2756 si
.cbSize
= sizeof(si
);
2757 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2758 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2759 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2760 "Vertical scrollbar is invisible, should be visible.\n");
2762 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2763 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2764 si
.nPage
, si
.nMin
, si
.nMax
);
2767 /* Ditto, see above */
2768 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2769 memset(&si
, 0, sizeof(si
));
2770 si
.cbSize
= sizeof(si
);
2771 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2772 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2773 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2774 "Vertical scrollbar is invisible, should be visible.\n");
2776 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2777 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2778 si
.nPage
, si
.nMin
, si
.nMax
);
2781 /* Ditto, see above */
2782 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a\na");
2783 memset(&si
, 0, sizeof(si
));
2784 si
.cbSize
= sizeof(si
);
2785 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2786 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2787 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2788 "Vertical scrollbar is invisible, should be visible.\n");
2790 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2791 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2792 si
.nPage
, si
.nMin
, si
.nMax
);
2795 /* Ditto, see above */
2796 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2797 memset(&si
, 0, sizeof(si
));
2798 si
.cbSize
= sizeof(si
);
2799 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2800 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2801 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2802 "Vertical scrollbar is invisible, should be visible.\n");
2804 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2805 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2806 si
.nPage
, si
.nMin
, si
.nMax
);
2809 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2810 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2811 memset(&si
, 0, sizeof(si
));
2812 si
.cbSize
= sizeof(si
);
2813 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2814 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2815 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2816 "Vertical scrollbar is visible, should be invisible.\n");
2817 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2818 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2819 si
.nPage
, si
.nMin
, si
.nMax
);
2821 DestroyWindow(hwndRichEdit
);
2823 hwndRichEdit
= new_richedit(NULL
);
2825 ShowScrollBar(hwndRichEdit
, SB_VERT
, FALSE
);
2826 memset(&si
, 0, sizeof(si
));
2827 si
.cbSize
= sizeof(si
);
2828 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2829 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2830 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2831 "Vertical scrollbar is visible, should be invisible.\n");
2832 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2833 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2834 si
.nPage
, si
.nMin
, si
.nMax
);
2836 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2837 memset(&si
, 0, sizeof(si
));
2838 si
.cbSize
= sizeof(si
);
2839 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2840 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2841 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2842 "Vertical scrollbar is visible, should be invisible.\n");
2843 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2844 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2845 si
.nPage
, si
.nMin
, si
.nMax
);
2847 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2848 memset(&si
, 0, sizeof(si
));
2849 si
.cbSize
= sizeof(si
);
2850 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2851 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2852 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2853 "Vertical scrollbar is visible, should be invisible.\n");
2854 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2855 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2856 si
.nPage
, si
.nMin
, si
.nMax
);
2858 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2859 memset(&si
, 0, sizeof(si
));
2860 si
.cbSize
= sizeof(si
);
2861 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2862 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2863 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2864 "Vertical scrollbar is visible, should be invisible.\n");
2865 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2866 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2867 si
.nPage
, si
.nMin
, si
.nMax
);
2869 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2870 memset(&si
, 0, sizeof(si
));
2871 si
.cbSize
= sizeof(si
);
2872 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2873 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2874 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2875 "Vertical scrollbar is invisible, should be visible.\n");
2876 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2877 "reported page/range is %d (%d..%d)\n",
2878 si
.nPage
, si
.nMin
, si
.nMax
);
2880 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */
2881 ShowScrollBar(hwndRichEdit
, SB_VERT
, FALSE
);
2882 memset(&si
, 0, sizeof(si
));
2883 si
.cbSize
= sizeof(si
);
2884 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2885 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2886 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2887 "Vertical scrollbar is visible, should be invisible.\n");
2888 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2889 "reported page/range is %d (%d..%d)\n",
2890 si
.nPage
, si
.nMin
, si
.nMax
);
2892 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2893 memset(&si
, 0, sizeof(si
));
2894 si
.cbSize
= sizeof(si
);
2895 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2896 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2897 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2898 "Vertical scrollbar is visible, should be invisible.\n");
2899 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2900 "reported page/range is %d (%d..%d)\n",
2901 si
.nPage
, si
.nMin
, si
.nMax
);
2903 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that
2904 EM_SCROLL will make visible any forcefully invisible scrollbar */
2905 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0);
2906 memset(&si
, 0, sizeof(si
));
2907 si
.cbSize
= sizeof(si
);
2908 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2909 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2910 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2911 "Vertical scrollbar is invisible, should be visible.\n");
2912 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2913 "reported page/range is %d (%d..%d)\n",
2914 si
.nPage
, si
.nMin
, si
.nMax
);
2916 ShowScrollBar(hwndRichEdit
, SB_VERT
, FALSE
);
2917 memset(&si
, 0, sizeof(si
));
2918 si
.cbSize
= sizeof(si
);
2919 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2920 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2921 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2922 "Vertical scrollbar is visible, should be invisible.\n");
2923 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2924 "reported page/range is %d (%d..%d)\n",
2925 si
.nPage
, si
.nMin
, si
.nMax
);
2927 /* Again, EM_SCROLL, with SB_LINEUP */
2928 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0);
2929 memset(&si
, 0, sizeof(si
));
2930 si
.cbSize
= sizeof(si
);
2931 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2932 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2933 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2934 "Vertical scrollbar is invisible, should be visible.\n");
2935 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2936 "reported page/range is %d (%d..%d)\n",
2937 si
.nPage
, si
.nMin
, si
.nMax
);
2939 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2940 memset(&si
, 0, sizeof(si
));
2941 si
.cbSize
= sizeof(si
);
2942 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2943 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2944 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2945 "Vertical scrollbar is visible, should be invisible.\n");
2946 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2947 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2948 si
.nPage
, si
.nMin
, si
.nMax
);
2950 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2951 memset(&si
, 0, sizeof(si
));
2952 si
.cbSize
= sizeof(si
);
2953 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2954 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2955 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2956 "Vertical scrollbar is invisible, should be visible.\n");
2957 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2958 "reported page/range is %d (%d..%d)\n",
2959 si
.nPage
, si
.nMin
, si
.nMax
);
2961 DestroyWindow(hwndRichEdit
);
2964 /* Test behavior with explicit visibility request, using SetWindowLongA()() */
2965 hwndRichEdit
= new_richedit(NULL
);
2967 #define ENABLE_WS_VSCROLL(hwnd) \
2968 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) | WS_VSCROLL)
2969 #define DISABLE_WS_VSCROLL(hwnd) \
2970 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) & ~WS_VSCROLL)
2972 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */
2973 ENABLE_WS_VSCROLL(hwndRichEdit
);
2974 memset(&si
, 0, sizeof(si
));
2975 si
.cbSize
= sizeof(si
);
2976 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2977 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2978 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2979 "Vertical scrollbar is invisible, should be visible.\n");
2980 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2981 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2982 si
.nPage
, si
.nMin
, si
.nMax
);
2984 /* Ditto, see above */
2985 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2986 memset(&si
, 0, sizeof(si
));
2987 si
.cbSize
= sizeof(si
);
2988 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2989 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2990 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2991 "Vertical scrollbar is invisible, should be visible.\n");
2992 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2993 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2994 si
.nPage
, si
.nMin
, si
.nMax
);
2996 /* Ditto, see above */
2997 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2998 memset(&si
, 0, sizeof(si
));
2999 si
.cbSize
= sizeof(si
);
3000 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3001 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3002 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3003 "Vertical scrollbar is invisible, should be visible.\n");
3004 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3005 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3006 si
.nPage
, si
.nMin
, si
.nMax
);
3008 /* Ditto, see above */
3009 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a\na");
3010 memset(&si
, 0, sizeof(si
));
3011 si
.cbSize
= sizeof(si
);
3012 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3013 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3014 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3015 "Vertical scrollbar is invisible, should be visible.\n");
3016 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3017 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3018 si
.nPage
, si
.nMin
, si
.nMax
);
3020 /* Ditto, see above */
3021 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3022 memset(&si
, 0, sizeof(si
));
3023 si
.cbSize
= sizeof(si
);
3024 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3025 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3026 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3027 "Vertical scrollbar is invisible, should be visible.\n");
3028 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3029 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3030 si
.nPage
, si
.nMin
, si
.nMax
);
3032 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3033 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3034 memset(&si
, 0, sizeof(si
));
3035 si
.cbSize
= sizeof(si
);
3036 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3037 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3038 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3039 "Vertical scrollbar is visible, should be invisible.\n");
3040 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3041 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3042 si
.nPage
, si
.nMin
, si
.nMax
);
3044 DestroyWindow(hwndRichEdit
);
3046 hwndRichEdit
= new_richedit(NULL
);
3048 DISABLE_WS_VSCROLL(hwndRichEdit
);
3049 memset(&si
, 0, sizeof(si
));
3050 si
.cbSize
= sizeof(si
);
3051 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3052 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3053 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3054 "Vertical scrollbar is visible, should be invisible.\n");
3055 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3056 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3057 si
.nPage
, si
.nMin
, si
.nMax
);
3059 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3060 memset(&si
, 0, sizeof(si
));
3061 si
.cbSize
= sizeof(si
);
3062 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3063 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3064 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3065 "Vertical scrollbar is visible, should be invisible.\n");
3066 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3067 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3068 si
.nPage
, si
.nMin
, si
.nMax
);
3070 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
3071 memset(&si
, 0, sizeof(si
));
3072 si
.cbSize
= sizeof(si
);
3073 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3074 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3075 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3076 "Vertical scrollbar is visible, should be invisible.\n");
3077 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3078 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3079 si
.nPage
, si
.nMin
, si
.nMax
);
3081 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3082 memset(&si
, 0, sizeof(si
));
3083 si
.cbSize
= sizeof(si
);
3084 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3085 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3086 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3087 "Vertical scrollbar is visible, should be invisible.\n");
3088 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3089 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3090 si
.nPage
, si
.nMin
, si
.nMax
);
3092 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3093 memset(&si
, 0, sizeof(si
));
3094 si
.cbSize
= sizeof(si
);
3095 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3096 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3097 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3098 "Vertical scrollbar is invisible, should be visible.\n");
3099 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3100 "reported page/range is %d (%d..%d)\n",
3101 si
.nPage
, si
.nMin
, si
.nMax
);
3103 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */
3104 DISABLE_WS_VSCROLL(hwndRichEdit
);
3105 memset(&si
, 0, sizeof(si
));
3106 si
.cbSize
= sizeof(si
);
3107 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3108 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3109 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3110 "Vertical scrollbar is visible, should be invisible.\n");
3111 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3112 "reported page/range is %d (%d..%d)\n",
3113 si
.nPage
, si
.nMin
, si
.nMax
);
3115 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3116 memset(&si
, 0, sizeof(si
));
3117 si
.cbSize
= sizeof(si
);
3118 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3119 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3120 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3121 "Vertical scrollbar is visible, should be invisible.\n");
3122 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3123 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3124 si
.nPage
, si
.nMin
, si
.nMax
);
3126 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3127 memset(&si
, 0, sizeof(si
));
3128 si
.cbSize
= sizeof(si
);
3129 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3130 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3131 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3132 "Vertical scrollbar is invisible, should be visible.\n");
3133 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3134 "reported page/range is %d (%d..%d)\n",
3135 si
.nPage
, si
.nMin
, si
.nMax
);
3137 DISABLE_WS_VSCROLL(hwndRichEdit
);
3138 memset(&si
, 0, sizeof(si
));
3139 si
.cbSize
= sizeof(si
);
3140 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3141 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3142 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3143 "Vertical scrollbar is visible, should be invisible.\n");
3144 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3145 "reported page/range is %d (%d..%d)\n",
3146 si
.nPage
, si
.nMin
, si
.nMax
);
3148 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that
3149 EM_SCROLL will make visible any forcefully invisible scrollbar */
3150 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0);
3151 memset(&si
, 0, sizeof(si
));
3152 si
.cbSize
= sizeof(si
);
3153 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3154 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3155 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3156 "Vertical scrollbar is invisible, should be visible.\n");
3157 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3158 "reported page/range is %d (%d..%d)\n",
3159 si
.nPage
, si
.nMin
, si
.nMax
);
3161 DISABLE_WS_VSCROLL(hwndRichEdit
);
3162 memset(&si
, 0, sizeof(si
));
3163 si
.cbSize
= sizeof(si
);
3164 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3165 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3166 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3167 "Vertical scrollbar is visible, should be invisible.\n");
3168 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3169 "reported page/range is %d (%d..%d)\n",
3170 si
.nPage
, si
.nMin
, si
.nMax
);
3172 /* Again, EM_SCROLL, with SB_LINEUP */
3173 SendMessageA(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0);
3174 memset(&si
, 0, sizeof(si
));
3175 si
.cbSize
= sizeof(si
);
3176 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3177 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3178 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3179 "Vertical scrollbar is invisible, should be visible.\n");
3180 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3181 "reported page/range is %d (%d..%d)\n",
3182 si
.nPage
, si
.nMin
, si
.nMax
);
3184 DestroyWindow(hwndRichEdit
);
3186 /* This window proc models what is going on with Corman Lisp 3.0.
3187 At WM_SIZE, this proc unconditionally calls ShowScrollBar() to
3188 force the scrollbar into visibility. Recursion should NOT happen
3189 as a result of this action.
3191 r
= GetClassInfoA(NULL
, RICHEDIT_CLASS20A
, &cls
);
3193 richeditProc
= cls
.lpfnWndProc
;
3194 cls
.lpfnWndProc
= RicheditStupidOverrideProcA
;
3195 cls
.lpszClassName
= "RicheditStupidOverride";
3196 if(!RegisterClassA(&cls
)) assert(0);
3199 WM_SIZE_recursionLevel
= 0;
3200 bailedOutOfRecursion
= FALSE
;
3201 hwndRichEdit
= new_window(cls
.lpszClassName
, ES_MULTILINE
, NULL
);
3202 ok(!bailedOutOfRecursion
,
3203 "WM_SIZE/scrollbar mutual recursion detected, expected none!\n");
3206 WM_SIZE_recursionLevel
= 0;
3207 bailedOutOfRecursion
= FALSE
;
3208 MoveWindow(hwndRichEdit
, 0, 0, 250, 100, TRUE
);
3209 ok(!bailedOutOfRecursion
,
3210 "WM_SIZE/scrollbar mutual recursion detected, expected none!\n");
3212 /* Unblock window in order to process WM_DESTROY */
3214 bailedOutOfRecursion
= FALSE
;
3215 WM_SIZE_recursionLevel
= 0;
3216 DestroyWindow(hwndRichEdit
);
3220 static void test_EM_SETUNDOLIMIT(void)
3222 /* cases we test for:
3223 * default behaviour - limiting at 100 undo's
3224 * undo disabled - setting a limit of 0
3225 * undo limited - undo limit set to some to some number, like 2
3226 * bad input - sending a negative number should default to 100 undo's */
3228 HWND hwndRichEdit
= new_richedit(NULL
);
3233 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"x");
3236 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
3237 /*Load "x" into the clipboard. Paste is an easy, undo'able operation.
3238 also, multiple pastes don't combine like WM_CHAR would */
3239 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
3241 /* first case - check the default */
3242 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
3243 for (i
=0; i
<101; i
++) /* Put 101 undo's on the stack */
3244 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
3245 for (i
=0; i
<100; i
++) /* Undo 100 of them */
3246 SendMessageA(hwndRichEdit
, WM_UNDO
, 0, 0);
3247 ok(!SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0),
3248 "EM_SETUNDOLIMIT allowed more than a hundred undo's by default.\n");
3250 /* second case - cannot undo */
3251 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0, 0);
3252 SendMessageA(hwndRichEdit
, EM_SETUNDOLIMIT
, 0, 0);
3253 SendMessageA(hwndRichEdit
,
3254 WM_PASTE
, 0, 0); /* Try to put something in the undo stack */
3255 ok(!SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0),
3256 "EM_SETUNDOLIMIT allowed undo with UNDOLIMIT set to 0\n");
3258 /* third case - set it to an arbitrary number */
3259 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0, 0);
3260 SendMessageA(hwndRichEdit
, EM_SETUNDOLIMIT
, 2, 0);
3261 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
3262 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
3263 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
3264 /* If SETUNDOLIMIT is working, there should only be two undo's after this */
3265 ok(SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0,0),
3266 "EM_SETUNDOLIMIT didn't allow the first undo with UNDOLIMIT set to 2\n");
3267 SendMessageA(hwndRichEdit
, WM_UNDO
, 0, 0);
3268 ok(SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0),
3269 "EM_SETUNDOLIMIT didn't allow a second undo with UNDOLIMIT set to 2\n");
3270 SendMessageA(hwndRichEdit
, WM_UNDO
, 0, 0);
3271 ok(!SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0),
3272 "EM_SETUNDOLIMIT allowed a third undo with UNDOLIMIT set to 2\n");
3274 /* fourth case - setting negative numbers should default to 100 undos */
3275 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
3276 result
= SendMessageA(hwndRichEdit
, EM_SETUNDOLIMIT
, -1, 0);
3278 "EM_SETUNDOLIMIT returned %d when set to -1, instead of 100\n",result
);
3280 DestroyWindow(hwndRichEdit
);
3283 static void test_ES_PASSWORD(void)
3285 /* This isn't hugely testable, so we're just going to run it through its paces */
3287 HWND hwndRichEdit
= new_richedit(NULL
);
3290 /* First, check the default of a regular control */
3291 result
= SendMessageA(hwndRichEdit
, EM_GETPASSWORDCHAR
, 0, 0);
3293 "EM_GETPASSWORDCHAR returned %c by default, instead of NULL\n",result
);
3295 /* Now, set it to something normal */
3296 SendMessageA(hwndRichEdit
, EM_SETPASSWORDCHAR
, 'x', 0);
3297 result
= SendMessageA(hwndRichEdit
, EM_GETPASSWORDCHAR
, 0, 0);
3299 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result
,result
);
3301 /* Now, set it to something odd */
3302 SendMessageA(hwndRichEdit
, EM_SETPASSWORDCHAR
, (WCHAR
)1234, 0);
3303 result
= SendMessageA(hwndRichEdit
, EM_GETPASSWORDCHAR
, 0, 0);
3305 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result
,result
);
3306 DestroyWindow(hwndRichEdit
);
3309 static DWORD CALLBACK
test_WM_SETTEXT_esCallback(DWORD_PTR dwCookie
,
3314 char** str
= (char**)dwCookie
;
3317 memcpy(*str
, pbBuff
, *pcb
);
3323 static void test_WM_SETTEXT(void)
3325 HWND hwndRichEdit
= new_richedit(NULL
);
3326 const char * TestItem1
= "TestSomeText";
3327 const char * TestItem2
= "TestSomeText\r";
3328 const char * TestItem2_after
= "TestSomeText\r\n";
3329 const char * TestItem3
= "TestSomeText\rSomeMoreText\r";
3330 const char * TestItem3_after
= "TestSomeText\r\nSomeMoreText\r\n";
3331 const char * TestItem4
= "TestSomeText\n\nTestSomeText";
3332 const char * TestItem4_after
= "TestSomeText\r\n\r\nTestSomeText";
3333 const char * TestItem5
= "TestSomeText\r\r\nTestSomeText";
3334 const char * TestItem5_after
= "TestSomeText TestSomeText";
3335 const char * TestItem6
= "TestSomeText\r\r\n\rTestSomeText";
3336 const char * TestItem6_after
= "TestSomeText \r\nTestSomeText";
3337 const char * TestItem7
= "TestSomeText\r\n\r\r\n\rTestSomeText";
3338 const char * TestItem7_after
= "TestSomeText\r\n \r\nTestSomeText";
3340 const char rtftextA
[] = "{\\rtf sometext}";
3341 const char urtftextA
[] = "{\\urtf sometext}";
3342 const WCHAR rtftextW
[] = {'{','\\','r','t','f',' ','s','o','m','e','t','e','x','t','}',0};
3343 const WCHAR urtftextW
[] = {'{','\\','u','r','t','f',' ','s','o','m','e','t','e','x','t','}',0};
3344 const WCHAR sometextW
[] = {'s','o','m','e','t','e','x','t',0};
3346 char buf
[1024] = {0};
3347 WCHAR bufW
[1024] = {0};
3350 /* This test attempts to show that WM_SETTEXT on a riched20 control causes
3351 any solitary \r to be converted to \r\n on return. Properly paired
3352 \r\n are not affected. It also shows that the special sequence \r\r\n
3353 gets converted to a single space.
3356 #define TEST_SETTEXT(a, b) \
3357 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)a); \
3358 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \
3359 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf); \
3360 ok (result == lstrlenA(buf), \
3361 "WM_GETTEXT returned %ld instead of expected %u\n", \
3362 result, lstrlenA(buf)); \
3363 result = strcmp(b, buf); \
3365 "WM_SETTEXT round trip: strcmp = %ld, text=\"%s\"\n", result, buf);
3367 TEST_SETTEXT(TestItem1
, TestItem1
)
3368 TEST_SETTEXT(TestItem2
, TestItem2_after
)
3369 TEST_SETTEXT(TestItem3
, TestItem3_after
)
3370 TEST_SETTEXT(TestItem3_after
, TestItem3_after
)
3371 TEST_SETTEXT(TestItem4
, TestItem4_after
)
3372 TEST_SETTEXT(TestItem5
, TestItem5_after
)
3373 TEST_SETTEXT(TestItem6
, TestItem6_after
)
3374 TEST_SETTEXT(TestItem7
, TestItem7_after
)
3376 /* The following tests demonstrate that WM_SETTEXT supports RTF strings */
3377 TEST_SETTEXT(rtftextA
, "sometext") /* interpreted as ascii rtf */
3378 TEST_SETTEXT(urtftextA
, "sometext") /* interpreted as ascii rtf */
3379 TEST_SETTEXT(rtftextW
, "{") /* interpreted as ascii text */
3380 TEST_SETTEXT(urtftextW
, "{") /* interpreted as ascii text */
3381 DestroyWindow(hwndRichEdit
);
3384 #define TEST_SETTEXTW(a, b) \
3385 result = SendMessageW(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)a); \
3386 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \
3387 result = SendMessageW(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufW); \
3388 ok (result == lstrlenW(bufW), \
3389 "WM_GETTEXT returned %ld instead of expected %u\n", \
3390 result, lstrlenW(bufW)); \
3391 result = lstrcmpW(b, bufW); \
3392 ok(result == 0, "WM_SETTEXT round trip: strcmp = %ld\n", result);
3394 hwndRichEdit
= CreateWindowW(RICHEDIT_CLASS20W
, NULL
,
3395 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
3396 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
3397 ok(hwndRichEdit
!= NULL
, "class: RichEdit20W, error: %d\n", (int) GetLastError());
3398 TEST_SETTEXTW(rtftextA
, sometextW
) /* interpreted as ascii rtf */
3399 TEST_SETTEXTW(urtftextA
, sometextW
) /* interpreted as ascii rtf */
3400 TEST_SETTEXTW(rtftextW
, rtftextW
) /* interpreted as ascii text */
3401 TEST_SETTEXTW(urtftextW
, urtftextW
) /* interpreted as ascii text */
3402 DestroyWindow(hwndRichEdit
);
3403 #undef TEST_SETTEXTW
3406 static void test_EM_STREAMOUT(void)
3408 HWND hwndRichEdit
= new_richedit(NULL
);
3411 char buf
[1024] = {0};
3414 const char * TestItem1
= "TestSomeText";
3415 const char * TestItem2
= "TestSomeText\r";
3416 const char * TestItem3
= "TestSomeText\r\n";
3418 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem1
);
3420 es
.dwCookie
= (DWORD_PTR
)&p
;
3422 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3423 memset(buf
, 0, sizeof(buf
));
3424 SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_TEXT
, (LPARAM
)&es
);
3426 ok(r
== 12, "streamed text length is %d, expecting 12\n", r
);
3427 ok(strcmp(buf
, TestItem1
) == 0,
3428 "streamed text different, got %s\n", buf
);
3430 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem2
);
3432 es
.dwCookie
= (DWORD_PTR
)&p
;
3434 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3435 memset(buf
, 0, sizeof(buf
));
3436 SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_TEXT
, (LPARAM
)&es
);
3438 /* Here again, \r gets converted to \r\n, like WM_GETTEXT */
3439 ok(r
== 14, "streamed text length is %d, expecting 14\n", r
);
3440 ok(strcmp(buf
, TestItem3
) == 0,
3441 "streamed text different from, got %s\n", buf
);
3442 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem3
);
3444 es
.dwCookie
= (DWORD_PTR
)&p
;
3446 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3447 memset(buf
, 0, sizeof(buf
));
3448 SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_TEXT
, (LPARAM
)&es
);
3450 ok(r
== 14, "streamed text length is %d, expecting 14\n", r
);
3451 ok(strcmp(buf
, TestItem3
) == 0,
3452 "streamed text different, got %s\n", buf
);
3454 DestroyWindow(hwndRichEdit
);
3457 static void test_EM_STREAMOUT_FONTTBL(void)
3459 HWND hwndRichEdit
= new_richedit(NULL
);
3461 char buf
[1024] = {0};
3466 const char * TestItem
= "TestSomeText";
3468 /* fills in the richedit control with some text */
3469 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem
);
3471 /* streams out the text in rtf format */
3473 es
.dwCookie
= (DWORD_PTR
)&p
;
3475 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3476 memset(buf
, 0, sizeof(buf
));
3477 SendMessageA(hwndRichEdit
, EM_STREAMOUT
, SF_RTF
, (LPARAM
)&es
);
3479 /* scans for \fonttbl, error if not found */
3480 fontTbl
= strstr(buf
, "\\fonttbl");
3481 ok(fontTbl
!= NULL
, "missing \\fonttbl section\n");
3484 /* scans for terminating closing bracket */
3486 while(*fontTbl
&& brackCount
)
3490 else if(*fontTbl
== '}')
3494 /* checks whether closing bracket is ok */
3495 ok(brackCount
== 0, "missing closing bracket in \\fonttbl block\n");
3498 /* char before closing fonttbl block should be a closed bracket */
3500 ok(*fontTbl
== '}', "spurious character '%02x' before \\fonttbl closing bracket\n", *fontTbl
);
3502 /* char after fonttbl block should be a crlf */
3504 ok(*fontTbl
== 0x0d && *(fontTbl
+1) == 0x0a, "missing crlf after \\fonttbl block\n");
3507 DestroyWindow(hwndRichEdit
);
3511 static void test_EM_SETTEXTEX(void)
3513 HWND hwndRichEdit
, parent
;
3515 int sel_start
, sel_end
;
3518 WCHAR TestItem1
[] = {'T', 'e', 's', 't',
3520 'T', 'e', 'x', 't', 0};
3521 WCHAR TestItem1alt
[] = {'T', 'T', 'e', 's',
3527 WCHAR TestItem1altn
[] = {'T','T','e','s','t','S','o','m','e','T','e','x','t',
3528 '\r','t','S','o','m','e','T','e','x','t',0};
3529 WCHAR TestItem2
[] = {'T', 'e', 's', 't',
3533 const char * TestItem2_after
= "TestSomeText\r\n";
3534 WCHAR TestItem3
[] = {'T', 'e', 's', 't',
3537 '\r','\n','\r','\n', 0};
3538 WCHAR TestItem3alt
[] = {'T', 'e', 's', 't',
3542 WCHAR TestItem3_after
[] = {'T', 'e', 's', 't',
3546 WCHAR TestItem4
[] = {'T', 'e', 's', 't',
3549 '\r','\r','\n','\r',
3551 WCHAR TestItem4_after
[] = {'T', 'e', 's', 't',
3555 #define MAX_BUF_LEN 1024
3556 WCHAR buf
[MAX_BUF_LEN
];
3557 char bufACP
[MAX_BUF_LEN
];
3564 /* Test the scroll position with and without a parent window.
3566 * For some reason the scroll position is 0 after EM_SETTEXTEX
3567 * with the ST_SELECTION flag only when the control has a parent
3568 * window, even though the selection is at the end. */
3570 cls
.lpfnWndProc
= DefWindowProcA
;
3573 cls
.hInstance
= GetModuleHandleA(0);
3575 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
3576 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
3577 cls
.lpszMenuName
= NULL
;
3578 cls
.lpszClassName
= "ParentTestClass";
3579 if(!RegisterClassA(&cls
)) assert(0);
3581 parent
= CreateWindowA(cls
.lpszClassName
, NULL
, WS_POPUP
|WS_VISIBLE
,
3582 0, 0, 200, 60, NULL
, NULL
, NULL
, NULL
);
3583 ok (parent
!= 0, "Failed to create parent window\n");
3585 hwndRichEdit
= CreateWindowExA(0,
3586 RICHEDIT_CLASS20A
, NULL
,
3587 ES_MULTILINE
|WS_VSCROLL
|WS_VISIBLE
|WS_CHILD
,
3588 0, 0, 200, 60, parent
, NULL
,
3589 hmoduleRichEdit
, NULL
);
3591 setText
.codepage
= CP_ACP
;
3592 setText
.flags
= ST_SELECTION
;
3593 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
,
3594 (LPARAM
)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
3595 si
.cbSize
= sizeof(si
);
3597 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3598 todo_wine
ok(si
.nPos
== 0, "Position is incorrectly at %d\n", si
.nPos
);
3599 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
3600 ok(sel_start
== 18, "Selection start incorrectly at %d\n", sel_start
);
3601 ok(sel_end
== 18, "Selection end incorrectly at %d\n", sel_end
);
3603 DestroyWindow(parent
);
3605 /* Test without a parent window */
3606 hwndRichEdit
= new_richedit(NULL
);
3607 setText
.codepage
= CP_ACP
;
3608 setText
.flags
= ST_SELECTION
;
3609 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
,
3610 (LPARAM
)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
3611 si
.cbSize
= sizeof(si
);
3613 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3614 ok(si
.nPos
!= 0, "Position is incorrectly at %d\n", si
.nPos
);
3615 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
3616 ok(sel_start
== 18, "Selection start incorrectly at %d\n", sel_start
);
3617 ok(sel_end
== 18, "Selection end incorrectly at %d\n", sel_end
);
3619 /* The scroll position should also be 0 after EM_SETTEXTEX with ST_DEFAULT,
3620 * but this time it is because the selection is at the beginning. */
3621 setText
.codepage
= CP_ACP
;
3622 setText
.flags
= ST_DEFAULT
;
3623 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
,
3624 (LPARAM
)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
3625 si
.cbSize
= sizeof(si
);
3627 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3628 ok(si
.nPos
== 0, "Position is incorrectly at %d\n", si
.nPos
);
3629 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
3630 ok(sel_start
== 0, "Selection start incorrectly at %d\n", sel_start
);
3631 ok(sel_end
== 0, "Selection end incorrectly at %d\n", sel_end
);
3633 setText
.codepage
= 1200; /* no constant for unicode */
3634 getText
.codepage
= 1200; /* no constant for unicode */
3635 getText
.cb
= MAX_BUF_LEN
;
3636 getText
.flags
= GT_DEFAULT
;
3637 getText
.lpDefaultChar
= NULL
;
3638 getText
.lpUsedDefChar
= NULL
;
3641 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
3642 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3643 ok(lstrcmpW(buf
, TestItem1
) == 0,
3644 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
3646 /* Unlike WM_SETTEXT/WM_GETTEXT pair, EM_SETTEXTEX/EM_GETTEXTEX does not
3647 convert \r to \r\n on return: !ST_SELECTION && Unicode && !\rtf
3649 setText
.codepage
= 1200; /* no constant for unicode */
3650 getText
.codepage
= 1200; /* no constant for unicode */
3651 getText
.cb
= MAX_BUF_LEN
;
3652 getText
.flags
= GT_DEFAULT
;
3653 getText
.lpDefaultChar
= NULL
;
3654 getText
.lpUsedDefChar
= NULL
;
3656 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem2
);
3657 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3658 ok(lstrcmpW(buf
, TestItem2
) == 0,
3659 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
3661 /* However, WM_GETTEXT *does* see \r\n where EM_GETTEXTEX would see \r */
3662 SendMessageA(hwndRichEdit
, WM_GETTEXT
, MAX_BUF_LEN
, (LPARAM
)buf
);
3663 ok(strcmp((const char *)buf
, TestItem2_after
) == 0,
3664 "WM_GETTEXT did *not* see \\r converted to \\r\\n pairs.\n");
3666 /* Baseline test for just-enough buffer space for string */
3667 getText
.cb
= (lstrlenW(TestItem2
) + 1) * sizeof(WCHAR
);
3668 getText
.codepage
= 1200; /* no constant for unicode */
3669 getText
.flags
= GT_DEFAULT
;
3670 getText
.lpDefaultChar
= NULL
;
3671 getText
.lpUsedDefChar
= NULL
;
3672 memset(buf
, 0, MAX_BUF_LEN
);
3673 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3674 ok(lstrcmpW(buf
, TestItem2
) == 0,
3675 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
3677 /* When there is enough space for one character, but not both, of the CRLF
3678 pair at the end of the string, the CR is not copied at all. That is,
3679 the caller must not see CRLF pairs truncated to CR at the end of the
3682 getText
.cb
= (lstrlenW(TestItem2
) + 1) * sizeof(WCHAR
);
3683 getText
.codepage
= 1200; /* no constant for unicode */
3684 getText
.flags
= GT_USECRLF
; /* <-- asking for CR -> CRLF conversion */
3685 getText
.lpDefaultChar
= NULL
;
3686 getText
.lpUsedDefChar
= NULL
;
3687 memset(buf
, 0, MAX_BUF_LEN
);
3688 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3689 ok(lstrcmpW(buf
, TestItem1
) == 0,
3690 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
3693 /* \r\n pairs get changed into \r: !ST_SELECTION && Unicode && !\rtf */
3694 setText
.codepage
= 1200; /* no constant for unicode */
3695 getText
.codepage
= 1200; /* no constant for unicode */
3696 getText
.cb
= MAX_BUF_LEN
;
3697 getText
.flags
= GT_DEFAULT
;
3698 getText
.lpDefaultChar
= NULL
;
3699 getText
.lpUsedDefChar
= NULL
;
3701 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem3
);
3702 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3703 ok(lstrcmpW(buf
, TestItem3_after
) == 0,
3704 "EM_SETTEXTEX did not convert properly\n");
3706 /* \n also gets changed to \r: !ST_SELECTION && Unicode && !\rtf */
3707 setText
.codepage
= 1200; /* no constant for unicode */
3708 getText
.codepage
= 1200; /* no constant for unicode */
3709 getText
.cb
= MAX_BUF_LEN
;
3710 getText
.flags
= GT_DEFAULT
;
3711 getText
.lpDefaultChar
= NULL
;
3712 getText
.lpUsedDefChar
= NULL
;
3714 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem3alt
);
3715 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3716 ok(lstrcmpW(buf
, TestItem3_after
) == 0,
3717 "EM_SETTEXTEX did not convert properly\n");
3719 /* \r\r\n gets changed into single space: !ST_SELECTION && Unicode && !\rtf */
3720 setText
.codepage
= 1200; /* no constant for unicode */
3721 getText
.codepage
= 1200; /* no constant for unicode */
3722 getText
.cb
= MAX_BUF_LEN
;
3723 getText
.flags
= GT_DEFAULT
;
3724 getText
.lpDefaultChar
= NULL
;
3725 getText
.lpUsedDefChar
= NULL
;
3727 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem4
);
3728 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3729 ok(lstrcmpW(buf
, TestItem4_after
) == 0,
3730 "EM_SETTEXTEX did not convert properly\n");
3732 /* !ST_SELECTION && Unicode && !\rtf */
3733 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, 0);
3734 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3737 "EM_SETTEXTEX returned %d, instead of 1\n",result
);
3738 ok(lstrlenW(buf
) == 0,
3739 "EM_SETTEXTEX with NULL lParam should clear rich edit.\n");
3741 /* put some text back: !ST_SELECTION && Unicode && !\rtf */
3743 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
3744 /* select some text */
3747 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
3748 /* replace current selection: ST_SELECTION && Unicode && !\rtf */
3749 setText
.flags
= ST_SELECTION
;
3750 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, 0);
3752 "EM_SETTEXTEX with NULL lParam to replace selection"
3753 " with no text should return 0. Got %i\n",
3756 /* put some text back: !ST_SELECTION && Unicode && !\rtf */
3758 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
3759 /* select some text */
3762 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
3763 /* replace current selection: ST_SELECTION && Unicode && !\rtf */
3764 setText
.flags
= ST_SELECTION
;
3765 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
3767 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3768 ok(result
== lstrlenW(TestItem1
),
3769 "EM_SETTEXTEX with NULL lParam to replace selection"
3770 " with no text should return 0. Got %i\n",
3772 ok(lstrlenW(buf
) == 22,
3773 "EM_SETTEXTEX to replace selection with more text failed: %i.\n",
3776 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings */
3777 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"TestSomeText"); /* TestItem1 */
3779 es
.dwCookie
= (DWORD_PTR
)&p
;
3781 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3782 memset(buf
, 0, sizeof(buf
));
3783 SendMessageA(hwndRichEdit
, EM_STREAMOUT
,
3784 (WPARAM
)(SF_RTF
), (LPARAM
)&es
);
3785 trace("EM_STREAMOUT produced:\n%s\n", (char *)buf
);
3787 /* !ST_SELECTION && !Unicode && \rtf */
3788 setText
.codepage
= CP_ACP
;/* EM_STREAMOUT saved as ANSI string */
3789 getText
.codepage
= 1200; /* no constant for unicode */
3790 getText
.cb
= MAX_BUF_LEN
;
3791 getText
.flags
= GT_DEFAULT
;
3792 getText
.lpDefaultChar
= NULL
;
3793 getText
.lpUsedDefChar
= NULL
;
3796 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)buf
);
3797 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3798 ok(lstrcmpW(buf
, TestItem1
) == 0,
3799 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
3801 /* The following test demonstrates that EM_SETTEXTEX treats text as ASCII if it
3802 * starts with ASCII characters "{\rtf" even when the codepage is unicode. */
3803 setText
.codepage
= 1200; /* Lie about code page (actual ASCII) */
3804 getText
.codepage
= CP_ACP
;
3805 getText
.cb
= MAX_BUF_LEN
;
3806 getText
.flags
= GT_DEFAULT
;
3807 getText
.lpDefaultChar
= NULL
;
3808 getText
.lpUsedDefChar
= NULL
;
3810 setText
.flags
= ST_SELECTION
;
3811 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
3812 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"{\\rtf not unicode}");
3813 todo_wine
ok(result
== 11, "EM_SETTEXTEX incorrectly returned %d\n", result
);
3814 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)bufACP
);
3815 ok(lstrcmpA(bufACP
, "not unicode") == 0, "'%s' != 'not unicode'\n", bufACP
);
3817 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings with a selection */
3818 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"TestSomeText"); /* TestItem1 */
3820 es
.dwCookie
= (DWORD_PTR
)&p
;
3822 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3823 memset(buf
, 0, sizeof(buf
));
3824 SendMessageA(hwndRichEdit
, EM_STREAMOUT
,
3825 (WPARAM
)(SF_RTF
), (LPARAM
)&es
);
3826 trace("EM_STREAMOUT produced:\n%s\n", (char *)buf
);
3828 /* select some text */
3831 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
3833 /* ST_SELECTION && !Unicode && \rtf */
3834 setText
.codepage
= CP_ACP
;/* EM_STREAMOUT saved as ANSI string */
3835 getText
.codepage
= 1200; /* no constant for unicode */
3836 getText
.cb
= MAX_BUF_LEN
;
3837 getText
.flags
= GT_DEFAULT
;
3838 getText
.lpDefaultChar
= NULL
;
3839 getText
.lpUsedDefChar
= NULL
;
3841 setText
.flags
= ST_SELECTION
;
3842 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)buf
);
3843 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3844 ok_w3("Expected \"%s\" or \"%s\", got \"%s\"\n", TestItem1alt
, TestItem1altn
, buf
);
3846 /* The following test demonstrates that EM_SETTEXTEX replacing a selection */
3847 setText
.codepage
= 1200; /* no constant for unicode */
3848 getText
.codepage
= CP_ACP
;
3849 getText
.cb
= MAX_BUF_LEN
;
3852 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
); /* TestItem1 */
3853 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)bufACP
);
3855 /* select some text */
3858 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
3860 /* ST_SELECTION && !Unicode && !\rtf */
3861 setText
.codepage
= CP_ACP
;
3862 getText
.codepage
= 1200; /* no constant for unicode */
3863 getText
.cb
= MAX_BUF_LEN
;
3864 getText
.flags
= GT_DEFAULT
;
3865 getText
.lpDefaultChar
= NULL
;
3866 getText
.lpUsedDefChar
= NULL
;
3868 setText
.flags
= ST_SELECTION
;
3869 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)bufACP
);
3870 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3871 ok(lstrcmpW(buf
, TestItem1alt
) == 0,
3872 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX when"
3873 " using ST_SELECTION and non-Unicode\n");
3875 /* Test setting text using rich text format */
3877 setText
.codepage
= CP_ACP
;
3878 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"{\\rtf richtext}");
3879 getText
.codepage
= CP_ACP
;
3880 getText
.cb
= MAX_BUF_LEN
;
3881 getText
.flags
= GT_DEFAULT
;
3882 getText
.lpDefaultChar
= NULL
;
3883 getText
.lpUsedDefChar
= NULL
;
3884 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)bufACP
);
3885 ok(!strcmp(bufACP
, "richtext"), "expected 'richtext' but got '%s'\n", bufACP
);
3888 setText
.codepage
= CP_ACP
;
3889 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"{\\urtf morerichtext}");
3890 getText
.codepage
= CP_ACP
;
3891 getText
.cb
= MAX_BUF_LEN
;
3892 getText
.flags
= GT_DEFAULT
;
3893 getText
.lpDefaultChar
= NULL
;
3894 getText
.lpUsedDefChar
= NULL
;
3895 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)bufACP
);
3896 ok(!strcmp(bufACP
, "morerichtext"), "expected 'morerichtext' but got '%s'\n", bufACP
);
3898 /* test for utf8 text with BOM */
3900 setText
.codepage
= CP_ACP
;
3901 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"\xef\xbb\xbfTestUTF8WithBOM");
3902 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)bufACP
);
3903 ok(result
== 15, "EM_SETTEXTEX: Test UTF8 with BOM returned %d, expected 15\n", result
);
3904 result
= strcmp(bufACP
, "TestUTF8WithBOM");
3905 ok(result
== 0, "EM_SETTEXTEX: Test UTF8 with BOM set wrong text: Result: %s\n", bufACP
);
3908 setText
.codepage
= CP_UTF8
;
3909 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"\xef\xbb\xbfTestUTF8WithBOM");
3910 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)bufACP
);
3911 ok(result
== 15, "EM_SETTEXTEX: Test UTF8 with BOM returned %d, expected 15\n", result
);
3912 result
= strcmp(bufACP
, "TestUTF8WithBOM");
3913 ok(result
== 0, "EM_SETTEXTEX: Test UTF8 with BOM set wrong text: Result: %s\n", bufACP
);
3915 DestroyWindow(hwndRichEdit
);
3918 static void test_EM_LIMITTEXT(void)
3922 HWND hwndRichEdit
= new_richedit(NULL
);
3924 /* The main purpose of this test is to demonstrate that the nonsense in MSDN
3925 * about setting the length to -1 for multiline edit controls doesn't happen.
3928 /* Don't check default gettextlimit case. That's done in other tests */
3930 /* Set textlimit to 100 */
3931 SendMessageA(hwndRichEdit
, EM_LIMITTEXT
, 100, 0);
3932 ret
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3934 "EM_LIMITTEXT: set to 100, returned: %d, expected: 100\n", ret
);
3936 /* Set textlimit to 0 */
3937 SendMessageA(hwndRichEdit
, EM_LIMITTEXT
, 0, 0);
3938 ret
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3940 "EM_LIMITTEXT: set to 0, returned: %d, expected: 65536\n", ret
);
3942 /* Set textlimit to -1 */
3943 SendMessageA(hwndRichEdit
, EM_LIMITTEXT
, -1, 0);
3944 ret
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3946 "EM_LIMITTEXT: set to -1, returned: %d, expected: -1\n", ret
);
3948 /* Set textlimit to -2 */
3949 SendMessageA(hwndRichEdit
, EM_LIMITTEXT
, -2, 0);
3950 ret
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3952 "EM_LIMITTEXT: set to -2, returned: %d, expected: -2\n", ret
);
3954 DestroyWindow (hwndRichEdit
);
3958 static void test_EM_EXLIMITTEXT(void)
3960 int i
, selBegin
, selEnd
, len1
, len2
;
3962 char text
[1024 + 1];
3963 char buffer
[1024 + 1];
3964 int textlimit
= 0; /* multiple of 100 */
3965 HWND hwndRichEdit
= new_richedit(NULL
);
3967 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3968 ok(32767 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 32767, i
); /* default */
3971 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
3972 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3974 ok(textlimit
== i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit
, i
);
3977 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
3978 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3980 ok(textlimit
== i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit
, i
);
3982 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, 0);
3983 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3984 /* default for WParam = 0 */
3985 ok(65536 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 65536, i
);
3987 textlimit
= sizeof(text
)-1;
3988 memset(text
, 'W', textlimit
);
3989 text
[sizeof(text
)-1] = 0;
3990 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
3991 /* maxed out text */
3992 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3994 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1); /* select everything */
3995 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
3996 len1
= selEnd
- selBegin
;
3998 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, VK_BACK
, 1);
3999 SendMessageA(hwndRichEdit
, WM_CHAR
, VK_BACK
, 1);
4000 SendMessageA(hwndRichEdit
, WM_KEYUP
, VK_BACK
, 1);
4001 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4002 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
4003 len2
= selEnd
- selBegin
;
4006 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4009 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'A', 1);
4010 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 1);
4011 SendMessageA(hwndRichEdit
, WM_KEYUP
, 'A', 1);
4012 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4013 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
4014 len1
= selEnd
- selBegin
;
4017 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4020 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'A', 1);
4021 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 1);
4022 SendMessageA(hwndRichEdit
, WM_KEYUP
, 'A', 1); /* full; should be no effect */
4023 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4024 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
4025 len2
= selEnd
- selBegin
;
4028 "EM_EXLIMITTEXT: No Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4031 /* set text up to the limit, select all the text, then add a char */
4033 memset(text
, 'W', textlimit
);
4034 text
[textlimit
] = 0;
4035 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
4036 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
4037 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4038 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 1);
4039 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4040 result
= strcmp(buffer
, "A");
4041 ok(0 == result
, "got string = \"%s\"\n", buffer
);
4043 /* WM_SETTEXT not limited */
4045 memset(text
, 'W', textlimit
);
4046 text
[textlimit
] = 0;
4047 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
-5);
4048 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
4049 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4051 ok(10 == i
, "expected 10 chars\n");
4052 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4053 ok(10 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i
);
4055 /* try inserting more text at end */
4056 i
= SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4057 ok(0 == i
, "WM_CHAR wasn't processed\n");
4058 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4060 ok(10 == i
, "expected 10 chars, got %i\n", i
);
4061 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4062 ok(10 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i
);
4064 /* try inserting text at beginning */
4065 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 0);
4066 i
= SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4067 ok(0 == i
, "WM_CHAR wasn't processed\n");
4068 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4070 ok(10 == i
, "expected 10 chars, got %i\n", i
);
4071 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4072 ok(10 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i
);
4074 /* WM_CHAR is limited */
4076 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
4077 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1); /* select everything */
4078 i
= SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4079 ok(0 == i
, "WM_CHAR wasn't processed\n");
4080 i
= SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4081 ok(0 == i
, "WM_CHAR wasn't processed\n");
4082 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4084 ok(1 == i
, "expected 1 chars, got %i instead\n", i
);
4086 DestroyWindow(hwndRichEdit
);
4089 static void test_EM_GETLIMITTEXT(void)
4092 HWND hwndRichEdit
= new_richedit(NULL
);
4094 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4095 ok(32767 == i
, "expected: %d, actual: %d\n", 32767, i
); /* default value */
4097 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, 50000);
4098 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4099 ok(50000 == i
, "expected: %d, actual: %d\n", 50000, i
);
4101 DestroyWindow(hwndRichEdit
);
4104 static void test_WM_SETFONT(void)
4106 /* There is no invalid input or error conditions for this function.
4107 * NULL wParam and lParam just fall back to their default values
4108 * It should be noted that even if you use a gibberish name for your fonts
4109 * here, it will still work because the name is stored. They will display as
4110 * System, but will report their name to be whatever they were created as */
4112 HWND hwndRichEdit
= new_richedit(NULL
);
4113 HFONT testFont1
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4114 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4115 FF_DONTCARE
, "Marlett");
4116 HFONT testFont2
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4117 OUT_TT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4118 FF_DONTCARE
, "MS Sans Serif");
4119 HFONT testFont3
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4120 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4121 FF_DONTCARE
, "Courier");
4122 LOGFONTA sentLogFont
;
4123 CHARFORMAT2A returnedCF2A
;
4125 returnedCF2A
.cbSize
= sizeof(returnedCF2A
);
4127 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"x");
4128 SendMessageA(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont1
, MAKELPARAM(TRUE
, 0));
4129 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&returnedCF2A
);
4131 GetObjectA(testFont1
, sizeof(LOGFONTA
), &sentLogFont
);
4132 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
4133 "EM_GETCHARFORMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n",
4134 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
4136 SendMessageA(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont2
, MAKELPARAM(TRUE
, 0));
4137 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&returnedCF2A
);
4138 GetObjectA(testFont2
, sizeof(LOGFONTA
), &sentLogFont
);
4139 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
4140 "EM_GETCHARFORMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n",
4141 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
4143 SendMessageA(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont3
, MAKELPARAM(TRUE
, 0));
4144 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&returnedCF2A
);
4145 GetObjectA(testFont3
, sizeof(LOGFONTA
), &sentLogFont
);
4146 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
4147 "EM_GETCHARFORMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n",
4148 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
4150 /* This last test is special since we send in NULL. We clear the variables
4151 * and just compare to "System" instead of the sent in font name. */
4152 ZeroMemory(&returnedCF2A
,sizeof(returnedCF2A
));
4153 ZeroMemory(&sentLogFont
,sizeof(sentLogFont
));
4154 returnedCF2A
.cbSize
= sizeof(returnedCF2A
);
4156 SendMessageA(hwndRichEdit
, WM_SETFONT
, 0, MAKELPARAM((WORD
) TRUE
, 0));
4157 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&returnedCF2A
);
4158 GetObjectA(NULL
, sizeof(LOGFONTA
), &sentLogFont
);
4159 ok (!strcmp("System",returnedCF2A
.szFaceName
),
4160 "EM_GETCHARFORMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A
.szFaceName
);
4162 DestroyWindow(hwndRichEdit
);
4166 static DWORD CALLBACK
test_EM_GETMODIFY_esCallback(DWORD_PTR dwCookie
,
4171 const char** str
= (const char**)dwCookie
;
4172 int size
= strlen(*str
);
4173 if(size
> 3) /* let's make it piecemeal for fun */
4180 memcpy(pbBuff
, *str
, *pcb
);
4186 static void test_EM_GETMODIFY(void)
4188 HWND hwndRichEdit
= new_richedit(NULL
);
4191 WCHAR TestItem1
[] = {'T', 'e', 's', 't',
4193 'T', 'e', 'x', 't', 0};
4194 WCHAR TestItem2
[] = {'T', 'e', 's', 't',
4196 'O', 't', 'h', 'e', 'r',
4197 'T', 'e', 'x', 't', 0};
4198 const char* streamText
= "hello world";
4203 HFONT testFont
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4204 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4205 FF_DONTCARE
, "Courier");
4207 setText
.codepage
= 1200; /* no constant for unicode */
4208 setText
.flags
= ST_KEEPUNDO
;
4211 /* modify flag shouldn't be set when richedit is first created */
4212 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4214 "EM_GETMODIFY returned non-zero, instead of zero on create\n");
4216 /* setting modify flag should actually set it */
4217 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, TRUE
, 0);
4218 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4220 "EM_GETMODIFY returned zero, instead of non-zero on EM_SETMODIFY\n");
4222 /* clearing modify flag should actually clear it */
4223 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4224 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4226 "EM_GETMODIFY returned non-zero, instead of zero on EM_SETMODIFY\n");
4228 /* setting font doesn't change modify flag */
4229 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4230 SendMessageA(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont
, MAKELPARAM(TRUE
, 0));
4231 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4233 "EM_GETMODIFY returned non-zero, instead of zero on setting font\n");
4235 /* setting text should set modify flag */
4236 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4237 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
4238 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4240 "EM_GETMODIFY returned zero, instead of non-zero on setting text\n");
4242 /* undo previous text doesn't reset modify flag */
4243 SendMessageA(hwndRichEdit
, WM_UNDO
, 0, 0);
4244 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4246 "EM_GETMODIFY returned zero, instead of non-zero on undo after setting text\n");
4248 /* set text with no flag to keep undo stack should not set modify flag */
4249 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4251 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
4252 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4254 "EM_GETMODIFY returned non-zero, instead of zero when setting text while not keeping undo stack\n");
4256 /* WM_SETTEXT doesn't modify */
4257 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4258 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem2
);
4259 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4261 "EM_GETMODIFY returned non-zero for WM_SETTEXT\n");
4263 /* clear the text */
4264 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4265 SendMessageA(hwndRichEdit
, WM_CLEAR
, 0, 0);
4266 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4268 "EM_GETMODIFY returned non-zero, instead of zero for WM_CLEAR\n");
4271 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4272 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
4273 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
4274 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, TRUE
, (LPARAM
)TestItem2
);
4275 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4277 "EM_GETMODIFY returned zero, instead of non-zero when replacing text\n");
4279 /* copy/paste text 1 */
4280 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4281 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
4282 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
4283 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
4284 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4286 "EM_GETMODIFY returned zero, instead of non-zero when pasting identical text\n");
4288 /* copy/paste text 2 */
4289 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4290 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
4291 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
4292 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 3);
4293 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
4294 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4296 "EM_GETMODIFY returned zero, instead of non-zero when pasting different text\n");
4299 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4300 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 1);
4301 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4302 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4304 "EM_GETMODIFY returned zero, instead of non-zero for WM_CHAR\n");
4307 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4308 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4309 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, VK_BACK
, 0);
4310 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4312 "EM_GETMODIFY returned zero, instead of non-zero for backspace\n");
4314 /* set char format */
4315 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4316 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
4317 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
4318 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
4319 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
4320 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
4321 result
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
4322 ok(result
== 1, "EM_SETCHARFORMAT returned %ld instead of 1\n", result
);
4323 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4325 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETCHARFORMAT\n");
4327 /* set para format */
4328 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4329 pf2
.cbSize
= sizeof(PARAFORMAT2
);
4330 SendMessageA(hwndRichEdit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&pf2
);
4331 pf2
.dwMask
= PFM_ALIGNMENT
| pf2
.dwMask
;
4332 pf2
.wAlignment
= PFA_RIGHT
;
4333 SendMessageA(hwndRichEdit
, EM_SETPARAFORMAT
, 0, (LPARAM
)&pf2
);
4334 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4336 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETPARAFORMAT\n");
4339 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4340 es
.dwCookie
= (DWORD_PTR
)&streamText
;
4342 es
.pfnCallback
= test_EM_GETMODIFY_esCallback
;
4343 SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
4344 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4346 "EM_GETMODIFY returned zero, instead of non-zero for EM_STREAM\n");
4348 DestroyWindow(hwndRichEdit
);
4354 LRESULT expected_retval
;
4355 int expected_getsel_start
;
4356 int expected_getsel_end
;
4357 int _getsel_todo_wine
;
4360 const struct exsetsel_s exsetsel_tests
[] = {
4362 {5, 10, 10, 5, 10, 0},
4363 {15, 17, 17, 15, 17, 0},
4364 /* test cpMax > strlen() */
4365 {0, 100, 18, 0, 18, 1},
4366 /* test cpMin == cpMax */
4368 /* test cpMin < 0 && cpMax >= 0 (bug 4462) */
4369 {-1, 0, 5, 5, 5, 0},
4370 {-1, 17, 5, 5, 5, 0},
4371 {-1, 18, 5, 5, 5, 0},
4372 /* test cpMin < 0 && cpMax < 0 */
4373 {-1, -1, 17, 17, 17, 0},
4374 {-4, -5, 17, 17, 17, 0},
4375 /* test cMin >=0 && cpMax < 0 (bug 6814) */
4376 {0, -1, 18, 0, 18, 1},
4377 {17, -5, 18, 17, 18, 1},
4378 {18, -3, 17, 17, 17, 0},
4379 /* test if cpMin > cpMax */
4380 {15, 19, 18, 15, 18, 1},
4381 {19, 15, 18, 15, 18, 1}
4384 static void check_EM_EXSETSEL(HWND hwnd
, const struct exsetsel_s
*setsel
, int id
) {
4389 cr
.cpMin
= setsel
->min
;
4390 cr
.cpMax
= setsel
->max
;
4391 result
= SendMessageA(hwnd
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
4393 ok(result
== setsel
->expected_retval
, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id
, setsel
->expected_retval
, result
);
4395 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&start
, (LPARAM
)&end
);
4397 if (setsel
->_getsel_todo_wine
) {
4399 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
);
4402 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
);
4406 static void test_EM_EXSETSEL(void)
4408 HWND hwndRichEdit
= new_richedit(NULL
);
4410 const int num_tests
= sizeof(exsetsel_tests
)/sizeof(struct exsetsel_s
);
4412 /* sending some text to the window */
4413 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"testing selection");
4414 /* 01234567890123456*/
4417 for (i
= 0; i
< num_tests
; i
++) {
4418 check_EM_EXSETSEL(hwndRichEdit
, &exsetsel_tests
[i
], i
);
4421 DestroyWindow(hwndRichEdit
);
4424 static void test_EM_REPLACESEL(int redraw
)
4426 HWND hwndRichEdit
= new_richedit(NULL
);
4427 char buffer
[1024] = {0};
4432 /* sending some text to the window */
4433 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"testing selection");
4434 /* 01234567890123456*/
4437 /* FIXME add more tests */
4438 SendMessageA(hwndRichEdit
, EM_SETSEL
, 7, 17);
4439 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, 0);
4440 ok(0 == r
, "EM_REPLACESEL returned %d, expected 0\n", r
);
4441 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4442 r
= strcmp(buffer
, "testing");
4443 ok(0 == r
, "expected %d, got %d\n", 0, r
);
4445 DestroyWindow(hwndRichEdit
);
4447 hwndRichEdit
= new_richedit(NULL
);
4449 trace("Testing EM_REPLACESEL behavior with redraw=%d\n", redraw
);
4450 SendMessageA(hwndRichEdit
, WM_SETREDRAW
, redraw
, 0);
4452 /* Test behavior with carriage returns and newlines */
4453 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4454 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"RichEdit1");
4455 ok(9 == r
, "EM_REPLACESEL returned %d, expected 9\n", r
);
4456 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4457 r
= strcmp(buffer
, "RichEdit1");
4458 ok(0 == r
, "expected %d, got %d\n", 0, r
);
4460 getText
.codepage
= CP_ACP
;
4461 getText
.flags
= GT_DEFAULT
;
4462 getText
.lpDefaultChar
= NULL
;
4463 getText
.lpUsedDefChar
= NULL
;
4464 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4465 ok(strcmp(buffer
, "RichEdit1") == 0,
4466 "EM_GETTEXTEX results not what was set by EM_REPLACESEL\n");
4468 /* Test number of lines reported after EM_REPLACESEL */
4469 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4470 ok(r
== 1, "EM_GETLINECOUNT returned %d, expected 1\n", r
);
4472 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4473 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"RichEdit1\r");
4474 ok(10 == r
, "EM_REPLACESEL returned %d, expected 10\n", r
);
4475 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4476 r
= strcmp(buffer
, "RichEdit1\r\n");
4477 ok(0 == r
, "expected %d, got %d\n", 0, r
);
4479 getText
.codepage
= CP_ACP
;
4480 getText
.flags
= GT_DEFAULT
;
4481 getText
.lpDefaultChar
= NULL
;
4482 getText
.lpUsedDefChar
= NULL
;
4483 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4484 ok(strcmp(buffer
, "RichEdit1\r") == 0,
4485 "EM_GETTEXTEX returned incorrect string\n");
4487 /* Test number of lines reported after EM_REPLACESEL */
4488 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4489 ok(r
== 2, "EM_GETLINECOUNT returned %d, expected 2\n", r
);
4491 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4492 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"RichEdit1\r\n");
4493 ok(r
== 11, "EM_REPLACESEL returned %d, expected 11\n", r
);
4495 /* Test number of lines reported after EM_REPLACESEL */
4496 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4497 ok(r
== 2, "EM_GETLINECOUNT returned %d, expected 2\n", r
);
4499 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4500 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4501 ok(cr
.cpMin
== 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr
.cpMin
);
4502 ok(cr
.cpMax
== 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr
.cpMax
);
4504 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4505 r
= strcmp(buffer
, "RichEdit1\r\n");
4506 ok(0 == r
, "expected %d, got %d\n", 0, r
);
4508 getText
.codepage
= CP_ACP
;
4509 getText
.flags
= GT_DEFAULT
;
4510 getText
.lpDefaultChar
= NULL
;
4511 getText
.lpUsedDefChar
= NULL
;
4512 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4513 ok(strcmp(buffer
, "RichEdit1\r") == 0,
4514 "EM_GETTEXTEX returned incorrect string\n");
4516 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4517 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4518 ok(cr
.cpMin
== 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr
.cpMin
);
4519 ok(cr
.cpMax
== 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr
.cpMax
);
4521 /* The following tests show that richedit should handle the special \r\r\n
4522 sequence by turning it into a single space on insertion. However,
4523 EM_REPLACESEL on WinXP returns the number of characters in the original
4527 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4528 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r");
4529 ok(2 == r
, "EM_REPLACESEL returned %d, expected 4\n", r
);
4530 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4531 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4532 ok(cr
.cpMin
== 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr
.cpMin
);
4533 ok(cr
.cpMax
== 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr
.cpMax
);
4535 /* Test the actual string */
4537 getText
.codepage
= CP_ACP
;
4538 getText
.flags
= GT_DEFAULT
;
4539 getText
.lpDefaultChar
= NULL
;
4540 getText
.lpUsedDefChar
= NULL
;
4541 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4542 ok(strcmp(buffer
, "\r\r") == 0,
4543 "EM_GETTEXTEX returned incorrect string\n");
4545 /* Test number of lines reported after EM_REPLACESEL */
4546 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4547 ok(r
== 3, "EM_GETLINECOUNT returned %d, expected 3\n", r
);
4549 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4550 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r\n");
4551 ok(r
== 3, "EM_REPLACESEL returned %d, expected 3\n", r
);
4552 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4553 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4554 ok(cr
.cpMin
== 1, "EM_EXGETSEL returned cpMin=%d, expected 1\n", cr
.cpMin
);
4555 ok(cr
.cpMax
== 1, "EM_EXGETSEL returned cpMax=%d, expected 1\n", cr
.cpMax
);
4557 /* Test the actual string */
4559 getText
.codepage
= CP_ACP
;
4560 getText
.flags
= GT_DEFAULT
;
4561 getText
.lpDefaultChar
= NULL
;
4562 getText
.lpUsedDefChar
= NULL
;
4563 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4564 ok(strcmp(buffer
, " ") == 0,
4565 "EM_GETTEXTEX returned incorrect string\n");
4567 /* Test number of lines reported after EM_REPLACESEL */
4568 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4569 ok(r
== 1, "EM_GETLINECOUNT returned %d, expected 1\n", r
);
4571 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4572 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r\r\r\r\n\r\r\r");
4573 ok(r
== 9, "EM_REPLACESEL returned %d, expected 9\n", r
);
4574 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4575 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4576 ok(cr
.cpMin
== 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr
.cpMin
);
4577 ok(cr
.cpMax
== 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr
.cpMax
);
4579 /* Test the actual string */
4581 getText
.codepage
= CP_ACP
;
4582 getText
.flags
= GT_DEFAULT
;
4583 getText
.lpDefaultChar
= NULL
;
4584 getText
.lpUsedDefChar
= NULL
;
4585 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4586 ok(strcmp(buffer
, "\r\r\r \r\r\r") == 0,
4587 "EM_GETTEXTEX returned incorrect string\n");
4589 /* Test number of lines reported after EM_REPLACESEL */
4590 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4591 ok(r
== 7, "EM_GETLINECOUNT returned %d, expected 7\n", r
);
4593 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4594 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r\n\r\n");
4595 ok(r
== 5, "EM_REPLACESEL returned %d, expected 5\n", r
);
4596 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4597 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4598 ok(cr
.cpMin
== 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr
.cpMin
);
4599 ok(cr
.cpMax
== 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr
.cpMax
);
4601 /* Test the actual string */
4603 getText
.codepage
= CP_ACP
;
4604 getText
.flags
= GT_DEFAULT
;
4605 getText
.lpDefaultChar
= NULL
;
4606 getText
.lpUsedDefChar
= NULL
;
4607 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4608 ok(strcmp(buffer
, " \r") == 0,
4609 "EM_GETTEXTEX returned incorrect string\n");
4611 /* Test number of lines reported after EM_REPLACESEL */
4612 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4613 ok(r
== 2, "EM_GETLINECOUNT returned %d, expected 2\n", r
);
4615 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4616 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r\n\r\r");
4617 ok(r
== 5, "EM_REPLACESEL returned %d, expected 5\n", r
);
4618 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4619 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4620 ok(cr
.cpMin
== 3, "EM_EXGETSEL returned cpMin=%d, expected 3\n", cr
.cpMin
);
4621 ok(cr
.cpMax
== 3, "EM_EXGETSEL returned cpMax=%d, expected 3\n", cr
.cpMax
);
4623 /* Test the actual string */
4625 getText
.codepage
= CP_ACP
;
4626 getText
.flags
= GT_DEFAULT
;
4627 getText
.lpDefaultChar
= NULL
;
4628 getText
.lpUsedDefChar
= NULL
;
4629 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4630 ok(strcmp(buffer
, " \r\r") == 0,
4631 "EM_GETTEXTEX returned incorrect string\n");
4633 /* Test number of lines reported after EM_REPLACESEL */
4634 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4635 ok(r
== 3, "EM_GETLINECOUNT returned %d, expected 3\n", r
);
4637 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4638 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\rX\r\n\r\r");
4639 ok(r
== 6, "EM_REPLACESEL returned %d, expected 6\n", r
);
4640 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4641 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4642 ok(cr
.cpMin
== 5, "EM_EXGETSEL returned cpMin=%d, expected 5\n", cr
.cpMin
);
4643 ok(cr
.cpMax
== 5, "EM_EXGETSEL returned cpMax=%d, expected 5\n", cr
.cpMax
);
4645 /* Test the actual string */
4647 getText
.codepage
= CP_ACP
;
4648 getText
.flags
= GT_DEFAULT
;
4649 getText
.lpDefaultChar
= NULL
;
4650 getText
.lpUsedDefChar
= NULL
;
4651 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4652 ok(strcmp(buffer
, "\rX\r\r\r") == 0,
4653 "EM_GETTEXTEX returned incorrect string\n");
4655 /* Test number of lines reported after EM_REPLACESEL */
4656 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4657 ok(r
== 5, "EM_GETLINECOUNT returned %d, expected 5\n", r
);
4659 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4660 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\n\n");
4661 ok(2 == r
, "EM_REPLACESEL returned %d, expected 2\n", r
);
4662 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4663 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4664 ok(cr
.cpMin
== 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr
.cpMin
);
4665 ok(cr
.cpMax
== 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr
.cpMax
);
4667 /* Test the actual string */
4669 getText
.codepage
= CP_ACP
;
4670 getText
.flags
= GT_DEFAULT
;
4671 getText
.lpDefaultChar
= NULL
;
4672 getText
.lpUsedDefChar
= NULL
;
4673 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4674 ok(strcmp(buffer
, "\r\r") == 0,
4675 "EM_GETTEXTEX returned incorrect string\n");
4677 /* Test number of lines reported after EM_REPLACESEL */
4678 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4679 ok(r
== 3, "EM_GETLINECOUNT returned %d, expected 3\n", r
);
4681 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4682 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\n\n\n\n\r\r\r\r\n");
4683 ok(r
== 9, "EM_REPLACESEL returned %d, expected 9\n", r
);
4684 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4685 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4686 ok(cr
.cpMin
== 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr
.cpMin
);
4687 ok(cr
.cpMax
== 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr
.cpMax
);
4689 /* Test the actual string */
4691 getText
.codepage
= CP_ACP
;
4692 getText
.flags
= GT_DEFAULT
;
4693 getText
.lpDefaultChar
= NULL
;
4694 getText
.lpUsedDefChar
= NULL
;
4695 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4696 ok(strcmp(buffer
, "\r\r\r\r\r\r ") == 0,
4697 "EM_GETTEXTEX returned incorrect string\n");
4699 /* Test number of lines reported after EM_REPLACESEL */
4700 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4701 ok(r
== 7, "EM_GETLINECOUNT returned %d, expected 7\n", r
);
4704 /* This is needed to avoid interferring with keybd_event calls
4705 * on other tests that simulate keyboard events. */
4706 SendMessageA(hwndRichEdit
, WM_SETREDRAW
, TRUE
, 0);
4708 DestroyWindow(hwndRichEdit
);
4711 /* Native riched20 inspects the keyboard state (e.g. GetKeyState)
4712 * to test the state of the modifiers (Ctrl/Alt/Shift).
4714 * Therefore Ctrl-<key> keystrokes need to be simulated with
4715 * keybd_event or by using SetKeyboardState to set the modifiers
4716 * and SendMessage to simulate the keystrokes.
4718 static LRESULT
send_ctrl_key(HWND hwnd
, UINT key
)
4721 hold_key(VK_CONTROL
);
4722 result
= SendMessageA(hwnd
, WM_KEYDOWN
, key
, 1);
4723 release_key(VK_CONTROL
);
4727 static void test_WM_PASTE(void)
4730 char buffer
[1024] = {0};
4731 const char* text1
= "testing paste\r";
4732 const char* text1_step1
= "testing paste\r\ntesting paste\r\n";
4733 const char* text1_after
= "testing paste\r\n";
4734 const char* text2
= "testing paste\r\rtesting paste";
4735 const char* text2_after
= "testing paste\r\n\r\ntesting paste";
4736 const char* text3
= "testing paste\r\npaste\r\ntesting paste";
4737 HWND hwndRichEdit
= new_richedit(NULL
);
4739 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
4740 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 14);
4742 send_ctrl_key(hwndRichEdit
, 'C'); /* Copy */
4743 SendMessageA(hwndRichEdit
, EM_SETSEL
, 14, 14);
4744 send_ctrl_key(hwndRichEdit
, 'V'); /* Paste */
4745 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4746 /* Pasted text should be visible at this step */
4747 result
= strcmp(text1_step1
, buffer
);
4749 "test paste: strcmp = %i, text='%s'\n", result
, buffer
);
4751 send_ctrl_key(hwndRichEdit
, 'Z'); /* Undo */
4752 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4753 /* Text should be the same as before (except for \r -> \r\n conversion) */
4754 result
= strcmp(text1_after
, buffer
);
4756 "test paste: strcmp = %i, text='%s'\n", result
, buffer
);
4758 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
4759 SendMessageA(hwndRichEdit
, EM_SETSEL
, 8, 13);
4760 send_ctrl_key(hwndRichEdit
, 'C'); /* Copy */
4761 SendMessageA(hwndRichEdit
, EM_SETSEL
, 14, 14);
4762 send_ctrl_key(hwndRichEdit
, 'V'); /* Paste */
4763 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4764 /* Pasted text should be visible at this step */
4765 result
= strcmp(text3
, buffer
);
4767 "test paste: strcmp = %i\n", result
);
4768 send_ctrl_key(hwndRichEdit
, 'Z'); /* Undo */
4769 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4770 /* Text should be the same as before (except for \r -> \r\n conversion) */
4771 result
= strcmp(text2_after
, buffer
);
4773 "test paste: strcmp = %i\n", result
);
4774 send_ctrl_key(hwndRichEdit
, 'Y'); /* Redo */
4775 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4776 /* Text should revert to post-paste state */
4777 result
= strcmp(buffer
,text3
);
4779 "test paste: strcmp = %i\n", result
);
4781 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4782 /* Send WM_CHAR to simulate Ctrl-V */
4783 SendMessageA(hwndRichEdit
, WM_CHAR
, 22,
4784 (MapVirtualKeyA('V', MAPVK_VK_TO_VSC
) << 16) | 1);
4785 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4786 /* Shouldn't paste because pasting is handled by WM_KEYDOWN */
4787 result
= strcmp(buffer
,"");
4789 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4791 /* Send keystrokes with WM_KEYDOWN after setting the modifiers
4792 * with SetKeyboard state. */
4794 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4795 /* Simulates paste (Ctrl-V) */
4796 hold_key(VK_CONTROL
);
4797 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'V',
4798 (MapVirtualKeyA('V', MAPVK_VK_TO_VSC
) << 16) | 1);
4799 release_key(VK_CONTROL
);
4800 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4801 result
= strcmp(buffer
,"paste");
4803 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4805 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
4806 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 7);
4807 /* Simulates copy (Ctrl-C) */
4808 hold_key(VK_CONTROL
);
4809 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'C',
4810 (MapVirtualKeyA('C', MAPVK_VK_TO_VSC
) << 16) | 1);
4811 release_key(VK_CONTROL
);
4812 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4813 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
4814 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4815 result
= strcmp(buffer
,"testing");
4817 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4819 /* Cut with WM_KEYDOWN to simulate Ctrl-X */
4820 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"cut");
4821 /* Simulates select all (Ctrl-A) */
4822 hold_key(VK_CONTROL
);
4823 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'A',
4824 (MapVirtualKeyA('A', MAPVK_VK_TO_VSC
) << 16) | 1);
4825 /* Simulates select cut (Ctrl-X) */
4826 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'X',
4827 (MapVirtualKeyA('X', MAPVK_VK_TO_VSC
) << 16) | 1);
4828 release_key(VK_CONTROL
);
4829 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4830 result
= strcmp(buffer
,"");
4832 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4833 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4834 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
4835 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4836 result
= strcmp(buffer
,"cut\r\n");
4837 todo_wine
ok(result
== 0,
4838 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4839 /* Simulates undo (Ctrl-Z) */
4840 hold_key(VK_CONTROL
);
4841 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'Z',
4842 (MapVirtualKeyA('Z', MAPVK_VK_TO_VSC
) << 16) | 1);
4843 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4844 result
= strcmp(buffer
,"");
4846 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4847 /* Simulates redo (Ctrl-Y) */
4848 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'Y',
4849 (MapVirtualKeyA('Y', MAPVK_VK_TO_VSC
) << 16) | 1);
4850 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4851 result
= strcmp(buffer
,"cut\r\n");
4852 todo_wine
ok(result
== 0,
4853 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4854 release_key(VK_CONTROL
);
4856 DestroyWindow(hwndRichEdit
);
4859 static void test_EM_FORMATRANGE(void)
4861 int r
, i
, tpp_x
, tpp_y
;
4863 HWND hwndRichEdit
= new_richedit(NULL
);
4865 BOOL skip_non_english
;
4866 static const struct {
4867 const char *string
; /* The string */
4868 int first
; /* First 'pagebreak', 0 for don't care */
4869 int second
; /* Second 'pagebreak', 0 for don't care */
4871 {"WINE wine", 0, 0},
4872 {"WINE wineWine", 0, 0},
4873 {"WINE\r\nwine\r\nwine", 5, 10},
4874 {"WINE\r\nWINEwine\r\nWINEwine", 5, 14},
4875 {"WINE\r\n\r\nwine\r\nwine", 5, 6}
4878 skip_non_english
= (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH
);
4879 if (skip_non_english
)
4880 skip("Skipping some tests on non-English platform\n");
4882 hdc
= GetDC(hwndRichEdit
);
4883 ok(hdc
!= NULL
, "Could not get HDC\n");
4885 /* Calculate the twips per pixel */
4886 tpp_x
= 1440 / GetDeviceCaps(hdc
, LOGPIXELSX
);
4887 tpp_y
= 1440 / GetDeviceCaps(hdc
, LOGPIXELSY
);
4889 /* Test the simple case where all the text fits in the page rect. */
4890 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
4891 fr
.hdc
= fr
.hdcTarget
= hdc
;
4892 fr
.rc
.top
= fr
.rcPage
.top
= fr
.rc
.left
= fr
.rcPage
.left
= 0;
4893 fr
.rc
.right
= fr
.rcPage
.right
= 500 * tpp_x
;
4894 fr
.rc
.bottom
= fr
.rcPage
.bottom
= 500 * tpp_y
;
4897 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, FALSE
, (LPARAM
)&fr
);
4898 todo_wine
ok(r
== 2, "r=%d expected r=2\n", r
);
4900 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"ab");
4901 fr
.rc
.bottom
= fr
.rcPage
.bottom
;
4902 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, FALSE
, (LPARAM
)&fr
);
4903 todo_wine
ok(r
== 3, "r=%d expected r=3\n", r
);
4905 SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, FALSE
, 0);
4907 for (i
= 0; i
< sizeof(fmtstrings
)/sizeof(fmtstrings
[0]); i
++)
4909 GETTEXTLENGTHEX gtl
;
4913 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)fmtstrings
[i
].string
);
4915 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
4916 gtl
.codepage
= CP_ACP
;
4917 len
= SendMessageA(hwndRichEdit
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
4919 /* Get some size information for the string */
4920 GetTextExtentPoint32A(hdc
, fmtstrings
[i
].string
, strlen(fmtstrings
[i
].string
), &stringsize
);
4922 /* Define the box to be half the width needed and a bit larger than the height.
4923 * Changes to the width means we have at least 2 pages. Changes to the height
4924 * is done so we can check the changing of fr.rc.bottom.
4926 fr
.hdc
= fr
.hdcTarget
= hdc
;
4927 fr
.rc
.top
= fr
.rcPage
.top
= fr
.rc
.left
= fr
.rcPage
.left
= 0;
4928 fr
.rc
.right
= fr
.rcPage
.right
= (stringsize
.cx
/ 2) * tpp_x
;
4929 fr
.rc
.bottom
= fr
.rcPage
.bottom
= (stringsize
.cy
+ 10) * tpp_y
;
4931 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, 0);
4933 ok(r
== len
, "Expected %d, got %d\n", len
, r
);
4936 /* We know that the page can't hold the full string. See how many characters
4937 * are on the first one
4941 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, (LPARAM
)&fr
);
4943 if (! skip_non_english
)
4944 ok(fr
.rc
.bottom
== (stringsize
.cy
* tpp_y
), "Expected bottom to be %d, got %d\n", (stringsize
.cy
* tpp_y
), fr
.rc
.bottom
);
4946 if (fmtstrings
[i
].first
)
4948 ok(r
== fmtstrings
[i
].first
, "Expected %d, got %d\n", fmtstrings
[i
].first
, r
);
4951 ok(r
< len
, "Expected < %d, got %d\n", len
, r
);
4953 /* Do another page */
4955 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, (LPARAM
)&fr
);
4956 if (fmtstrings
[i
].second
)
4958 ok(r
== fmtstrings
[i
].second
, "Expected %d, got %d\n", fmtstrings
[i
].second
, r
);
4960 else if (! skip_non_english
)
4961 ok (r
< len
, "Expected < %d, got %d\n", len
, r
);
4963 /* There is at least on more page, but we don't care */
4965 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, 0);
4967 ok(r
== len
, "Expected %d, got %d\n", len
, r
);
4971 ReleaseDC(NULL
, hdc
);
4972 DestroyWindow(hwndRichEdit
);
4975 static int nCallbackCount
= 0;
4977 static DWORD CALLBACK
EditStreamCallback(DWORD_PTR dwCookie
, LPBYTE pbBuff
,
4980 const char text
[] = {'t','e','s','t'};
4982 if (sizeof(text
) <= cb
)
4984 if ((int)dwCookie
!= nCallbackCount
)
4990 memcpy (pbBuff
, text
, sizeof(text
));
4991 *pcb
= sizeof(text
);
4998 return 1; /* indicates callback failed */
5001 static DWORD CALLBACK
test_EM_STREAMIN_esCallback(DWORD_PTR dwCookie
,
5006 const char** str
= (const char**)dwCookie
;
5007 int size
= strlen(*str
);
5013 memcpy(pbBuff
, *str
, *pcb
);
5019 static DWORD CALLBACK
test_EM_STREAMIN_esCallback_UTF8Split(DWORD_PTR dwCookie
,
5024 DWORD
*phase
= (DWORD
*)dwCookie
;
5027 static const char first
[] = "\xef\xbb\xbf\xc3\x96\xc3";
5028 *pcb
= sizeof(first
) - 1;
5029 memcpy(pbBuff
, first
, *pcb
);
5030 }else if(*phase
== 1){
5031 static const char second
[] = "\x8f\xc3\x8b";
5032 *pcb
= sizeof(second
) - 1;
5033 memcpy(pbBuff
, second
, *pcb
);
5042 struct StringWithLength
{
5047 /* This callback is used to handled the null characters in a string. */
5048 static DWORD CALLBACK
test_EM_STREAMIN_esCallback2(DWORD_PTR dwCookie
,
5053 struct StringWithLength
* str
= (struct StringWithLength
*)dwCookie
;
5054 int size
= str
->length
;
5060 memcpy(pbBuff
, str
->buffer
, *pcb
);
5061 str
->buffer
+= *pcb
;
5062 str
->length
-= *pcb
;
5067 static void test_EM_STREAMIN(void)
5069 HWND hwndRichEdit
= new_richedit(NULL
);
5073 char buffer
[1024] = {0};
5075 const char * streamText0
= "{\\rtf1 TestSomeText}";
5076 const char * streamText0a
= "{\\rtf1 TestSomeText\\par}";
5077 const char * streamText0b
= "{\\rtf1 TestSomeText\\par\\par}";
5079 const char * streamText1
=
5080 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n"
5081 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n"
5084 /* In richedit 2.0 mode, this should NOT be accepted, unlike 1.0 */
5085 const char * streamText2
=
5086 "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;"
5087 "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255"
5088 "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 "
5089 "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 "
5090 "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 "
5091 "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 "
5092 "\\tx11448 \\tx11872 \\tx12296 \\tx12720 \\tx13144 \\cf2 RichEdit1\\line }";
5094 const char * streamText3
= "RichEdit1";
5096 const char * streamTextUTF8BOM
= "\xef\xbb\xbfTestUTF8WithBOM";
5098 const char * streamText4
=
5099 "This text just needs to be long enough to cause run to be split onto "
5100 "two separate lines and make sure the null terminating character is "
5101 "handled properly.\0";
5102 int length4
= strlen(streamText4
) + 1;
5103 struct StringWithLength cookieForStream4
= {
5105 (char *)streamText4
,
5108 const WCHAR streamText5
[] = { 'T', 'e', 's', 't', 'S', 'o', 'm', 'e', 'T', 'e', 'x', 't' };
5109 int length5
= sizeof(streamText5
) / sizeof(WCHAR
);
5110 struct StringWithLength cookieForStream5
= {
5111 sizeof(streamText5
),
5112 (char *)streamText5
,
5115 /* Minimal test without \par at the end */
5116 es
.dwCookie
= (DWORD_PTR
)&streamText0
;
5118 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5119 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5120 ok(result
== 12, "got %ld, expected %d\n", result
, 12);
5122 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5124 "EM_STREAMIN: Test 0 returned %ld, expected 12\n", result
);
5125 result
= strcmp (buffer
,"TestSomeText");
5127 "EM_STREAMIN: Test 0 set wrong text: Result: %s\n",buffer
);
5128 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es
.dwError
, 0);
5130 /* Native richedit 2.0 ignores last \par */
5131 es
.dwCookie
= (DWORD_PTR
)&streamText0a
;
5133 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5134 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5135 ok(result
== 12, "got %ld, expected %d\n", result
, 12);
5137 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5139 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result
);
5140 result
= strcmp (buffer
,"TestSomeText");
5142 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer
);
5143 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0-a set error %d, expected %d\n", es
.dwError
, 0);
5145 /* Native richedit 2.0 ignores last \par, next-to-last \par appears */
5146 es
.dwCookie
= (DWORD_PTR
)&streamText0b
;
5148 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5149 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5150 ok(result
== 13, "got %ld, expected %d\n", result
, 13);
5152 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5154 "EM_STREAMIN: Test 0-b returned %ld, expected 14\n", result
);
5155 result
= strcmp (buffer
,"TestSomeText\r\n");
5157 "EM_STREAMIN: Test 0-b set wrong text: Result: %s\n",buffer
);
5158 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0-b set error %d, expected %d\n", es
.dwError
, 0);
5160 es
.dwCookie
= (DWORD_PTR
)&streamText1
;
5162 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5163 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5164 ok(result
== 12, "got %ld, expected %d\n", result
, 12);
5166 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5168 "EM_STREAMIN: Test 1 returned %ld, expected 12\n", result
);
5169 result
= strcmp (buffer
,"TestSomeText");
5171 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer
);
5172 ok(es
.dwError
== 0, "EM_STREAMIN: Test 1 set error %d, expected %d\n", es
.dwError
, 0);
5174 es
.dwCookie
= (DWORD_PTR
)&streamText2
;
5176 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5177 ok(result
== 0, "got %ld, expected %d\n", result
, 0);
5179 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5181 "EM_STREAMIN: Test 2 returned %ld, expected 0\n", result
);
5182 ok (strlen(buffer
) == 0,
5183 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
5184 ok(es
.dwError
== -16, "EM_STREAMIN: Test 2 set error %d, expected %d\n", es
.dwError
, -16);
5186 es
.dwCookie
= (DWORD_PTR
)&streamText3
;
5188 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5189 ok(result
== 0, "got %ld, expected %d\n", result
, 0);
5191 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5193 "EM_STREAMIN: Test 3 returned %ld, expected 0\n", result
);
5194 ok (strlen(buffer
) == 0,
5195 "EM_STREAMIN: Test 3 set wrong text: Result: %s\n",buffer
);
5196 ok(es
.dwError
== -16, "EM_STREAMIN: Test 3 set error %d, expected %d\n", es
.dwError
, -16);
5198 es
.dwCookie
= (DWORD_PTR
)&streamTextUTF8BOM
;
5200 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5201 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
5202 ok(result
== 18, "got %ld, expected %d\n", result
, 18);
5204 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5206 "EM_STREAMIN: Test UTF8WithBOM returned %ld, expected 15\n", result
);
5207 result
= strcmp (buffer
,"TestUTF8WithBOM");
5209 "EM_STREAMIN: Test UTF8WithBOM set wrong text: Result: %s\n",buffer
);
5210 ok(es
.dwError
== 0, "EM_STREAMIN: Test UTF8WithBOM set error %d, expected %d\n", es
.dwError
, 0);
5213 es
.dwCookie
= (DWORD_PTR
)&phase
;
5215 es
.pfnCallback
= test_EM_STREAMIN_esCallback_UTF8Split
;
5216 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
5217 ok(result
== 8, "got %ld\n", result
);
5219 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5221 "EM_STREAMIN: Test UTF8Split returned %ld\n", result
);
5222 result
= memcmp (buffer
,"\xd6\xcf\xcb", 3);
5224 "EM_STREAMIN: Test UTF8Split set wrong text: Result: %s\n",buffer
);
5225 ok(es
.dwError
== 0, "EM_STREAMIN: Test UTF8Split set error %d, expected %d\n", es
.dwError
, 0);
5227 es
.dwCookie
= (DWORD_PTR
)&cookieForStream4
;
5229 es
.pfnCallback
= test_EM_STREAMIN_esCallback2
;
5230 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
5231 ok(result
== length4
, "got %ld, expected %d\n", result
, length4
);
5233 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5234 ok (result
== length4
,
5235 "EM_STREAMIN: Test 4 returned %ld, expected %d\n", result
, length4
);
5236 ok(es
.dwError
== 0, "EM_STREAMIN: Test 4 set error %d, expected %d\n", es
.dwError
, 0);
5238 es
.dwCookie
= (DWORD_PTR
)&cookieForStream5
;
5240 es
.pfnCallback
= test_EM_STREAMIN_esCallback2
;
5241 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
| SF_UNICODE
, (LPARAM
)&es
);
5242 ok(result
== sizeof(streamText5
), "got %ld, expected %u\n", result
, (UINT
)sizeof(streamText5
));
5244 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5245 ok (result
== length5
,
5246 "EM_STREAMIN: Test 5 returned %ld, expected %d\n", result
, length5
);
5247 ok(es
.dwError
== 0, "EM_STREAMIN: Test 5 set error %d, expected %d\n", es
.dwError
, 0);
5249 DestroyWindow(hwndRichEdit
);
5252 static void test_EM_StreamIn_Undo(void)
5254 /* The purpose of this test is to determine when a EM_StreamIn should be
5255 * undoable. This is important because WM_PASTE currently uses StreamIn and
5256 * pasting should always be undoable but streaming isn't always.
5259 * StreamIn plain text without SFF_SELECTION.
5260 * StreamIn plain text with SFF_SELECTION set but a zero-length selection
5261 * StreamIn plain text with SFF_SELECTION and a valid, normal selection
5262 * StreamIn plain text with SFF_SELECTION and a backwards-selection (from>to)
5263 * Feel free to add tests for other text modes or StreamIn things.
5267 HWND hwndRichEdit
= new_richedit(NULL
);
5270 char buffer
[1024] = {0};
5271 const char randomtext
[] = "Some text";
5273 es
.pfnCallback
= EditStreamCallback
;
5275 /* StreamIn, no SFF_SELECTION */
5276 es
.dwCookie
= nCallbackCount
;
5277 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
5278 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)randomtext
);
5279 SendMessageA(hwndRichEdit
, EM_SETSEL
,0,0);
5280 SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
5281 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5282 result
= strcmp (buffer
,"test");
5284 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer
);
5286 result
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
5287 ok (result
== FALSE
,
5288 "EM_STREAMIN without SFF_SELECTION wrongly allows undo\n");
5290 /* StreamIn, SFF_SELECTION, but nothing selected */
5291 es
.dwCookie
= nCallbackCount
;
5292 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
5293 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)randomtext
);
5294 SendMessageA(hwndRichEdit
, EM_SETSEL
,0,0);
5295 SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
|SFF_SELECTION
, (LPARAM
)&es
);
5296 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5297 result
= strcmp (buffer
,"testSome text");
5299 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
5301 result
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
5303 "EM_STREAMIN with SFF_SELECTION but no selection set "
5304 "should create an undo\n");
5306 /* StreamIn, SFF_SELECTION, with a selection */
5307 es
.dwCookie
= nCallbackCount
;
5308 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
5309 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)randomtext
);
5310 SendMessageA(hwndRichEdit
, EM_SETSEL
,4,5);
5311 SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
|SFF_SELECTION
, (LPARAM
)&es
);
5312 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5313 result
= strcmp (buffer
,"Sometesttext");
5315 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
5317 result
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
5319 "EM_STREAMIN with SFF_SELECTION and selection set "
5320 "should create an undo\n");
5322 DestroyWindow(hwndRichEdit
);
5325 static BOOL
is_em_settextex_supported(HWND hwnd
)
5327 SETTEXTEX stex
= { ST_DEFAULT
, CP_ACP
};
5328 return SendMessageA(hwnd
, EM_SETTEXTEX
, (WPARAM
)&stex
, 0) != 0;
5331 static void test_unicode_conversions(void)
5333 static const WCHAR tW
[] = {'t',0};
5334 static const WCHAR teW
[] = {'t','e',0};
5335 static const WCHAR textW
[] = {'t','e','s','t',0};
5336 static const char textA
[] = "test";
5340 int em_settextex_supported
, ret
;
5342 #define set_textA(hwnd, wm_set_text, txt) \
5344 SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; \
5345 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
5346 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
5347 ret = SendMessageA(hwnd, wm_set_text, wparam, (LPARAM)txt); \
5348 ok(ret, "SendMessageA(%02x) error %u\n", wm_set_text, GetLastError()); \
5350 #define expect_textA(hwnd, wm_get_text, txt) \
5352 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
5353 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
5354 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
5355 memset(bufA, 0xAA, sizeof(bufA)); \
5356 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
5357 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
5358 ret = lstrcmpA(bufA, txt); \
5359 ok(!ret, "%02x: strings do not match: expected %s got %s\n", wm_get_text, txt, bufA); \
5362 #define set_textW(hwnd, wm_set_text, txt) \
5364 SETTEXTEX stex = { ST_DEFAULT, 1200 }; \
5365 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
5366 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
5367 ret = SendMessageW(hwnd, wm_set_text, wparam, (LPARAM)txt); \
5368 ok(ret, "SendMessageW(%02x) error %u\n", wm_set_text, GetLastError()); \
5370 #define expect_textW(hwnd, wm_get_text, txt) \
5372 GETTEXTEX gtex = { 64, GT_DEFAULT, 1200, NULL, NULL }; \
5373 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
5374 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
5375 memset(bufW, 0xAA, sizeof(bufW)); \
5376 ret = SendMessageW(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
5377 ok(ret, "SendMessageW(%02x) error %u\n", wm_get_text, GetLastError()); \
5378 ret = lstrcmpW(bufW, txt); \
5379 ok(!ret, "%02x: strings do not match: expected[0] %x got[0] %x\n", wm_get_text, txt[0], bufW[0]); \
5381 #define expect_empty(hwnd, wm_get_text) \
5383 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
5384 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
5385 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
5386 memset(bufA, 0xAA, sizeof(bufA)); \
5387 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
5388 ok(!ret, "empty richedit should return 0, got %d\n", ret); \
5389 ok(!*bufA, "empty richedit should return empty string, got %s\n", bufA); \
5392 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
,
5393 0, 0, 200, 60, 0, 0, 0, 0);
5394 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5396 ret
= IsWindowUnicode(hwnd
);
5397 ok(ret
, "RichEdit20W should be unicode under NT\n");
5399 /* EM_SETTEXTEX is supported starting from version 3.0 */
5400 em_settextex_supported
= is_em_settextex_supported(hwnd
);
5401 trace("EM_SETTEXTEX is %ssupported on this platform\n",
5402 em_settextex_supported
? "" : "NOT ");
5404 expect_empty(hwnd
, WM_GETTEXT
);
5405 expect_empty(hwnd
, EM_GETTEXTEX
);
5407 ret
= SendMessageA(hwnd
, WM_CHAR
, textW
[0], 0);
5408 ok(!ret
, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret
);
5409 expect_textA(hwnd
, WM_GETTEXT
, "t");
5410 expect_textA(hwnd
, EM_GETTEXTEX
, "t");
5411 expect_textW(hwnd
, EM_GETTEXTEX
, tW
);
5413 ret
= SendMessageA(hwnd
, WM_CHAR
, textA
[1], 0);
5414 ok(!ret
, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret
);
5415 expect_textA(hwnd
, WM_GETTEXT
, "te");
5416 expect_textA(hwnd
, EM_GETTEXTEX
, "te");
5417 expect_textW(hwnd
, EM_GETTEXTEX
, teW
);
5419 set_textA(hwnd
, WM_SETTEXT
, NULL
);
5420 expect_empty(hwnd
, WM_GETTEXT
);
5421 expect_empty(hwnd
, EM_GETTEXTEX
);
5423 set_textA(hwnd
, WM_SETTEXT
, textA
);
5424 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5425 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5426 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5428 if (em_settextex_supported
)
5430 set_textA(hwnd
, EM_SETTEXTEX
, textA
);
5431 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5432 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5433 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5436 set_textW(hwnd
, WM_SETTEXT
, textW
);
5437 expect_textW(hwnd
, WM_GETTEXT
, textW
);
5438 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5439 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5440 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5442 if (em_settextex_supported
)
5444 set_textW(hwnd
, EM_SETTEXTEX
, textW
);
5445 expect_textW(hwnd
, WM_GETTEXT
, textW
);
5446 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5447 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5448 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5450 DestroyWindow(hwnd
);
5452 hwnd
= CreateWindowExA(0, "RichEdit20A", NULL
, WS_POPUP
,
5453 0, 0, 200, 60, 0, 0, 0, 0);
5454 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5456 ret
= IsWindowUnicode(hwnd
);
5457 ok(!ret
, "RichEdit20A should NOT be unicode\n");
5459 set_textA(hwnd
, WM_SETTEXT
, textA
);
5460 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5461 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5462 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5464 if (em_settextex_supported
)
5466 set_textA(hwnd
, EM_SETTEXTEX
, textA
);
5467 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5468 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5469 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5472 set_textW(hwnd
, WM_SETTEXT
, textW
);
5473 expect_textW(hwnd
, WM_GETTEXT
, textW
);
5474 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5475 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5476 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5478 if (em_settextex_supported
)
5480 set_textW(hwnd
, EM_SETTEXTEX
, textW
);
5481 expect_textW(hwnd
, WM_GETTEXT
, textW
);
5482 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5483 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5484 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5486 DestroyWindow(hwnd
);
5489 static void test_WM_CHAR(void)
5493 const char * char_list
= "abc\rabc\r";
5494 const char * expected_content_single
= "abcabc";
5495 const char * expected_content_multi
= "abc\r\nabc\r\n";
5496 char buffer
[64] = {0};
5499 /* single-line control must IGNORE carriage returns */
5500 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
,
5501 0, 0, 200, 60, 0, 0, 0, 0);
5502 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5505 while (*p
!= '\0') {
5506 SendMessageA(hwnd
, WM_KEYDOWN
, *p
, 1);
5507 ret
= SendMessageA(hwnd
, WM_CHAR
, *p
, 1);
5508 ok(ret
== 0, "WM_CHAR('%c') ret=%d\n", *p
, ret
);
5509 SendMessageA(hwnd
, WM_KEYUP
, *p
, 1);
5513 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5514 ret
= strcmp(buffer
, expected_content_single
);
5515 ok(ret
== 0, "WM_GETTEXT recovered incorrect string!\n");
5517 DestroyWindow(hwnd
);
5519 /* multi-line control inserts CR normally */
5520 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
|ES_MULTILINE
,
5521 0, 0, 200, 60, 0, 0, 0, 0);
5522 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5525 while (*p
!= '\0') {
5526 SendMessageA(hwnd
, WM_KEYDOWN
, *p
, 1);
5527 ret
= SendMessageA(hwnd
, WM_CHAR
, *p
, 1);
5528 ok(ret
== 0, "WM_CHAR('%c') ret=%d\n", *p
, ret
);
5529 SendMessageA(hwnd
, WM_KEYUP
, *p
, 1);
5533 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5534 ret
= strcmp(buffer
, expected_content_multi
);
5535 ok(ret
== 0, "WM_GETTEXT recovered incorrect string!\n");
5537 DestroyWindow(hwnd
);
5540 static void test_EM_GETTEXTLENGTHEX(void)
5543 GETTEXTLENGTHEX gtl
;
5545 const char * base_string
= "base string";
5546 const char * test_string
= "a\nb\n\n\r\n";
5547 const char * test_string_after
= "a";
5548 const char * test_string_2
= "a\rtest\rstring";
5549 char buffer
[64] = {0};
5552 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
,
5553 0, 0, 200, 60, 0, 0, 0, 0);
5554 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5556 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5557 gtl
.codepage
= CP_ACP
;
5558 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5559 ok(ret
== 0, "ret %d\n",ret
);
5561 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5562 gtl
.codepage
= CP_ACP
;
5563 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5564 ok(ret
== 0, "ret %d\n",ret
);
5566 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)base_string
);
5568 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5569 gtl
.codepage
= CP_ACP
;
5570 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5571 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
5573 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5574 gtl
.codepage
= CP_ACP
;
5575 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5576 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
5578 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)test_string
);
5580 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5581 gtl
.codepage
= CP_ACP
;
5582 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5583 ok(ret
== 1, "ret %d\n",ret
);
5585 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5586 gtl
.codepage
= CP_ACP
;
5587 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5588 ok(ret
== 1, "ret %d\n",ret
);
5590 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5591 ret
= strcmp(buffer
, test_string_after
);
5592 ok(ret
== 0, "WM_GETTEXT recovered incorrect string!\n");
5594 DestroyWindow(hwnd
);
5597 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
| ES_MULTILINE
,
5598 0, 0, 200, 60, 0, 0, 0, 0);
5599 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5601 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5602 gtl
.codepage
= CP_ACP
;
5603 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5604 ok(ret
== 0, "ret %d\n",ret
);
5606 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5607 gtl
.codepage
= CP_ACP
;
5608 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5609 ok(ret
== 0, "ret %d\n",ret
);
5611 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)base_string
);
5613 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5614 gtl
.codepage
= CP_ACP
;
5615 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5616 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
5618 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5619 gtl
.codepage
= CP_ACP
;
5620 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5621 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
5623 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)test_string_2
);
5625 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5626 gtl
.codepage
= CP_ACP
;
5627 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5628 ok(ret
== strlen(test_string_2
) + 2, "ret %d\n",ret
);
5630 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5631 gtl
.codepage
= CP_ACP
;
5632 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5633 ok(ret
== strlen(test_string_2
), "ret %d\n",ret
);
5635 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)test_string
);
5637 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5638 gtl
.codepage
= CP_ACP
;
5639 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5640 ok(ret
== 10, "ret %d\n",ret
);
5642 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5643 gtl
.codepage
= CP_ACP
;
5644 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5645 ok(ret
== 6, "ret %d\n",ret
);
5647 /* Unicode/NUMCHARS/NUMBYTES */
5648 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)test_string_2
);
5650 gtl
.flags
= GTL_DEFAULT
;
5651 gtl
.codepage
= 1200;
5652 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5653 ok(ret
== lstrlenA(test_string_2
),
5654 "GTL_DEFAULT gave %i, expected %i\n", ret
, lstrlenA(test_string_2
));
5656 gtl
.flags
= GTL_NUMCHARS
;
5657 gtl
.codepage
= 1200;
5658 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5659 ok(ret
== lstrlenA(test_string_2
),
5660 "GTL_NUMCHARS gave %i, expected %i\n", ret
, lstrlenA(test_string_2
));
5662 gtl
.flags
= GTL_NUMBYTES
;
5663 gtl
.codepage
= 1200;
5664 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5665 ok(ret
== lstrlenA(test_string_2
)*2,
5666 "GTL_NUMBYTES gave %i, expected %i\n", ret
, lstrlenA(test_string_2
)*2);
5668 gtl
.flags
= GTL_PRECISE
;
5669 gtl
.codepage
= 1200;
5670 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5671 ok(ret
== lstrlenA(test_string_2
)*2,
5672 "GTL_PRECISE gave %i, expected %i\n", ret
, lstrlenA(test_string_2
)*2);
5674 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5675 gtl
.codepage
= 1200;
5676 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5677 ok(ret
== lstrlenA(test_string_2
),
5678 "GTL_NUMCHAR | GTL_PRECISE gave %i, expected %i\n", ret
, lstrlenA(test_string_2
));
5680 gtl
.flags
= GTL_NUMCHARS
| GTL_NUMBYTES
;
5681 gtl
.codepage
= 1200;
5682 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5683 ok(ret
== E_INVALIDARG
,
5684 "GTL_NUMCHARS | GTL_NUMBYTES gave %i, expected %i\n", ret
, E_INVALIDARG
);
5686 DestroyWindow(hwnd
);
5690 /* globals that parent and child access when checking event masks & notifications */
5691 static HWND eventMaskEditHwnd
= 0;
5692 static int queriedEventMask
;
5693 static int watchForEventMask
= 0;
5695 /* parent proc that queries the edit's event mask when it gets a WM_COMMAND */
5696 static LRESULT WINAPI
ParentMsgCheckProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
5698 if(message
== WM_COMMAND
&& (watchForEventMask
& (wParam
>> 16)))
5700 queriedEventMask
= SendMessageA(eventMaskEditHwnd
, EM_GETEVENTMASK
, 0, 0);
5702 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
5705 /* test event masks in combination with WM_COMMAND */
5706 static void test_eventMask(void)
5711 const char text
[] = "foo bar\n";
5714 /* register class to capture WM_COMMAND */
5716 cls
.lpfnWndProc
= ParentMsgCheckProcA
;
5719 cls
.hInstance
= GetModuleHandleA(0);
5721 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
5722 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
5723 cls
.lpszMenuName
= NULL
;
5724 cls
.lpszClassName
= "EventMaskParentClass";
5725 if(!RegisterClassA(&cls
)) assert(0);
5727 parent
= CreateWindowA(cls
.lpszClassName
, NULL
, WS_POPUP
|WS_VISIBLE
,
5728 0, 0, 200, 60, NULL
, NULL
, NULL
, NULL
);
5729 ok (parent
!= 0, "Failed to create parent window\n");
5731 eventMaskEditHwnd
= new_richedit(parent
);
5732 ok(eventMaskEditHwnd
!= 0, "Failed to create edit window\n");
5734 eventMask
= ENM_CHANGE
| ENM_UPDATE
;
5735 ret
= SendMessageA(eventMaskEditHwnd
, EM_SETEVENTMASK
, 0, eventMask
);
5736 ok(ret
== ENM_NONE
, "wrong event mask\n");
5737 ret
= SendMessageA(eventMaskEditHwnd
, EM_GETEVENTMASK
, 0, 0);
5738 ok(ret
== eventMask
, "failed to set event mask\n");
5740 /* check what happens when we ask for EN_CHANGE and send WM_SETTEXT */
5741 queriedEventMask
= 0; /* initialize to something other than we expect */
5742 watchForEventMask
= EN_CHANGE
;
5743 ret
= SendMessageA(eventMaskEditHwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
5744 ok(ret
== TRUE
, "failed to set text\n");
5745 /* richedit should mask off ENM_CHANGE when it sends an EN_CHANGE
5746 notification in response to WM_SETTEXT */
5747 ok(queriedEventMask
== (eventMask
& ~ENM_CHANGE
),
5748 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
5750 /* check to see if EN_CHANGE is sent when redraw is turned off */
5751 SendMessageA(eventMaskEditHwnd
, WM_CLEAR
, 0, 0);
5752 ok(IsWindowVisible(eventMaskEditHwnd
), "Window should be visible.\n");
5753 SendMessageA(eventMaskEditHwnd
, WM_SETREDRAW
, FALSE
, 0);
5754 /* redraw is disabled by making the window invisible. */
5755 ok(!IsWindowVisible(eventMaskEditHwnd
), "Window shouldn't be visible.\n");
5756 queriedEventMask
= 0; /* initialize to something other than we expect */
5757 SendMessageA(eventMaskEditHwnd
, EM_REPLACESEL
, 0, (LPARAM
)text
);
5758 ok(queriedEventMask
== (eventMask
& ~ENM_CHANGE
),
5759 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
5760 SendMessageA(eventMaskEditHwnd
, WM_SETREDRAW
, TRUE
, 0);
5761 ok(IsWindowVisible(eventMaskEditHwnd
), "Window should be visible.\n");
5763 /* check to see if EN_UPDATE is sent when the editor isn't visible */
5764 SendMessageA(eventMaskEditHwnd
, WM_CLEAR
, 0, 0);
5765 style
= GetWindowLongA(eventMaskEditHwnd
, GWL_STYLE
);
5766 SetWindowLongA(eventMaskEditHwnd
, GWL_STYLE
, style
& ~WS_VISIBLE
);
5767 ok(!IsWindowVisible(eventMaskEditHwnd
), "Window shouldn't be visible.\n");
5768 watchForEventMask
= EN_UPDATE
;
5769 queriedEventMask
= 0; /* initialize to something other than we expect */
5770 SendMessageA(eventMaskEditHwnd
, EM_REPLACESEL
, 0, (LPARAM
)text
);
5771 ok(queriedEventMask
== 0,
5772 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
5773 SetWindowLongA(eventMaskEditHwnd
, GWL_STYLE
, style
);
5774 ok(IsWindowVisible(eventMaskEditHwnd
), "Window should be visible.\n");
5775 queriedEventMask
= 0; /* initialize to something other than we expect */
5776 SendMessageA(eventMaskEditHwnd
, EM_REPLACESEL
, 0, (LPARAM
)text
);
5777 ok(queriedEventMask
== eventMask
,
5778 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
5781 DestroyWindow(parent
);
5784 static int received_WM_NOTIFY
= 0;
5785 static int modify_at_WM_NOTIFY
= 0;
5786 static BOOL filter_on_WM_NOTIFY
= FALSE
;
5787 static HWND hwndRichedit_WM_NOTIFY
;
5789 static LRESULT WINAPI
WM_NOTIFY_ParentMsgCheckProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
5791 if(message
== WM_NOTIFY
)
5793 received_WM_NOTIFY
= 1;
5794 modify_at_WM_NOTIFY
= SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETMODIFY
, 0, 0);
5795 if (filter_on_WM_NOTIFY
) return TRUE
;
5797 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
5800 static void test_WM_NOTIFY(void)
5805 int sel_start
, sel_end
;
5807 /* register class to capture WM_NOTIFY */
5809 cls
.lpfnWndProc
= WM_NOTIFY_ParentMsgCheckProcA
;
5812 cls
.hInstance
= GetModuleHandleA(0);
5814 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
5815 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
5816 cls
.lpszMenuName
= NULL
;
5817 cls
.lpszClassName
= "WM_NOTIFY_ParentClass";
5818 if(!RegisterClassA(&cls
)) assert(0);
5820 parent
= CreateWindowA(cls
.lpszClassName
, NULL
, WS_POPUP
|WS_VISIBLE
,
5821 0, 0, 200, 60, NULL
, NULL
, NULL
, NULL
);
5822 ok (parent
!= 0, "Failed to create parent window\n");
5824 hwndRichedit_WM_NOTIFY
= new_richedit(parent
);
5825 ok(hwndRichedit_WM_NOTIFY
!= 0, "Failed to create edit window\n");
5827 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETEVENTMASK
, 0, ENM_SELCHANGE
);
5829 /* Notifications for selection change should only be sent when selection
5830 actually changes. EM_SETCHARFORMAT is one message that calls
5831 ME_CommitUndo, which should check whether message should be sent */
5832 received_WM_NOTIFY
= 0;
5833 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
5834 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
5835 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
5836 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
5837 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETCHARFORMAT
, 0, (LPARAM
)&cf2
);
5838 ok(received_WM_NOTIFY
== 0, "Unexpected WM_NOTIFY was sent!\n");
5840 /* WM_SETTEXT should NOT cause a WM_NOTIFY to be sent when selection is
5842 received_WM_NOTIFY
= 0;
5843 modify_at_WM_NOTIFY
= 0;
5844 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_SETTEXT
, 0, (LPARAM
)"sometext");
5845 ok(received_WM_NOTIFY
== 0, "Unexpected WM_NOTIFY was sent!\n");
5846 ok(modify_at_WM_NOTIFY
== 0, "WM_NOTIFY callback saw text flagged as modified!\n");
5848 received_WM_NOTIFY
= 0;
5849 modify_at_WM_NOTIFY
= 0;
5850 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETSEL
, 4, 4);
5851 ok(received_WM_NOTIFY
== 1, "Expected WM_NOTIFY was NOT sent!\n");
5853 received_WM_NOTIFY
= 0;
5854 modify_at_WM_NOTIFY
= 0;
5855 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_SETTEXT
, 0, (LPARAM
)"sometext");
5856 ok(received_WM_NOTIFY
== 1, "Expected WM_NOTIFY was NOT sent!\n");
5857 ok(modify_at_WM_NOTIFY
== 0, "WM_NOTIFY callback saw text flagged as modified!\n");
5859 /* Test for WM_NOTIFY messages with redraw disabled. */
5860 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETSEL
, 0, 0);
5861 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_SETREDRAW
, FALSE
, 0);
5862 received_WM_NOTIFY
= 0;
5863 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_REPLACESEL
, FALSE
, (LPARAM
)"inserted");
5864 ok(received_WM_NOTIFY
== 1, "Expected WM_NOTIFY was NOT sent!\n");
5865 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_SETREDRAW
, TRUE
, 0);
5867 /* Test filtering key events. */
5868 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETSEL
, 0, 0);
5869 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETEVENTMASK
, 0, ENM_KEYEVENTS
);
5870 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5871 received_WM_NOTIFY
= 0;
5872 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_KEYDOWN
, VK_RIGHT
, 0);
5873 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5874 ok(sel_start
== 1 && sel_end
== 1,
5875 "selections is incorrectly at (%d,%d)\n", sel_start
, sel_end
);
5876 filter_on_WM_NOTIFY
= TRUE
;
5877 received_WM_NOTIFY
= 0;
5878 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_KEYDOWN
, VK_RIGHT
, 0);
5879 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5880 ok(sel_start
== 1 && sel_end
== 1,
5881 "selections is incorrectly at (%d,%d)\n", sel_start
, sel_end
);
5883 /* test with owner set to NULL */
5884 SetWindowLongPtrA(hwndRichedit_WM_NOTIFY
, GWLP_HWNDPARENT
, 0);
5885 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_KEYDOWN
, VK_RIGHT
, 0);
5886 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5887 ok(sel_start
== 1 && sel_end
== 1,
5888 "selections is incorrectly at (%d,%d)\n", sel_start
, sel_end
);
5890 DestroyWindow(hwndRichedit_WM_NOTIFY
);
5891 DestroyWindow(parent
);
5894 static void test_undo_coalescing(void)
5898 char buffer
[64] = {0};
5900 /* multi-line control inserts CR normally */
5901 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
|ES_MULTILINE
,
5902 0, 0, 200, 60, 0, 0, 0, 0);
5903 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5905 result
= SendMessageA(hwnd
, EM_CANUNDO
, 0, 0);
5906 ok (result
== FALSE
, "Can undo after window creation.\n");
5907 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
5908 ok (result
== FALSE
, "Undo operation successful with nothing to undo.\n");
5909 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
5910 ok (result
== FALSE
, "Can redo after window creation.\n");
5911 result
= SendMessageA(hwnd
, EM_REDO
, 0, 0);
5912 ok (result
== FALSE
, "Redo operation successful with nothing undone.\n");
5914 /* Test the effect of arrows keys during typing on undo transactions*/
5915 simulate_typing_characters(hwnd
, "one two three");
5916 SendMessageA(hwnd
, WM_KEYDOWN
, VK_RIGHT
, 1);
5917 SendMessageA(hwnd
, WM_KEYUP
, VK_RIGHT
, 1);
5918 simulate_typing_characters(hwnd
, " four five six");
5920 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
5921 ok (result
== FALSE
, "Can redo before anything is undone.\n");
5922 result
= SendMessageA(hwnd
, EM_CANUNDO
, 0, 0);
5923 ok (result
== TRUE
, "Cannot undo typed characters.\n");
5924 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
5925 ok (result
== TRUE
, "EM_UNDO Failed to undo typed characters.\n");
5926 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
5927 ok (result
== TRUE
, "Cannot redo after undo.\n");
5928 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5929 result
= strcmp(buffer
, "one two three");
5930 ok (result
== 0, "expected '%s' but got '%s'\n", "one two three", buffer
);
5932 result
= SendMessageA(hwnd
, EM_CANUNDO
, 0, 0);
5933 ok (result
== TRUE
, "Cannot undo typed characters.\n");
5934 result
= SendMessageA(hwnd
, WM_UNDO
, 0, 0);
5935 ok (result
== TRUE
, "Failed to undo typed characters.\n");
5936 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5937 result
= strcmp(buffer
, "");
5938 ok (result
== 0, "expected '%s' but got '%s'\n", "", buffer
);
5940 /* Test the effect of focus changes during typing on undo transactions*/
5941 simulate_typing_characters(hwnd
, "one two three");
5942 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
5943 ok (result
== FALSE
, "Redo buffer should have been cleared by typing.\n");
5944 SendMessageA(hwnd
, WM_KILLFOCUS
, 0, 0);
5945 SendMessageA(hwnd
, WM_SETFOCUS
, 0, 0);
5946 simulate_typing_characters(hwnd
, " four five six");
5947 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
5948 ok (result
== TRUE
, "Failed to undo typed characters.\n");
5949 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5950 result
= strcmp(buffer
, "one two three");
5951 ok (result
== 0, "expected '%s' but got '%s'\n", "one two three", buffer
);
5953 /* Test the effect of the back key during typing on undo transactions */
5954 SendMessageA(hwnd
, EM_EMPTYUNDOBUFFER
, 0, 0);
5955 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"");
5956 ok (result
== TRUE
, "Failed to clear the text.\n");
5957 simulate_typing_characters(hwnd
, "one two threa");
5958 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
5959 ok (result
== FALSE
, "Redo buffer should have been cleared by typing.\n");
5960 SendMessageA(hwnd
, WM_KEYDOWN
, VK_BACK
, 1);
5961 SendMessageA(hwnd
, WM_KEYUP
, VK_BACK
, 1);
5962 simulate_typing_characters(hwnd
, "e four five six");
5963 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
5964 ok (result
== TRUE
, "Failed to undo typed characters.\n");
5965 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5966 result
= strcmp(buffer
, "");
5967 ok (result
== 0, "expected '%s' but got '%s'\n", "", buffer
);
5969 /* Test the effect of the delete key during typing on undo transactions */
5970 SendMessageA(hwnd
, EM_EMPTYUNDOBUFFER
, 0, 0);
5971 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"abcd");
5972 ok(result
== TRUE
, "Failed to set the text.\n");
5973 SendMessageA(hwnd
, EM_SETSEL
, 1, 1);
5974 SendMessageA(hwnd
, WM_KEYDOWN
, VK_DELETE
, 1);
5975 SendMessageA(hwnd
, WM_KEYUP
, VK_DELETE
, 1);
5976 SendMessageA(hwnd
, WM_KEYDOWN
, VK_DELETE
, 1);
5977 SendMessageA(hwnd
, WM_KEYUP
, VK_DELETE
, 1);
5978 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
5979 ok (result
== TRUE
, "Failed to undo typed characters.\n");
5980 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5981 result
= strcmp(buffer
, "acd");
5982 ok (result
== 0, "expected '%s' but got '%s'\n", "acd", buffer
);
5983 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
5984 ok (result
== TRUE
, "Failed to undo typed characters.\n");
5985 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5986 result
= strcmp(buffer
, "abcd");
5987 ok (result
== 0, "expected '%s' but got '%s'\n", "abcd", buffer
);
5989 /* Test the effect of EM_STOPGROUPTYPING on undo transactions*/
5990 SendMessageA(hwnd
, EM_EMPTYUNDOBUFFER
, 0, 0);
5991 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"");
5992 ok (result
== TRUE
, "Failed to clear the text.\n");
5993 simulate_typing_characters(hwnd
, "one two three");
5994 result
= SendMessageA(hwnd
, EM_STOPGROUPTYPING
, 0, 0);
5995 ok (result
== 0, "expected %d but got %d\n", 0, result
);
5996 simulate_typing_characters(hwnd
, " four five six");
5997 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
5998 ok (result
== TRUE
, "Failed to undo typed characters.\n");
5999 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6000 result
= strcmp(buffer
, "one two three");
6001 ok (result
== 0, "expected '%s' but got '%s'\n", "one two three", buffer
);
6002 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6003 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6004 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6005 result
= strcmp(buffer
, "");
6006 ok (result
== 0, "expected '%s' but got '%s'\n", "", buffer
);
6008 DestroyWindow(hwnd
);
6011 static LONG CALLBACK
customWordBreakProc(WCHAR
*text
, int pos
, int bytes
, int code
)
6015 /* MSDN lied, length is actually the number of bytes. */
6016 length
= bytes
/ sizeof(WCHAR
);
6019 case WB_ISDELIMITER
:
6020 return text
[pos
] == 'X';
6022 case WB_MOVEWORDLEFT
:
6023 if (customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
6025 return min(customWordBreakProc(text
, pos
, bytes
, WB_LEFTBREAK
)-1, 0);
6028 while (pos
> 0 && !customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
6032 case WB_MOVEWORDRIGHT
:
6033 if (customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
6035 return min(customWordBreakProc(text
, pos
, bytes
, WB_RIGHTBREAK
)+1, length
);
6038 while (pos
< length
&& !customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
6042 ok(FALSE
, "Unexpected code %d\n", code
);
6048 static void test_word_movement(void)
6052 int sel_start
, sel_end
;
6053 const WCHAR textW
[] = {'o','n','e',' ','t','w','o','X','t','h','r','e','e',0};
6055 /* multi-line control inserts CR normally */
6056 hwnd
= new_richedit(NULL
);
6058 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"one two three");
6059 ok (result
== TRUE
, "Failed to clear the text.\n");
6060 SendMessageA(hwnd
, EM_SETSEL
, 0, 0);
6061 /* |one two three */
6063 send_ctrl_key(hwnd
, VK_RIGHT
);
6064 /* one |two three */
6065 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6066 ok(sel_start
== sel_end
, "Selection should be empty\n");
6067 ok(sel_start
== 4, "Cursor is at %d instead of %d\n", sel_start
, 4);
6069 send_ctrl_key(hwnd
, VK_RIGHT
);
6070 /* one two |three */
6071 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6072 ok(sel_start
== sel_end
, "Selection should be empty\n");
6073 ok(sel_start
== 9, "Cursor is at %d instead of %d\n", sel_start
, 9);
6075 send_ctrl_key(hwnd
, VK_LEFT
);
6076 /* one |two three */
6077 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6078 ok(sel_start
== sel_end
, "Selection should be empty\n");
6079 ok(sel_start
== 4, "Cursor is at %d instead of %d\n", sel_start
, 4);
6081 send_ctrl_key(hwnd
, VK_LEFT
);
6082 /* |one two three */
6083 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6084 ok(sel_start
== sel_end
, "Selection should be empty\n");
6085 ok(sel_start
== 0, "Cursor is at %d instead of %d\n", sel_start
, 0);
6087 SendMessageA(hwnd
, EM_SETSEL
, 8, 8);
6088 /* one two | three */
6089 send_ctrl_key(hwnd
, VK_RIGHT
);
6090 /* one two |three */
6091 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6092 ok(sel_start
== sel_end
, "Selection should be empty\n");
6093 ok(sel_start
== 9, "Cursor is at %d instead of %d\n", sel_start
, 9);
6095 SendMessageA(hwnd
, EM_SETSEL
, 11, 11);
6096 /* one two th|ree */
6097 send_ctrl_key(hwnd
, VK_LEFT
);
6098 /* one two |three */
6099 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6100 ok(sel_start
== sel_end
, "Selection should be empty\n");
6101 ok(sel_start
== 9, "Cursor is at %d instead of %d\n", sel_start
, 9);
6103 /* Test with a custom word break procedure that uses X as the delimiter. */
6104 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"one twoXthree");
6105 ok (result
== TRUE
, "Failed to clear the text.\n");
6106 SendMessageA(hwnd
, EM_SETWORDBREAKPROC
, 0, (LPARAM
)customWordBreakProc
);
6107 /* |one twoXthree */
6108 send_ctrl_key(hwnd
, VK_RIGHT
);
6109 /* one twoX|three */
6110 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6111 ok(sel_start
== sel_end
, "Selection should be empty\n");
6112 ok(sel_start
== 8, "Cursor is at %d instead of %d\n", sel_start
, 8);
6114 DestroyWindow(hwnd
);
6116 /* Make sure the behaviour is the same with a unicode richedit window,
6117 * and using unicode functions. */
6119 hwnd
= CreateWindowW(RICHEDIT_CLASS20W
, NULL
,
6120 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
6121 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6123 /* Test with a custom word break procedure that uses X as the delimiter. */
6124 result
= SendMessageW(hwnd
, WM_SETTEXT
, 0, (LPARAM
)textW
);
6125 ok (result
== TRUE
, "Failed to clear the text.\n");
6126 SendMessageW(hwnd
, EM_SETWORDBREAKPROC
, 0, (LPARAM
)customWordBreakProc
);
6127 /* |one twoXthree */
6128 send_ctrl_key(hwnd
, VK_RIGHT
);
6129 /* one twoX|three */
6130 SendMessageW(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6131 ok(sel_start
== sel_end
, "Selection should be empty\n");
6132 ok(sel_start
== 8, "Cursor is at %d instead of %d\n", sel_start
, 8);
6134 DestroyWindow(hwnd
);
6137 static void test_EM_CHARFROMPOS(void)
6146 /* multi-line control inserts CR normally */
6147 hwnd
= new_richedit(NULL
);
6148 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0,
6149 (LPARAM
)"one two three four five six seven\reight");
6150 ok(result
== 1, "Expected 1, got %d\n", result
);
6151 GetClientRect(hwnd
, &rcClient
);
6153 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6154 ok(result
== 34, "expected character index of 34 but got %d\n", result
);
6156 /* Test with points outside the bounds of the richedit control. */
6159 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6160 todo_wine
ok(result
== 34, "expected character index of 34 but got %d\n", result
);
6164 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6165 todo_wine
ok(result
== 33, "expected character index of 33 but got %d\n", result
);
6169 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6170 todo_wine
ok(result
== 39, "expected character index of 39 but got %d\n", result
);
6174 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6175 todo_wine
ok(result
== 0, "expected character index of 0 but got %d\n", result
);
6178 point
.y
= rcClient
.bottom
+ 1;
6179 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6180 todo_wine
ok(result
== 34, "expected character index of 34 but got %d\n", result
);
6183 point
.y
= rcClient
.bottom
;
6184 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6185 todo_wine
ok(result
== 39, "expected character index of 39 but got %d\n", result
);
6187 DestroyWindow(hwnd
);
6190 static void test_word_wrap(void)
6193 POINTL point
= {0, 60}; /* This point must be below the first line */
6194 const char *text
= "Must be long enough to test line wrapping";
6195 DWORD dwCommonStyle
= WS_VISIBLE
|WS_POPUP
|WS_VSCROLL
|ES_MULTILINE
;
6196 int res
, pos
, lines
;
6198 /* Test the effect of WS_HSCROLL and ES_AUTOHSCROLL styles on wrapping
6199 * when specified on window creation and set later. */
6200 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, dwCommonStyle
,
6201 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6202 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6203 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
6204 ok(res
, "WM_SETTEXT failed.\n");
6205 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6206 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
6207 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6208 ok(lines
> 1, "Line was expected to wrap (lines=%d).\n", lines
);
6210 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
|WS_HSCROLL
|ES_AUTOHSCROLL
);
6211 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6212 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
6213 DestroyWindow(hwnd
);
6215 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, dwCommonStyle
|WS_HSCROLL
,
6216 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6217 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6219 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
6220 ok(res
, "WM_SETTEXT failed.\n");
6221 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6222 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6223 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6224 ok(lines
== 1, "Line wasn't expected to wrap (lines=%d).\n", lines
);
6226 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
);
6227 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6228 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6229 DestroyWindow(hwnd
);
6231 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, dwCommonStyle
|ES_AUTOHSCROLL
,
6232 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6233 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6234 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
6235 ok(res
, "WM_SETTEXT failed.\n");
6236 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6237 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6239 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
);
6240 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6241 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6242 DestroyWindow(hwnd
);
6244 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
,
6245 dwCommonStyle
|WS_HSCROLL
|ES_AUTOHSCROLL
,
6246 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6247 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6248 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
6249 ok(res
, "WM_SETTEXT failed.\n");
6250 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6251 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6253 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
);
6254 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6255 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6257 /* Test the effect of EM_SETTARGETDEVICE on word wrap. */
6258 res
= SendMessageA(hwnd
, EM_SETTARGETDEVICE
, 0, 1);
6259 ok(res
, "EM_SETTARGETDEVICE failed (returned %d).\n", res
);
6260 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6261 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6263 res
= SendMessageA(hwnd
, EM_SETTARGETDEVICE
, 0, 0);
6264 ok(res
, "EM_SETTARGETDEVICE failed (returned %d).\n", res
);
6265 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6266 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
6267 DestroyWindow(hwnd
);
6269 /* Test to see if wrapping happens with redraw disabled. */
6270 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, dwCommonStyle
,
6271 0, 0, 400, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6272 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6273 SendMessageA(hwnd
, WM_SETREDRAW
, FALSE
, 0);
6274 res
= SendMessageA(hwnd
, EM_REPLACESEL
, FALSE
, (LPARAM
)text
);
6275 ok(res
, "EM_REPLACESEL failed.\n");
6276 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6277 ok(lines
== 1, "Line wasn't expected to wrap (lines=%d).\n", lines
);
6278 MoveWindow(hwnd
, 0, 0, 200, 80, FALSE
);
6279 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6280 ok(lines
> 1, "Line was expected to wrap (lines=%d).\n", lines
);
6282 SendMessageA(hwnd
, WM_SETREDRAW
, TRUE
, 0);
6283 DestroyWindow(hwnd
);
6286 static void test_autoscroll(void)
6288 HWND hwnd
= new_richedit(NULL
);
6289 int lines
, ret
, redraw
;
6292 for (redraw
= 0; redraw
<= 1; redraw
++) {
6293 trace("testing with WM_SETREDRAW=%d\n", redraw
);
6294 SendMessageA(hwnd
, WM_SETREDRAW
, redraw
, 0);
6295 SendMessageA(hwnd
, EM_REPLACESEL
, 0, (LPARAM
)"1\n2\n3\n4\n5\n6\n7\n8");
6296 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6297 ok(lines
== 8, "%d lines instead of 8\n", lines
);
6298 ret
= SendMessageA(hwnd
, EM_GETSCROLLPOS
, 0, (LPARAM
)&pt
);
6299 ok(ret
== 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret
);
6300 ok(pt
.y
!= 0, "Didn't scroll down after replacing text.\n");
6301 ret
= GetWindowLongA(hwnd
, GWL_STYLE
);
6302 ok(ret
& WS_VSCROLL
, "Scrollbar was not shown yet (style=%x).\n", (UINT
)ret
);
6304 SendMessageA(hwnd
, WM_SETTEXT
, 0, 0);
6305 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6306 ok(lines
== 1, "%d lines instead of 1\n", lines
);
6307 ret
= SendMessageA(hwnd
, EM_GETSCROLLPOS
, 0, (LPARAM
)&pt
);
6308 ok(ret
== 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret
);
6309 ok(pt
.y
== 0, "y scroll position is %d after clearing text.\n", pt
.y
);
6310 ret
= GetWindowLongA(hwnd
, GWL_STYLE
);
6311 ok(!(ret
& WS_VSCROLL
), "Scrollbar is still shown (style=%x).\n", (UINT
)ret
);
6314 SendMessageA(hwnd
, WM_SETREDRAW
, TRUE
, 0);
6315 DestroyWindow(hwnd
);
6317 /* The WS_VSCROLL and WS_HSCROLL styles implicitly set
6318 * auto vertical/horizontal scrolling options. */
6319 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6320 WS_POPUP
|ES_MULTILINE
|WS_VSCROLL
|WS_HSCROLL
,
6321 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6322 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6323 ret
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
6324 ok(ret
& ECO_AUTOVSCROLL
, "ECO_AUTOVSCROLL isn't set.\n");
6325 ok(ret
& ECO_AUTOHSCROLL
, "ECO_AUTOHSCROLL isn't set.\n");
6326 ret
= GetWindowLongA(hwnd
, GWL_STYLE
);
6327 ok(!(ret
& ES_AUTOVSCROLL
), "ES_AUTOVSCROLL is set.\n");
6328 ok(!(ret
& ES_AUTOHSCROLL
), "ES_AUTOHSCROLL is set.\n");
6329 DestroyWindow(hwnd
);
6331 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6332 WS_POPUP
|ES_MULTILINE
,
6333 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6334 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6335 ret
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
6336 ok(!(ret
& ECO_AUTOVSCROLL
), "ECO_AUTOVSCROLL is set.\n");
6337 ok(!(ret
& ECO_AUTOHSCROLL
), "ECO_AUTOHSCROLL is set.\n");
6338 ret
= GetWindowLongA(hwnd
, GWL_STYLE
);
6339 ok(!(ret
& ES_AUTOVSCROLL
), "ES_AUTOVSCROLL is set.\n");
6340 ok(!(ret
& ES_AUTOHSCROLL
), "ES_AUTOHSCROLL is set.\n");
6341 DestroyWindow(hwnd
);
6345 static void test_format_rect(void)
6348 RECT rc
, expected
, clientRect
;
6352 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6353 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
6354 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6355 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6357 GetClientRect(hwnd
, &clientRect
);
6359 expected
= clientRect
;
6361 expected
.right
-= 1;
6362 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6363 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6364 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6365 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6366 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6367 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6369 for (n
= -3; n
<= 3; n
++)
6376 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6379 expected
.top
= max(0, rc
.top
);
6380 expected
.left
= max(0, rc
.left
);
6381 expected
.bottom
= min(clientRect
.bottom
, rc
.bottom
);
6382 expected
.right
= min(clientRect
.right
, rc
.right
);
6383 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6384 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6385 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6386 "[n=%d] rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6387 n
, rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6388 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6392 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6393 expected
= clientRect
;
6394 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6395 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6396 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6397 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6398 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6399 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6401 /* Adding the selectionbar adds the selectionbar width to the left side. */
6402 SendMessageA(hwnd
, EM_SETOPTIONS
, ECOOP_OR
, ECO_SELECTIONBAR
);
6403 options
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
6404 ok(options
& ECO_SELECTIONBAR
, "EM_SETOPTIONS failed to add selectionbar.\n");
6405 expected
.left
+= 8; /* selection bar width */
6406 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6407 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6408 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6409 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6410 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6411 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6414 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6415 expected
= clientRect
;
6416 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6417 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6418 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6419 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6420 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6421 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6423 /* Removing the selectionbar subtracts the selectionbar width from the left side,
6424 * even if the left side is already 0. */
6425 SendMessageA(hwnd
, EM_SETOPTIONS
, ECOOP_AND
, ~ECO_SELECTIONBAR
);
6426 options
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
6427 ok(!(options
& ECO_SELECTIONBAR
), "EM_SETOPTIONS failed to remove selectionbar.\n");
6428 expected
.left
-= 8; /* selection bar width */
6429 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6430 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6431 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6432 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6433 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6434 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6436 /* Set the absolute value of the formatting rectangle. */
6438 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6439 expected
= clientRect
;
6440 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6441 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6442 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6443 "[n=%d] rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6444 n
, rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6445 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6447 /* MSDN documents the EM_SETRECT message as using the rectangle provided in
6448 * LPARAM as being a relative offset when the WPARAM value is 1, but these
6449 * tests show that this isn't true. */
6452 rc
.bottom
= clientRect
.bottom
- 15;
6453 rc
.right
= clientRect
.right
- 15;
6455 SendMessageA(hwnd
, EM_SETRECT
, 1, (LPARAM
)&rc
);
6456 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6457 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6458 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6459 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6460 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6461 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6463 /* For some reason it does not limit the values to the client rect with
6464 * a WPARAM value of 1. */
6467 rc
.bottom
= clientRect
.bottom
+ 15;
6468 rc
.right
= clientRect
.right
+ 15;
6470 SendMessageA(hwnd
, EM_SETRECT
, 1, (LPARAM
)&rc
);
6471 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6472 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6473 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6474 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6475 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6476 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6478 /* Reset to default rect and check how the format rect adjusts to window
6479 * resize and how it copes with very small windows */
6480 SendMessageA(hwnd
, EM_SETRECT
, 0, 0);
6482 MoveWindow(hwnd
, 0, 0, 100, 30, FALSE
);
6483 GetClientRect(hwnd
, &clientRect
);
6485 expected
= clientRect
;
6487 expected
.right
-= 1;
6488 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6489 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6490 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6491 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6492 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6493 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6495 MoveWindow(hwnd
, 0, 0, 0, 30, FALSE
);
6496 GetClientRect(hwnd
, &clientRect
);
6498 expected
= clientRect
;
6500 expected
.right
-= 1;
6501 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6502 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6503 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6504 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6505 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6506 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6508 MoveWindow(hwnd
, 0, 0, 100, 0, FALSE
);
6509 GetClientRect(hwnd
, &clientRect
);
6511 expected
= clientRect
;
6513 expected
.right
-= 1;
6514 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6515 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6516 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6517 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6518 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6519 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6521 DestroyWindow(hwnd
);
6523 /* The extended window style affects the formatting rectangle. */
6524 hwnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, RICHEDIT_CLASS20A
, NULL
,
6525 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
6526 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6527 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6529 GetClientRect(hwnd
, &clientRect
);
6531 expected
= clientRect
;
6534 expected
.right
-= 1;
6535 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6536 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6537 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6538 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6539 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6540 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6550 expected
.right
+= 1;
6551 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6552 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6553 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6554 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6555 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6556 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6557 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6559 DestroyWindow(hwnd
);
6562 static void test_WM_GETDLGCODE(void)
6568 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6570 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6571 ES_MULTILINE
|ES_WANTRETURN
|WS_POPUP
,
6572 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6573 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6575 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, 0);
6576 expected
= expected
| DLGC_WANTMESSAGE
;
6577 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6579 DestroyWindow(hwnd
);
6581 msg
.message
= WM_KEYDOWN
;
6582 msg
.wParam
= VK_RETURN
;
6583 msg
.lParam
= (MapVirtualKeyA(VK_RETURN
, MAPVK_VK_TO_VSC
) << 16) | 0x0001;
6586 msg
.time
= GetTickCount();
6588 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6589 ES_MULTILINE
|ES_WANTRETURN
|WS_POPUP
,
6590 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6591 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6593 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6594 expected
= expected
| DLGC_WANTMESSAGE
;
6595 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6597 DestroyWindow(hwnd
);
6599 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6600 ES_MULTILINE
|WS_POPUP
,
6601 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6602 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6604 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6605 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6606 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6608 DestroyWindow(hwnd
);
6610 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6611 ES_WANTRETURN
|WS_POPUP
,
6612 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6613 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6615 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6616 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6617 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6619 DestroyWindow(hwnd
);
6621 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6623 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6624 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6626 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6627 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6628 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6630 DestroyWindow(hwnd
);
6632 msg
.wParam
= VK_TAB
;
6633 msg
.lParam
= (MapVirtualKeyA(VK_TAB
, MAPVK_VK_TO_VSC
) << 16) | 0x0001;
6635 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6636 ES_MULTILINE
|WS_POPUP
,
6637 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6638 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6640 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6641 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6642 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6644 DestroyWindow(hwnd
);
6646 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6648 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6649 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6651 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6652 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6653 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6655 DestroyWindow(hwnd
);
6657 hold_key(VK_CONTROL
);
6659 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6660 ES_MULTILINE
|WS_POPUP
,
6661 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6662 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6664 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6665 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6666 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6668 DestroyWindow(hwnd
);
6670 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6672 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6673 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6675 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6676 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6677 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6679 DestroyWindow(hwnd
);
6681 release_key(VK_CONTROL
);
6684 msg
.lParam
= (MapVirtualKeyA('a', MAPVK_VK_TO_VSC
) << 16) | 0x0001;
6686 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6687 ES_MULTILINE
|WS_POPUP
,
6688 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6689 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6691 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6692 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6693 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6695 DestroyWindow(hwnd
);
6697 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6699 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6700 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6702 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6703 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6704 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6706 DestroyWindow(hwnd
);
6708 msg
.message
= WM_CHAR
;
6710 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6711 ES_MULTILINE
|WS_POPUP
,
6712 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6713 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6715 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6716 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6717 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6719 DestroyWindow(hwnd
);
6721 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6723 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6724 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6726 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6727 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6728 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6730 DestroyWindow(hwnd
);
6732 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6733 WS_POPUP
|ES_SAVESEL
,
6734 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6735 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6736 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, 0, 0);
6737 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
;
6738 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6740 DestroyWindow(hwnd
);
6743 static void test_zoom(void)
6749 int numerator
, denominator
;
6751 hwnd
= new_richedit(NULL
);
6752 GetClientRect(hwnd
, &rc
);
6753 pt
.x
= (rc
.right
- rc
.left
) / 2;
6754 pt
.y
= (rc
.bottom
- rc
.top
) / 2;
6755 ClientToScreen(hwnd
, &pt
);
6757 /* Test initial zoom value */
6758 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6759 ok(numerator
== 0, "Numerator should be initialized to 0 (got %d).\n", numerator
);
6760 ok(denominator
== 0, "Denominator should be initialized to 0 (got %d).\n", denominator
);
6761 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6763 /* test scroll wheel */
6764 hold_key(VK_CONTROL
);
6765 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
6766 MAKELPARAM(pt
.x
, pt
.y
));
6767 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6768 release_key(VK_CONTROL
);
6770 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6771 ok(numerator
== 110, "incorrect numerator is %d\n", numerator
);
6772 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6773 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6775 /* Test how much the mouse wheel can zoom in and out. */
6776 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 490, 100);
6777 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6779 hold_key(VK_CONTROL
);
6780 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
6781 MAKELPARAM(pt
.x
, pt
.y
));
6782 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6783 release_key(VK_CONTROL
);
6785 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6786 ok(numerator
== 500, "incorrect numerator is %d\n", numerator
);
6787 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6788 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6790 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 491, 100);
6791 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6793 hold_key(VK_CONTROL
);
6794 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
6795 MAKELPARAM(pt
.x
, pt
.y
));
6796 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6797 release_key(VK_CONTROL
);
6799 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6800 ok(numerator
== 491, "incorrect numerator is %d\n", numerator
);
6801 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6802 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6804 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 20, 100);
6805 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6807 hold_key(VK_CONTROL
);
6808 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, -WHEEL_DELTA
),
6809 MAKELPARAM(pt
.x
, pt
.y
));
6810 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6811 release_key(VK_CONTROL
);
6813 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6814 ok(numerator
== 10, "incorrect numerator is %d\n", numerator
);
6815 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6816 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6818 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 19, 100);
6819 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6821 hold_key(VK_CONTROL
);
6822 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, -WHEEL_DELTA
),
6823 MAKELPARAM(pt
.x
, pt
.y
));
6824 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6825 release_key(VK_CONTROL
);
6827 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6828 ok(numerator
== 19, "incorrect numerator is %d\n", numerator
);
6829 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6830 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6832 /* Test how WM_SCROLLWHEEL treats our custom denominator. */
6833 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 50, 13);
6834 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6836 hold_key(VK_CONTROL
);
6837 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
6838 MAKELPARAM(pt
.x
, pt
.y
));
6839 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6840 release_key(VK_CONTROL
);
6842 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6843 ok(numerator
== 394, "incorrect numerator is %d\n", numerator
);
6844 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6845 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6847 /* Test bounds checking on EM_SETZOOM */
6848 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 2, 127);
6849 ok(ret
== TRUE
, "EM_SETZOOM rejected valid values (%d).\n", ret
);
6851 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 127, 2);
6852 ok(ret
== TRUE
, "EM_SETZOOM rejected valid values (%d).\n", ret
);
6854 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 2, 128);
6855 ok(ret
== FALSE
, "EM_SETZOOM accepted invalid values (%d).\n", ret
);
6857 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6858 ok(numerator
== 127, "incorrect numerator is %d\n", numerator
);
6859 ok(denominator
== 2, "incorrect denominator is %d\n", denominator
);
6860 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6862 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 128, 2);
6863 ok(ret
== FALSE
, "EM_SETZOOM accepted invalid values (%d).\n", ret
);
6865 /* See if negative numbers are accepted. */
6866 ret
= SendMessageA(hwnd
, EM_SETZOOM
, -100, -100);
6867 ok(ret
== FALSE
, "EM_SETZOOM accepted invalid values (%d).\n", ret
);
6869 /* See if negative numbers are accepted. */
6870 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 0, 100);
6871 ok(ret
== FALSE
, "EM_SETZOOM failed (%d).\n", ret
);
6873 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6874 ok(numerator
== 127, "incorrect numerator is %d\n", numerator
);
6875 ok(denominator
== 2, "incorrect denominator is %d\n", denominator
);
6876 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6878 /* Reset the zoom value */
6879 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 0, 0);
6880 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6882 DestroyWindow(hwnd
);
6885 struct dialog_mode_messages
6887 int wm_getdefid
, wm_close
, wm_nextdlgctl
;
6890 static struct dialog_mode_messages dm_messages
;
6892 #define test_dm_messages(wmclose, wmgetdefid, wmnextdlgctl) \
6893 ok(dm_messages.wm_close == wmclose, "expected %d WM_CLOSE message, " \
6894 "got %d\n", wmclose, dm_messages.wm_close); \
6895 ok(dm_messages.wm_getdefid == wmgetdefid, "expected %d WM_GETDIFID message, " \
6896 "got %d\n", wmgetdefid, dm_messages.wm_getdefid);\
6897 ok(dm_messages.wm_nextdlgctl == wmnextdlgctl, "expected %d WM_NEXTDLGCTL message, " \
6898 "got %d\n", wmnextdlgctl, dm_messages.wm_nextdlgctl)
6900 static LRESULT CALLBACK
dialog_mode_wnd_proc(HWND hwnd
, UINT iMsg
, WPARAM wParam
, LPARAM lParam
)
6905 dm_messages
.wm_getdefid
++;
6906 return MAKELONG(ID_RICHEDITTESTDBUTTON
, DC_HASDEFID
);
6908 dm_messages
.wm_nextdlgctl
++;
6911 dm_messages
.wm_close
++;
6915 return DefWindowProcA(hwnd
, iMsg
, wParam
, lParam
);
6918 static void test_dialogmode(void)
6920 HWND hwRichEdit
, hwParent
, hwButton
;
6926 cls
.lpfnWndProc
= dialog_mode_wnd_proc
;
6929 cls
.hInstance
= GetModuleHandleA(0);
6931 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
6932 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
6933 cls
.lpszMenuName
= NULL
;
6934 cls
.lpszClassName
= "DialogModeParentClass";
6935 if(!RegisterClassA(&cls
)) assert(0);
6937 hwParent
= CreateWindowA("DialogModeParentClass", NULL
, WS_OVERLAPPEDWINDOW
,
6938 CW_USEDEFAULT
, 0, 200, 120, NULL
, NULL
, GetModuleHandleA(0), NULL
);
6940 /* Test richedit(ES_MULTILINE) */
6942 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, hwParent
);
6944 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6945 ok(0 == r
, "expected 0, got %d\n", r
);
6946 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
6947 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
6949 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, 0);
6950 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
6952 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6953 ok(0 == r
, "expected 0, got %d\n", r
);
6954 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
6955 ok(3 == lcount
, "expected 3, got %d\n", lcount
);
6957 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
6958 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
6959 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6960 ok(0 == r
, "expected 0, got %d\n", r
);
6961 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
6962 ok(3 == lcount
, "expected 3, got %d\n", lcount
);
6964 DestroyWindow(hwRichEdit
);
6966 /* Test standalone richedit(ES_MULTILINE) */
6968 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, NULL
);
6970 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6971 ok(0 == r
, "expected 0, got %d\n", r
);
6972 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
6973 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
6975 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
6976 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
6978 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6979 ok(0 == r
, "expected 0, got %d\n", r
);
6980 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
6981 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
6983 DestroyWindow(hwRichEdit
);
6985 /* Check a destination for messages */
6987 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, hwParent
);
6989 SetWindowLongA(hwRichEdit
, GWL_STYLE
, GetWindowLongA(hwRichEdit
, GWL_STYLE
)& ~WS_POPUP
);
6990 SetParent( hwRichEdit
, NULL
);
6992 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
6993 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
6995 memset(&dm_messages
, 0, sizeof(dm_messages
));
6996 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6997 ok(0 == r
, "expected 0, got %d\n", r
);
6998 test_dm_messages(0, 1, 0);
7000 memset(&dm_messages
, 0, sizeof(dm_messages
));
7001 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7002 ok(0 == r
, "expected 0, got %d\n", r
);
7003 test_dm_messages(0, 0, 1);
7005 DestroyWindow(hwRichEdit
);
7007 /* Check messages from richedit(ES_MULTILINE) */
7009 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, hwParent
);
7011 memset(&dm_messages
, 0, sizeof(dm_messages
));
7012 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7013 ok(0 == r
, "expected 0, got %d\n", r
);
7014 test_dm_messages(0, 0, 0);
7016 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7017 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7019 memset(&dm_messages
, 0, sizeof(dm_messages
));
7020 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7021 ok(0 == r
, "expected 0, got %d\n", r
);
7022 test_dm_messages(0, 0, 0);
7024 memset(&dm_messages
, 0, sizeof(dm_messages
));
7025 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7026 ok(0 == r
, "expected 0, got %d\n", r
);
7027 test_dm_messages(0, 0, 0);
7029 memset(&dm_messages
, 0, sizeof(dm_messages
));
7030 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7031 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
7032 test_dm_messages(0, 0, 0);
7034 memset(&dm_messages
, 0, sizeof(dm_messages
));
7035 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7036 ok(0 == r
, "expected 0, got %d\n", r
);
7037 test_dm_messages(0, 1, 0);
7039 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7040 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7042 memset(&dm_messages
, 0, sizeof(dm_messages
));
7043 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7044 ok(0 == r
, "expected 0, got %d\n", r
);
7045 test_dm_messages(0, 0, 0);
7047 memset(&dm_messages
, 0, sizeof(dm_messages
));
7048 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7049 ok(0 == r
, "expected 0, got %d\n", r
);
7050 test_dm_messages(0, 0, 1);
7052 hwButton
= CreateWindowA("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
7053 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
7054 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
7056 memset(&dm_messages
, 0, sizeof(dm_messages
));
7057 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7058 ok(0 == r
, "expected 0, got %d\n", r
);
7059 test_dm_messages(0, 1, 1);
7061 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7062 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7064 DestroyWindow(hwButton
);
7065 DestroyWindow(hwRichEdit
);
7067 /* Check messages from richedit(ES_MULTILINE|ES_WANTRETURN) */
7069 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
|ES_WANTRETURN
, hwParent
);
7071 memset(&dm_messages
, 0, sizeof(dm_messages
));
7072 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7073 ok(0 == r
, "expected 0, got %d\n", r
);
7074 test_dm_messages(0, 0, 0);
7076 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7077 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7079 memset(&dm_messages
, 0, sizeof(dm_messages
));
7080 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7081 ok(0 == r
, "expected 0, got %d\n", r
);
7082 test_dm_messages(0, 0, 0);
7084 memset(&dm_messages
, 0, sizeof(dm_messages
));
7085 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7086 ok(0 == r
, "expected 0, got %d\n", r
);
7087 test_dm_messages(0, 0, 0);
7089 memset(&dm_messages
, 0, sizeof(dm_messages
));
7090 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7091 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
7092 test_dm_messages(0, 0, 0);
7094 memset(&dm_messages
, 0, sizeof(dm_messages
));
7095 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7096 ok(0 == r
, "expected 0, got %d\n", r
);
7097 test_dm_messages(0, 0, 0);
7099 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7100 ok(3 == lcount
, "expected 3, got %d\n", lcount
);
7102 memset(&dm_messages
, 0, sizeof(dm_messages
));
7103 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7104 ok(0 == r
, "expected 0, got %d\n", r
);
7105 test_dm_messages(0, 0, 0);
7107 memset(&dm_messages
, 0, sizeof(dm_messages
));
7108 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7109 ok(0 == r
, "expected 0, got %d\n", r
);
7110 test_dm_messages(0, 0, 1);
7112 hwButton
= CreateWindowA("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
7113 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
7114 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
7116 memset(&dm_messages
, 0, sizeof(dm_messages
));
7117 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7118 ok(0 == r
, "expected 0, got %d\n", r
);
7119 test_dm_messages(0, 0, 0);
7121 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7122 ok(4 == lcount
, "expected 4, got %d\n", lcount
);
7124 DestroyWindow(hwButton
);
7125 DestroyWindow(hwRichEdit
);
7127 /* Check messages from richedit(0) */
7129 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, 0, hwParent
);
7131 memset(&dm_messages
, 0, sizeof(dm_messages
));
7132 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7133 ok(0 == r
, "expected 0, got %d\n", r
);
7134 test_dm_messages(0, 0, 0);
7136 memset(&dm_messages
, 0, sizeof(dm_messages
));
7137 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7138 ok(0 == r
, "expected 0, got %d\n", r
);
7139 test_dm_messages(0, 0, 0);
7141 memset(&dm_messages
, 0, sizeof(dm_messages
));
7142 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7143 ok(0 == r
, "expected 0, got %d\n", r
);
7144 test_dm_messages(0, 0, 0);
7146 memset(&dm_messages
, 0, sizeof(dm_messages
));
7147 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7148 ok(0x8b == r
, "expected 0x8b, got 0x%x\n", r
);
7149 test_dm_messages(0, 0, 0);
7151 memset(&dm_messages
, 0, sizeof(dm_messages
));
7152 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7153 ok(0 == r
, "expected 0, got %d\n", r
);
7154 test_dm_messages(0, 1, 0);
7156 memset(&dm_messages
, 0, sizeof(dm_messages
));
7157 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7158 ok(0 == r
, "expected 0, got %d\n", r
);
7159 test_dm_messages(0, 0, 0);
7161 memset(&dm_messages
, 0, sizeof(dm_messages
));
7162 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7163 ok(0 == r
, "expected 0, got %d\n", r
);
7164 test_dm_messages(0, 0, 1);
7166 hwButton
= CreateWindowA("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
7167 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
7168 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
7170 memset(&dm_messages
, 0, sizeof(dm_messages
));
7171 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7172 ok(0 == r
, "expected 0, got %d\n", r
);
7173 test_dm_messages(0, 1, 1);
7175 DestroyWindow(hwRichEdit
);
7177 /* Check messages from richedit(ES_WANTRETURN) */
7179 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_WANTRETURN
, hwParent
);
7181 memset(&dm_messages
, 0, sizeof(dm_messages
));
7182 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7183 ok(0 == r
, "expected 0, got %d\n", r
);
7184 test_dm_messages(0, 0, 0);
7186 memset(&dm_messages
, 0, sizeof(dm_messages
));
7187 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7188 ok(0x8b == r
, "expected 0x8b, got 0x%x\n", r
);
7189 test_dm_messages(0, 0, 0);
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 hwButton
= CreateWindowA("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
7197 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
7198 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
7200 memset(&dm_messages
, 0, sizeof(dm_messages
));
7201 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7202 ok(0 == r
, "expected 0, got %d\n", r
);
7203 test_dm_messages(0, 0, 0);
7205 DestroyWindow(hwRichEdit
);
7206 DestroyWindow(hwParent
);
7209 static void test_EM_FINDWORDBREAK_W(void)
7211 static const struct {
7213 BOOL isdelimiter
; /* expected result of WB_ISDELIMITER */
7214 } delimiter_tests
[] = {
7215 {0x0a, FALSE
}, /* newline */
7216 {0x0b, FALSE
}, /* vertical tab */
7217 {0x0c, FALSE
}, /* form feed */
7218 {0x0d, FALSE
}, /* carriage return */
7219 {0x20, TRUE
}, /* space */
7220 {0x61, FALSE
}, /* capital letter a */
7221 {0xa0, FALSE
}, /* no-break space */
7222 {0x2000, FALSE
}, /* en quad */
7223 {0x3000, FALSE
}, /* Ideographic space */
7224 {0x1100, FALSE
}, /* Hangul Choseong Kiyeok (G sound) Ordinary Letter*/
7225 {0x11ff, FALSE
}, /* Hangul Jongseoung Kiyeok-Hieuh (Hard N sound) Ordinary Letter*/
7226 {0x115f, FALSE
}, /* Hangul Choseong Filler (no sound, used with two letter Hangul words) Ordinary Letter */
7227 {0xac00, FALSE
}, /* Hangul character GA*/
7228 {0xd7af, FALSE
}, /* End of Hangul character chart */
7229 {0xf020, TRUE
}, /* MS private for CP_SYMBOL round trip?, see kb897872 */
7230 {0xff20, FALSE
}, /* fullwidth commercial @ */
7231 {WCH_EMBEDDING
, FALSE
}, /* object replacement character*/
7234 HWND hwndRichEdit
= new_richeditW(NULL
);
7235 ok(IsWindowUnicode(hwndRichEdit
), "window should be unicode\n");
7236 for (i
= 0; i
< sizeof(delimiter_tests
)/sizeof(delimiter_tests
[0]); i
++)
7241 wbuf
[0] = delimiter_tests
[i
].c
;
7243 SendMessageW(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)wbuf
);
7244 result
= SendMessageW(hwndRichEdit
, EM_FINDWORDBREAK
, WB_ISDELIMITER
,0);
7245 if (wbuf
[0] == 0x20 || wbuf
[0] == 0xf020)
7247 ok(result
== delimiter_tests
[i
].isdelimiter
,
7248 "wanted ISDELIMITER_W(0x%x) %d, got %d\n",
7249 delimiter_tests
[i
].c
, delimiter_tests
[i
].isdelimiter
,result
);
7251 ok(result
== delimiter_tests
[i
].isdelimiter
,
7252 "wanted ISDELIMITER_W(0x%x) %d, got %d\n",
7253 delimiter_tests
[i
].c
, delimiter_tests
[i
].isdelimiter
, result
);
7255 DestroyWindow(hwndRichEdit
);
7258 static void test_EM_FINDWORDBREAK_A(void)
7260 static const struct {
7262 BOOL isdelimiter
; /* expected result of WB_ISDELIMITER */
7263 } delimiter_tests
[] = {
7264 {0x0a, FALSE
}, /* newline */
7265 {0x0b, FALSE
}, /* vertical tab */
7266 {0x0c, FALSE
}, /* form feed */
7267 {0x0d, FALSE
}, /* carriage return */
7268 {0x20, TRUE
}, /* space */
7269 {0x61, FALSE
}, /* capital letter a */
7272 HWND hwndRichEdit
= new_richedit(NULL
);
7274 ok(!IsWindowUnicode(hwndRichEdit
), "window should not be unicode\n");
7275 for (i
= 0; i
< sizeof(delimiter_tests
)/sizeof(delimiter_tests
[0]); i
++)
7279 buf
[0] = delimiter_tests
[i
].c
;
7281 SendMessageW(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buf
);
7282 result
= SendMessageA(hwndRichEdit
, EM_FINDWORDBREAK
, WB_ISDELIMITER
, 0);
7285 ok(result
== delimiter_tests
[i
].isdelimiter
,
7286 "wanted ISDELIMITER_A(0x%x) %d, got %d\n",
7287 delimiter_tests
[i
].c
, delimiter_tests
[i
].isdelimiter
,result
);
7289 ok(result
== delimiter_tests
[i
].isdelimiter
,
7290 "wanted ISDELIMITER_A(0x%x) %d, got %d\n",
7291 delimiter_tests
[i
].c
, delimiter_tests
[i
].isdelimiter
, result
);
7293 DestroyWindow(hwndRichEdit
);
7297 * This test attempts to show the effect of enter on a richedit
7298 * control v1.0 inserts CRLF whereas for higher versions it only
7299 * inserts CR. If shows that EM_GETTEXTEX with GT_USECRLF == WM_GETTEXT
7300 * and also shows that GT_USECRLF has no effect in richedit 1.0, but
7301 * does for higher. The same test is cloned in riched32 and riched20.
7303 static void test_enter(void)
7305 static const struct {
7306 const char *initialtext
;
7308 const char *expectedwmtext
;
7309 const char *expectedemtext
;
7310 const char *expectedemtextcrlf
;
7311 } testenteritems
[] = {
7312 { "aaabbb\r\n", 3, "aaa\r\nbbb\r\n", "aaa\rbbb\r", "aaa\r\nbbb\r\n"},
7313 { "aaabbb\r\n", 6, "aaabbb\r\n\r\n", "aaabbb\r\r", "aaabbb\r\n\r\n"},
7314 { "aa\rabbb\r\n", 7, "aa\r\nabbb\r\n\r\n", "aa\rabbb\r\r", "aa\r\nabbb\r\n\r\n"},
7315 { "aa\rabbb\r\n", 3, "aa\r\n\r\nabbb\r\n", "aa\r\rabbb\r", "aa\r\n\r\nabbb\r\n"},
7316 { "aa\rabbb\r\n", 2, "aa\r\n\r\nabbb\r\n", "aa\r\rabbb\r", "aa\r\n\r\nabbb\r\n"}
7319 char expectedbuf
[1024];
7320 char resultbuf
[1024];
7321 HWND hwndRichEdit
= new_richedit(NULL
);
7324 for (i
= 0; i
< sizeof(testenteritems
)/sizeof(testenteritems
[0]); i
++) {
7326 char buf
[1024] = {0};
7329 const char *expected
;
7331 /* Set the text to the initial text */
7332 result
= SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)testenteritems
[i
].initialtext
);
7333 ok (result
== 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i
, result
);
7336 SendMessageA(hwndRichEdit
, EM_SETSEL
, testenteritems
[i
].cursor
, testenteritems
[i
].cursor
);
7337 simulate_typing_characters(hwndRichEdit
, "\r");
7339 /* 1. Retrieve with WM_GETTEXT */
7341 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buf
);
7342 expected
= testenteritems
[i
].expectedwmtext
;
7345 for (j
= 0; j
< (UINT
)result
; j
++)
7346 sprintf(resultbuf
+strlen(resultbuf
), "%02x", buf
[j
] & 0xFF);
7347 expectedbuf
[0] = '\0';
7348 for (j
= 0; j
< strlen(expected
); j
++)
7349 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", expected
[j
] & 0xFF);
7351 result
= strcmp(expected
, buf
);
7353 "[%d] WM_GETTEXT unexpected '%s' expected '%s'\n",
7354 i
, resultbuf
, expectedbuf
);
7356 /* 2. Retrieve with EM_GETTEXTEX, GT_DEFAULT */
7357 getText
.cb
= sizeof(buf
);
7358 getText
.flags
= GT_DEFAULT
;
7359 getText
.codepage
= CP_ACP
;
7360 getText
.lpDefaultChar
= NULL
;
7361 getText
.lpUsedDefChar
= NULL
;
7363 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
7364 expected
= testenteritems
[i
].expectedemtext
;
7367 for (j
= 0; j
< (UINT
)result
; j
++)
7368 sprintf(resultbuf
+strlen(resultbuf
), "%02x", buf
[j
] & 0xFF);
7369 expectedbuf
[0] = '\0';
7370 for (j
= 0; j
< strlen(expected
); j
++)
7371 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", expected
[j
] & 0xFF);
7373 result
= strcmp(expected
, buf
);
7375 "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n",
7376 i
, resultbuf
, expectedbuf
);
7378 /* 3. Retrieve with EM_GETTEXTEX, GT_USECRLF */
7379 getText
.cb
= sizeof(buf
);
7380 getText
.flags
= GT_USECRLF
;
7381 getText
.codepage
= CP_ACP
;
7382 getText
.lpDefaultChar
= NULL
;
7383 getText
.lpUsedDefChar
= NULL
;
7385 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
7386 expected
= testenteritems
[i
].expectedemtextcrlf
;
7389 for (j
= 0; j
< (UINT
)result
; j
++)
7390 sprintf(resultbuf
+strlen(resultbuf
), "%02x", buf
[j
] & 0xFF);
7391 expectedbuf
[0] = '\0';
7392 for (j
= 0; j
< strlen(expected
); j
++)
7393 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", expected
[j
] & 0xFF);
7395 result
= strcmp(expected
, buf
);
7397 "[%d] EM_GETTEXTEX, GT_USECRLF unexpected '%s', expected '%s'\n",
7398 i
, resultbuf
, expectedbuf
);
7401 DestroyWindow(hwndRichEdit
);
7404 static void test_WM_CREATE(void)
7406 static const WCHAR titleW
[] = {'l','i','n','e','1','\n','l','i','n','e','2',0};
7407 static const char title
[] = "line1\nline2";
7414 rich_edit
= CreateWindowA(RICHEDIT_CLASS20A
, title
, WS_POPUP
|WS_VISIBLE
,
7415 0, 0, 200, 80, NULL
, NULL
, NULL
, NULL
);
7416 ok(rich_edit
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7418 len
= GetWindowTextA(rich_edit
, buf
, sizeof(buf
));
7419 ok(len
== 5, "GetWindowText returned %d\n", len
);
7420 ok(!strcmp(buf
, "line1"), "buf = %s\n", buf
);
7422 res
= SendMessageA(rich_edit
, EM_GETSEL
, 0, 0);
7423 ok(res
== 0, "SendMessage(EM_GETSEL) returned %lx\n", res
);
7425 DestroyWindow(rich_edit
);
7427 rich_edit
= CreateWindowW(RICHEDIT_CLASS20W
, titleW
, WS_POPUP
|WS_VISIBLE
|ES_MULTILINE
,
7428 0, 0, 200, 80, NULL
, NULL
, NULL
, NULL
);
7429 ok(rich_edit
!= NULL
, "class: %s, error: %d\n", wine_dbgstr_w(RICHEDIT_CLASS20W
), (int) GetLastError());
7431 len
= GetWindowTextA(rich_edit
, buf
, sizeof(buf
));
7432 ok(len
== 12, "GetWindowText returned %d\n", len
);
7433 ok(!strcmp(buf
, "line1\r\nline2"), "buf = %s\n", buf
);
7435 res
= SendMessageA(rich_edit
, EM_GETSEL
, 0, 0);
7436 ok(res
== 0, "SendMessage(EM_GETSEL) returned %lx\n", res
);
7438 DestroyWindow(rich_edit
);
7441 /*******************************************************************
7442 * Test that after deleting all of the text, the first paragraph
7443 * format reverts to the default.
7445 static void test_reset_default_para_fmt( void )
7447 HWND richedit
= new_richeditW( NULL
);
7449 WORD def_align
, new_align
;
7451 memset( &fmt
, 0, sizeof(fmt
) );
7452 fmt
.cbSize
= sizeof(PARAFORMAT2
);
7454 SendMessageA( richedit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
7455 def_align
= fmt
.wAlignment
;
7456 new_align
= (def_align
== PFA_LEFT
) ? PFA_RIGHT
: PFA_LEFT
;
7458 simulate_typing_characters( richedit
, "123" );
7460 SendMessageA( richedit
, EM_SETSEL
, 0, -1 );
7461 fmt
.dwMask
= PFM_ALIGNMENT
;
7462 fmt
.wAlignment
= new_align
;
7463 SendMessageA( richedit
, EM_SETPARAFORMAT
, 0, (LPARAM
)&fmt
);
7465 SendMessageA( richedit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
7466 ok( fmt
.wAlignment
== new_align
, "got %d expect %d\n", fmt
.wAlignment
, new_align
);
7468 SendMessageA( richedit
, EM_SETSEL
, 0, -1 );
7469 SendMessageA( richedit
, WM_CUT
, 0, 0 );
7471 SendMessageA( richedit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
7472 ok( fmt
.wAlignment
== def_align
, "got %d exppect %d\n", fmt
.wAlignment
, def_align
);
7474 DestroyWindow( richedit
);
7477 START_TEST( editor
)
7480 /* Must explicitly LoadLibrary(). The test has no references to functions in
7481 * RICHED20.DLL, so the linker doesn't actually link to it. */
7482 hmoduleRichEdit
= LoadLibraryA("riched20.dll");
7483 ok(hmoduleRichEdit
!= NULL
, "error: %d\n", (int) GetLastError());
7486 test_EM_FINDTEXT(FALSE
);
7487 test_EM_FINDTEXT(TRUE
);
7489 test_EM_POSFROMCHAR();
7490 test_EM_SCROLLCARET();
7492 test_scrollbar_visibility();
7494 test_EM_LINELENGTH();
7495 test_EM_SETCHARFORMAT();
7496 test_EM_SETTEXTMODE();
7497 test_TM_PLAINTEXT();
7498 test_EM_SETOPTIONS();
7500 test_EM_GETTEXTRANGE();
7501 test_EM_GETSELTEXT();
7502 test_EM_SETUNDOLIMIT();
7504 test_EM_SETTEXTEX();
7505 test_EM_LIMITTEXT();
7506 test_EM_EXLIMITTEXT();
7507 test_EM_GETLIMITTEXT();
7509 test_EM_GETMODIFY();
7513 test_EM_STREAMOUT();
7514 test_EM_STREAMOUT_FONTTBL();
7515 test_EM_StreamIn_Undo();
7516 test_EM_FORMATRANGE();
7517 test_unicode_conversions();
7518 test_EM_GETTEXTLENGTHEX();
7519 test_EM_REPLACESEL(1);
7520 test_EM_REPLACESEL(0);
7522 test_EM_AUTOURLDETECT();
7524 test_undo_coalescing();
7525 test_word_movement();
7526 test_EM_CHARFROMPOS();
7527 test_SETPARAFORMAT();
7531 test_WM_GETDLGCODE();
7534 test_EM_FINDWORDBREAK_W();
7535 test_EM_FINDWORDBREAK_A();
7538 test_reset_default_para_fmt();
7540 /* Set the environment variable WINETEST_RICHED20 to keep windows
7541 * responsive and open for 30 seconds. This is useful for debugging.
7543 if (getenv( "WINETEST_RICHED20" )) {
7544 keep_responsive(30);
7547 OleFlushClipboard();
7548 ret
= FreeLibrary(hmoduleRichEdit
);
7549 ok(ret
, "error: %d\n", (int) GetLastError());