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(!buf
[0], "EM_SETTEXTEX with NULL lParam should clear rich edit.\n");
3740 /* put some text back: !ST_SELECTION && Unicode && !\rtf */
3742 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
3743 /* select some text */
3746 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
3747 /* replace current selection: ST_SELECTION && Unicode && !\rtf */
3748 setText
.flags
= ST_SELECTION
;
3749 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, 0);
3751 "EM_SETTEXTEX with NULL lParam to replace selection"
3752 " with no text should return 0. Got %i\n",
3755 /* put some text back: !ST_SELECTION && Unicode && !\rtf */
3757 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
3758 /* select some text */
3761 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
3762 /* replace current selection: ST_SELECTION && Unicode && !\rtf */
3763 setText
.flags
= ST_SELECTION
;
3764 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
3766 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3767 ok(result
== lstrlenW(TestItem1
),
3768 "EM_SETTEXTEX with NULL lParam to replace selection"
3769 " with no text should return 0. Got %i\n",
3771 ok(lstrlenW(buf
) == 22,
3772 "EM_SETTEXTEX to replace selection with more text failed: %i.\n",
3775 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings */
3776 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"TestSomeText"); /* TestItem1 */
3778 es
.dwCookie
= (DWORD_PTR
)&p
;
3780 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3781 memset(buf
, 0, sizeof(buf
));
3782 SendMessageA(hwndRichEdit
, EM_STREAMOUT
,
3783 (WPARAM
)(SF_RTF
), (LPARAM
)&es
);
3784 trace("EM_STREAMOUT produced:\n%s\n", (char *)buf
);
3786 /* !ST_SELECTION && !Unicode && \rtf */
3787 setText
.codepage
= CP_ACP
;/* EM_STREAMOUT saved as ANSI string */
3788 getText
.codepage
= 1200; /* no constant for unicode */
3789 getText
.cb
= MAX_BUF_LEN
;
3790 getText
.flags
= GT_DEFAULT
;
3791 getText
.lpDefaultChar
= NULL
;
3792 getText
.lpUsedDefChar
= NULL
;
3795 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)buf
);
3796 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3797 ok(lstrcmpW(buf
, TestItem1
) == 0,
3798 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
3800 /* The following test demonstrates that EM_SETTEXTEX treats text as ASCII if it
3801 * starts with ASCII characters "{\rtf" even when the codepage is unicode. */
3802 setText
.codepage
= 1200; /* Lie about code page (actual ASCII) */
3803 getText
.codepage
= CP_ACP
;
3804 getText
.cb
= MAX_BUF_LEN
;
3805 getText
.flags
= GT_DEFAULT
;
3806 getText
.lpDefaultChar
= NULL
;
3807 getText
.lpUsedDefChar
= NULL
;
3809 setText
.flags
= ST_SELECTION
;
3810 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
3811 result
= SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"{\\rtf not unicode}");
3812 todo_wine
ok(result
== 11, "EM_SETTEXTEX incorrectly returned %d\n", result
);
3813 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)bufACP
);
3814 ok(lstrcmpA(bufACP
, "not unicode") == 0, "'%s' != 'not unicode'\n", bufACP
);
3816 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings with a selection */
3817 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"TestSomeText"); /* TestItem1 */
3819 es
.dwCookie
= (DWORD_PTR
)&p
;
3821 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3822 memset(buf
, 0, sizeof(buf
));
3823 SendMessageA(hwndRichEdit
, EM_STREAMOUT
,
3824 (WPARAM
)(SF_RTF
), (LPARAM
)&es
);
3825 trace("EM_STREAMOUT produced:\n%s\n", (char *)buf
);
3827 /* select some text */
3830 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
3832 /* ST_SELECTION && !Unicode && \rtf */
3833 setText
.codepage
= CP_ACP
;/* EM_STREAMOUT saved as ANSI string */
3834 getText
.codepage
= 1200; /* no constant for unicode */
3835 getText
.cb
= MAX_BUF_LEN
;
3836 getText
.flags
= GT_DEFAULT
;
3837 getText
.lpDefaultChar
= NULL
;
3838 getText
.lpUsedDefChar
= NULL
;
3840 setText
.flags
= ST_SELECTION
;
3841 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)buf
);
3842 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3843 ok_w3("Expected \"%s\" or \"%s\", got \"%s\"\n", TestItem1alt
, TestItem1altn
, buf
);
3845 /* The following test demonstrates that EM_SETTEXTEX replacing a selection */
3846 setText
.codepage
= 1200; /* no constant for unicode */
3847 getText
.codepage
= CP_ACP
;
3848 getText
.cb
= MAX_BUF_LEN
;
3851 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
); /* TestItem1 */
3852 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)bufACP
);
3854 /* select some text */
3857 SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
3859 /* ST_SELECTION && !Unicode && !\rtf */
3860 setText
.codepage
= CP_ACP
;
3861 getText
.codepage
= 1200; /* no constant for unicode */
3862 getText
.cb
= MAX_BUF_LEN
;
3863 getText
.flags
= GT_DEFAULT
;
3864 getText
.lpDefaultChar
= NULL
;
3865 getText
.lpUsedDefChar
= NULL
;
3867 setText
.flags
= ST_SELECTION
;
3868 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)bufACP
);
3869 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
3870 ok(lstrcmpW(buf
, TestItem1alt
) == 0,
3871 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX when"
3872 " using ST_SELECTION and non-Unicode\n");
3874 /* Test setting text using rich text format */
3876 setText
.codepage
= CP_ACP
;
3877 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"{\\rtf richtext}");
3878 getText
.codepage
= CP_ACP
;
3879 getText
.cb
= MAX_BUF_LEN
;
3880 getText
.flags
= GT_DEFAULT
;
3881 getText
.lpDefaultChar
= NULL
;
3882 getText
.lpUsedDefChar
= NULL
;
3883 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)bufACP
);
3884 ok(!strcmp(bufACP
, "richtext"), "expected 'richtext' but got '%s'\n", bufACP
);
3887 setText
.codepage
= CP_ACP
;
3888 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"{\\urtf morerichtext}");
3889 getText
.codepage
= CP_ACP
;
3890 getText
.cb
= MAX_BUF_LEN
;
3891 getText
.flags
= GT_DEFAULT
;
3892 getText
.lpDefaultChar
= NULL
;
3893 getText
.lpUsedDefChar
= NULL
;
3894 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)bufACP
);
3895 ok(!strcmp(bufACP
, "morerichtext"), "expected 'morerichtext' but got '%s'\n", bufACP
);
3897 /* test for utf8 text with BOM */
3899 setText
.codepage
= CP_ACP
;
3900 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"\xef\xbb\xbfTestUTF8WithBOM");
3901 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)bufACP
);
3902 ok(result
== 15, "EM_SETTEXTEX: Test UTF8 with BOM returned %d, expected 15\n", result
);
3903 result
= strcmp(bufACP
, "TestUTF8WithBOM");
3904 ok(result
== 0, "EM_SETTEXTEX: Test UTF8 with BOM set wrong text: Result: %s\n", bufACP
);
3907 setText
.codepage
= CP_UTF8
;
3908 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"\xef\xbb\xbfTestUTF8WithBOM");
3909 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)bufACP
);
3910 ok(result
== 15, "EM_SETTEXTEX: Test UTF8 with BOM returned %d, expected 15\n", result
);
3911 result
= strcmp(bufACP
, "TestUTF8WithBOM");
3912 ok(result
== 0, "EM_SETTEXTEX: Test UTF8 with BOM set wrong text: Result: %s\n", bufACP
);
3914 DestroyWindow(hwndRichEdit
);
3917 static void test_EM_LIMITTEXT(void)
3921 HWND hwndRichEdit
= new_richedit(NULL
);
3923 /* The main purpose of this test is to demonstrate that the nonsense in MSDN
3924 * about setting the length to -1 for multiline edit controls doesn't happen.
3927 /* Don't check default gettextlimit case. That's done in other tests */
3929 /* Set textlimit to 100 */
3930 SendMessageA(hwndRichEdit
, EM_LIMITTEXT
, 100, 0);
3931 ret
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3933 "EM_LIMITTEXT: set to 100, returned: %d, expected: 100\n", ret
);
3935 /* Set textlimit to 0 */
3936 SendMessageA(hwndRichEdit
, EM_LIMITTEXT
, 0, 0);
3937 ret
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3939 "EM_LIMITTEXT: set to 0, returned: %d, expected: 65536\n", ret
);
3941 /* Set textlimit to -1 */
3942 SendMessageA(hwndRichEdit
, EM_LIMITTEXT
, -1, 0);
3943 ret
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3945 "EM_LIMITTEXT: set to -1, returned: %d, expected: -1\n", ret
);
3947 /* Set textlimit to -2 */
3948 SendMessageA(hwndRichEdit
, EM_LIMITTEXT
, -2, 0);
3949 ret
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3951 "EM_LIMITTEXT: set to -2, returned: %d, expected: -2\n", ret
);
3953 DestroyWindow (hwndRichEdit
);
3957 static void test_EM_EXLIMITTEXT(void)
3959 int i
, selBegin
, selEnd
, len1
, len2
;
3961 char text
[1024 + 1];
3962 char buffer
[1024 + 1];
3963 int textlimit
= 0; /* multiple of 100 */
3964 HWND hwndRichEdit
= new_richedit(NULL
);
3966 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3967 ok(32767 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 32767, i
); /* default */
3970 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
3971 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3973 ok(textlimit
== i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit
, i
);
3976 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
3977 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3979 ok(textlimit
== i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit
, i
);
3981 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, 0);
3982 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3983 /* default for WParam = 0 */
3984 ok(65536 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 65536, i
);
3986 textlimit
= sizeof(text
)-1;
3987 memset(text
, 'W', textlimit
);
3988 text
[sizeof(text
)-1] = 0;
3989 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
3990 /* maxed out text */
3991 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3993 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1); /* select everything */
3994 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
3995 len1
= selEnd
- selBegin
;
3997 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, VK_BACK
, 1);
3998 SendMessageA(hwndRichEdit
, WM_CHAR
, VK_BACK
, 1);
3999 SendMessageA(hwndRichEdit
, WM_KEYUP
, VK_BACK
, 1);
4000 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4001 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
4002 len2
= selEnd
- selBegin
;
4005 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4008 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'A', 1);
4009 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 1);
4010 SendMessageA(hwndRichEdit
, WM_KEYUP
, 'A', 1);
4011 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4012 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
4013 len1
= selEnd
- selBegin
;
4016 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4019 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'A', 1);
4020 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 1);
4021 SendMessageA(hwndRichEdit
, WM_KEYUP
, 'A', 1); /* full; should be no effect */
4022 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4023 SendMessageA(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
4024 len2
= selEnd
- selBegin
;
4027 "EM_EXLIMITTEXT: No Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4030 /* set text up to the limit, select all the text, then add a char */
4032 memset(text
, 'W', textlimit
);
4033 text
[textlimit
] = 0;
4034 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
4035 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
4036 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1);
4037 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 1);
4038 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4039 result
= strcmp(buffer
, "A");
4040 ok(0 == result
, "got string = \"%s\"\n", buffer
);
4042 /* WM_SETTEXT not limited */
4044 memset(text
, 'W', textlimit
);
4045 text
[textlimit
] = 0;
4046 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
-5);
4047 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
4048 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4050 ok(10 == i
, "expected 10 chars\n");
4051 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4052 ok(10 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i
);
4054 /* try inserting more text at end */
4055 i
= SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4056 ok(0 == i
, "WM_CHAR wasn't processed\n");
4057 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4059 ok(10 == i
, "expected 10 chars, got %i\n", i
);
4060 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4061 ok(10 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i
);
4063 /* try inserting text at beginning */
4064 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 0);
4065 i
= SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4066 ok(0 == i
, "WM_CHAR wasn't processed\n");
4067 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4069 ok(10 == i
, "expected 10 chars, got %i\n", i
);
4070 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4071 ok(10 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i
);
4073 /* WM_CHAR is limited */
4075 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
4076 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, -1); /* select everything */
4077 i
= SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4078 ok(0 == i
, "WM_CHAR wasn't processed\n");
4079 i
= SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4080 ok(0 == i
, "WM_CHAR wasn't processed\n");
4081 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4083 ok(1 == i
, "expected 1 chars, got %i instead\n", i
);
4085 DestroyWindow(hwndRichEdit
);
4088 static void test_EM_GETLIMITTEXT(void)
4091 HWND hwndRichEdit
= new_richedit(NULL
);
4093 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4094 ok(32767 == i
, "expected: %d, actual: %d\n", 32767, i
); /* default value */
4096 SendMessageA(hwndRichEdit
, EM_EXLIMITTEXT
, 0, 50000);
4097 i
= SendMessageA(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4098 ok(50000 == i
, "expected: %d, actual: %d\n", 50000, i
);
4100 DestroyWindow(hwndRichEdit
);
4103 static void test_WM_SETFONT(void)
4105 /* There is no invalid input or error conditions for this function.
4106 * NULL wParam and lParam just fall back to their default values
4107 * It should be noted that even if you use a gibberish name for your fonts
4108 * here, it will still work because the name is stored. They will display as
4109 * System, but will report their name to be whatever they were created as */
4111 HWND hwndRichEdit
= new_richedit(NULL
);
4112 HFONT testFont1
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4113 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4114 FF_DONTCARE
, "Marlett");
4115 HFONT testFont2
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4116 OUT_TT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4117 FF_DONTCARE
, "MS Sans Serif");
4118 HFONT testFont3
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4119 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4120 FF_DONTCARE
, "Courier");
4121 LOGFONTA sentLogFont
;
4122 CHARFORMAT2A returnedCF2A
;
4124 returnedCF2A
.cbSize
= sizeof(returnedCF2A
);
4126 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"x");
4127 SendMessageA(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont1
, MAKELPARAM(TRUE
, 0));
4128 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&returnedCF2A
);
4130 GetObjectA(testFont1
, sizeof(LOGFONTA
), &sentLogFont
);
4131 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
4132 "EM_GETCHARFORMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n",
4133 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
4135 SendMessageA(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont2
, MAKELPARAM(TRUE
, 0));
4136 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&returnedCF2A
);
4137 GetObjectA(testFont2
, sizeof(LOGFONTA
), &sentLogFont
);
4138 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
4139 "EM_GETCHARFORMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n",
4140 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
4142 SendMessageA(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont3
, MAKELPARAM(TRUE
, 0));
4143 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&returnedCF2A
);
4144 GetObjectA(testFont3
, sizeof(LOGFONTA
), &sentLogFont
);
4145 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
4146 "EM_GETCHARFORMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n",
4147 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
4149 /* This last test is special since we send in NULL. We clear the variables
4150 * and just compare to "System" instead of the sent in font name. */
4151 ZeroMemory(&returnedCF2A
,sizeof(returnedCF2A
));
4152 ZeroMemory(&sentLogFont
,sizeof(sentLogFont
));
4153 returnedCF2A
.cbSize
= sizeof(returnedCF2A
);
4155 SendMessageA(hwndRichEdit
, WM_SETFONT
, 0, MAKELPARAM((WORD
) TRUE
, 0));
4156 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&returnedCF2A
);
4157 GetObjectA(NULL
, sizeof(LOGFONTA
), &sentLogFont
);
4158 ok (!strcmp("System",returnedCF2A
.szFaceName
),
4159 "EM_GETCHARFORMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A
.szFaceName
);
4161 DestroyWindow(hwndRichEdit
);
4165 static DWORD CALLBACK
test_EM_GETMODIFY_esCallback(DWORD_PTR dwCookie
,
4170 const char** str
= (const char**)dwCookie
;
4171 int size
= strlen(*str
);
4172 if(size
> 3) /* let's make it piecemeal for fun */
4179 memcpy(pbBuff
, *str
, *pcb
);
4185 static void test_EM_GETMODIFY(void)
4187 HWND hwndRichEdit
= new_richedit(NULL
);
4190 WCHAR TestItem1
[] = {'T', 'e', 's', 't',
4192 'T', 'e', 'x', 't', 0};
4193 WCHAR TestItem2
[] = {'T', 'e', 's', 't',
4195 'O', 't', 'h', 'e', 'r',
4196 'T', 'e', 'x', 't', 0};
4197 const char* streamText
= "hello world";
4202 HFONT testFont
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4203 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4204 FF_DONTCARE
, "Courier");
4206 setText
.codepage
= 1200; /* no constant for unicode */
4207 setText
.flags
= ST_KEEPUNDO
;
4210 /* modify flag shouldn't be set when richedit is first created */
4211 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4213 "EM_GETMODIFY returned non-zero, instead of zero on create\n");
4215 /* setting modify flag should actually set it */
4216 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, TRUE
, 0);
4217 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4219 "EM_GETMODIFY returned zero, instead of non-zero on EM_SETMODIFY\n");
4221 /* clearing modify flag should actually clear it */
4222 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4223 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4225 "EM_GETMODIFY returned non-zero, instead of zero on EM_SETMODIFY\n");
4227 /* setting font doesn't change modify flag */
4228 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4229 SendMessageA(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont
, MAKELPARAM(TRUE
, 0));
4230 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4232 "EM_GETMODIFY returned non-zero, instead of zero on setting font\n");
4234 /* setting text should set modify flag */
4235 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4236 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
4237 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4239 "EM_GETMODIFY returned zero, instead of non-zero on setting text\n");
4241 /* undo previous text doesn't reset modify flag */
4242 SendMessageA(hwndRichEdit
, WM_UNDO
, 0, 0);
4243 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4245 "EM_GETMODIFY returned zero, instead of non-zero on undo after setting text\n");
4247 /* set text with no flag to keep undo stack should not set modify flag */
4248 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4250 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
4251 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4253 "EM_GETMODIFY returned non-zero, instead of zero when setting text while not keeping undo stack\n");
4255 /* WM_SETTEXT doesn't modify */
4256 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4257 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem2
);
4258 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4260 "EM_GETMODIFY returned non-zero for WM_SETTEXT\n");
4262 /* clear the text */
4263 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4264 SendMessageA(hwndRichEdit
, WM_CLEAR
, 0, 0);
4265 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4267 "EM_GETMODIFY returned non-zero, instead of zero for WM_CLEAR\n");
4270 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4271 SendMessageA(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
4272 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
4273 SendMessageA(hwndRichEdit
, EM_REPLACESEL
, TRUE
, (LPARAM
)TestItem2
);
4274 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4276 "EM_GETMODIFY returned zero, instead of non-zero when replacing text\n");
4278 /* copy/paste text 1 */
4279 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4280 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
4281 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
4282 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
4283 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4285 "EM_GETMODIFY returned zero, instead of non-zero when pasting identical text\n");
4287 /* copy/paste text 2 */
4288 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4289 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 2);
4290 SendMessageA(hwndRichEdit
, WM_COPY
, 0, 0);
4291 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 3);
4292 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
4293 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4295 "EM_GETMODIFY returned zero, instead of non-zero when pasting different text\n");
4298 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4299 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 1);
4300 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4301 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4303 "EM_GETMODIFY returned zero, instead of non-zero for WM_CHAR\n");
4306 SendMessageA(hwndRichEdit
, WM_CHAR
, 'A', 0);
4307 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4308 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, VK_BACK
, 0);
4309 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4311 "EM_GETMODIFY returned zero, instead of non-zero for backspace\n");
4313 /* set char format */
4314 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4315 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
4316 SendMessageA(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
4317 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
4318 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
4319 SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
4320 result
= SendMessageA(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
4321 ok(result
== 1, "EM_SETCHARFORMAT returned %ld instead of 1\n", result
);
4322 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4324 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETCHARFORMAT\n");
4326 /* set para format */
4327 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4328 pf2
.cbSize
= sizeof(PARAFORMAT2
);
4329 SendMessageA(hwndRichEdit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&pf2
);
4330 pf2
.dwMask
= PFM_ALIGNMENT
| pf2
.dwMask
;
4331 pf2
.wAlignment
= PFA_RIGHT
;
4332 SendMessageA(hwndRichEdit
, EM_SETPARAFORMAT
, 0, (LPARAM
)&pf2
);
4333 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4335 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETPARAFORMAT\n");
4338 SendMessageA(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4339 es
.dwCookie
= (DWORD_PTR
)&streamText
;
4341 es
.pfnCallback
= test_EM_GETMODIFY_esCallback
;
4342 SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
4343 result
= SendMessageA(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4345 "EM_GETMODIFY returned zero, instead of non-zero for EM_STREAM\n");
4347 DestroyWindow(hwndRichEdit
);
4353 LRESULT expected_retval
;
4354 int expected_getsel_start
;
4355 int expected_getsel_end
;
4356 int _getsel_todo_wine
;
4359 const struct exsetsel_s exsetsel_tests
[] = {
4361 {5, 10, 10, 5, 10, 0},
4362 {15, 17, 17, 15, 17, 0},
4363 /* test cpMax > strlen() */
4364 {0, 100, 18, 0, 18, 0},
4365 /* test cpMin < 0 && cpMax >= 0 after cpMax > strlen() */
4366 {-1, 1, 17, 17, 17, 0},
4367 /* test cpMin == cpMax */
4369 /* test cpMin < 0 && cpMax >= 0 (bug 4462) */
4370 {-1, 0, 5, 5, 5, 0},
4371 {-1, 17, 5, 5, 5, 0},
4372 {-1, 18, 5, 5, 5, 0},
4373 /* test cpMin < 0 && cpMax < 0 */
4374 {-1, -1, 17, 17, 17, 0},
4375 {-4, -5, 17, 17, 17, 0},
4376 /* test cpMin >=0 && cpMax < 0 (bug 6814) */
4377 {0, -1, 18, 0, 18, 0},
4378 {17, -5, 18, 17, 18, 0},
4379 {18, -3, 17, 17, 17, 0},
4380 /* test if cpMin > cpMax */
4381 {15, 19, 18, 15, 18, 0},
4382 {19, 15, 18, 15, 18, 0},
4385 static void check_EM_EXSETSEL(HWND hwnd
, const struct exsetsel_s
*setsel
, int id
) {
4390 cr
.cpMin
= setsel
->min
;
4391 cr
.cpMax
= setsel
->max
;
4392 result
= SendMessageA(hwnd
, EM_EXSETSEL
, 0, (LPARAM
)&cr
);
4394 ok(result
== setsel
->expected_retval
, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id
, setsel
->expected_retval
, result
);
4396 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&start
, (LPARAM
)&end
);
4398 if (setsel
->_getsel_todo_wine
) {
4400 ok(start
== setsel
->expected_getsel_start
&& end
== setsel
->expected_getsel_end
, "EM_EXSETSEL(%d): expected (%d,%d) actual:(%d,%d)\n", id
, setsel
->expected_getsel_start
, setsel
->expected_getsel_end
, start
, end
);
4403 ok(start
== setsel
->expected_getsel_start
&& end
== setsel
->expected_getsel_end
, "EM_EXSETSEL(%d): expected (%d,%d) actual:(%d,%d)\n", id
, setsel
->expected_getsel_start
, setsel
->expected_getsel_end
, start
, end
);
4407 static void test_EM_EXSETSEL(void)
4409 HWND hwndRichEdit
= new_richedit(NULL
);
4411 const int num_tests
= sizeof(exsetsel_tests
)/sizeof(struct exsetsel_s
);
4413 /* sending some text to the window */
4414 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"testing selection");
4415 /* 01234567890123456*/
4418 for (i
= 0; i
< num_tests
; i
++) {
4419 check_EM_EXSETSEL(hwndRichEdit
, &exsetsel_tests
[i
], i
);
4422 DestroyWindow(hwndRichEdit
);
4425 static void check_EM_SETSEL(HWND hwnd
, const struct exsetsel_s
*setsel
, int id
) {
4429 result
= SendMessageA(hwnd
, EM_SETSEL
, setsel
->min
, setsel
->max
);
4431 ok(result
== setsel
->expected_retval
, "EM_SETSEL(%d): expected: %ld actual: %ld\n", id
, setsel
->expected_retval
, result
);
4433 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&start
, (LPARAM
)&end
);
4435 if (setsel
->_getsel_todo_wine
) {
4437 ok(start
== setsel
->expected_getsel_start
&& end
== setsel
->expected_getsel_end
, "EM_SETSEL(%d): expected (%d,%d) actual:(%d,%d)\n", id
, setsel
->expected_getsel_start
, setsel
->expected_getsel_end
, start
, end
);
4440 ok(start
== setsel
->expected_getsel_start
&& end
== setsel
->expected_getsel_end
, "EM_SETSEL(%d): expected (%d,%d) actual:(%d,%d)\n", id
, setsel
->expected_getsel_start
, setsel
->expected_getsel_end
, start
, end
);
4444 static void test_EM_SETSEL(void)
4446 HWND hwndRichEdit
= new_richedit(NULL
);
4448 const int num_tests
= sizeof(exsetsel_tests
)/sizeof(struct exsetsel_s
);
4450 /* sending some text to the window */
4451 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"testing selection");
4452 /* 01234567890123456*/
4455 for (i
= 0; i
< num_tests
; i
++) {
4456 check_EM_SETSEL(hwndRichEdit
, &exsetsel_tests
[i
], i
);
4459 DestroyWindow(hwndRichEdit
);
4462 static void test_EM_REPLACESEL(int redraw
)
4464 HWND hwndRichEdit
= new_richedit(NULL
);
4465 char buffer
[1024] = {0};
4470 /* sending some text to the window */
4471 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"testing selection");
4472 /* 01234567890123456*/
4475 /* FIXME add more tests */
4476 SendMessageA(hwndRichEdit
, EM_SETSEL
, 7, 17);
4477 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, 0);
4478 ok(0 == r
, "EM_REPLACESEL returned %d, expected 0\n", r
);
4479 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4480 r
= strcmp(buffer
, "testing");
4481 ok(0 == r
, "expected %d, got %d\n", 0, r
);
4483 DestroyWindow(hwndRichEdit
);
4485 hwndRichEdit
= new_richedit(NULL
);
4487 trace("Testing EM_REPLACESEL behavior with redraw=%d\n", redraw
);
4488 SendMessageA(hwndRichEdit
, WM_SETREDRAW
, redraw
, 0);
4490 /* Test behavior with carriage returns and newlines */
4491 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4492 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"RichEdit1");
4493 ok(9 == r
, "EM_REPLACESEL returned %d, expected 9\n", r
);
4494 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4495 r
= strcmp(buffer
, "RichEdit1");
4496 ok(0 == r
, "expected %d, got %d\n", 0, r
);
4498 getText
.codepage
= CP_ACP
;
4499 getText
.flags
= GT_DEFAULT
;
4500 getText
.lpDefaultChar
= NULL
;
4501 getText
.lpUsedDefChar
= NULL
;
4502 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4503 ok(strcmp(buffer
, "RichEdit1") == 0,
4504 "EM_GETTEXTEX results not what was set by EM_REPLACESEL\n");
4506 /* Test number of lines reported after EM_REPLACESEL */
4507 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4508 ok(r
== 1, "EM_GETLINECOUNT returned %d, expected 1\n", r
);
4510 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4511 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"RichEdit1\r");
4512 ok(10 == r
, "EM_REPLACESEL returned %d, expected 10\n", r
);
4513 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4514 r
= strcmp(buffer
, "RichEdit1\r\n");
4515 ok(0 == r
, "expected %d, got %d\n", 0, r
);
4517 getText
.codepage
= CP_ACP
;
4518 getText
.flags
= GT_DEFAULT
;
4519 getText
.lpDefaultChar
= NULL
;
4520 getText
.lpUsedDefChar
= NULL
;
4521 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4522 ok(strcmp(buffer
, "RichEdit1\r") == 0,
4523 "EM_GETTEXTEX returned incorrect string\n");
4525 /* Test number of lines reported after EM_REPLACESEL */
4526 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4527 ok(r
== 2, "EM_GETLINECOUNT returned %d, expected 2\n", r
);
4529 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4530 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"RichEdit1\r\n");
4531 ok(r
== 11, "EM_REPLACESEL returned %d, expected 11\n", r
);
4533 /* Test number of lines reported after EM_REPLACESEL */
4534 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4535 ok(r
== 2, "EM_GETLINECOUNT returned %d, expected 2\n", r
);
4537 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4538 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4539 ok(cr
.cpMin
== 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr
.cpMin
);
4540 ok(cr
.cpMax
== 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr
.cpMax
);
4542 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4543 r
= strcmp(buffer
, "RichEdit1\r\n");
4544 ok(0 == r
, "expected %d, got %d\n", 0, r
);
4546 getText
.codepage
= CP_ACP
;
4547 getText
.flags
= GT_DEFAULT
;
4548 getText
.lpDefaultChar
= NULL
;
4549 getText
.lpUsedDefChar
= NULL
;
4550 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4551 ok(strcmp(buffer
, "RichEdit1\r") == 0,
4552 "EM_GETTEXTEX returned incorrect string\n");
4554 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4555 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4556 ok(cr
.cpMin
== 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr
.cpMin
);
4557 ok(cr
.cpMax
== 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr
.cpMax
);
4559 /* The following tests show that richedit should handle the special \r\r\n
4560 sequence by turning it into a single space on insertion. However,
4561 EM_REPLACESEL on WinXP returns the number of characters in the original
4565 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4566 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r");
4567 ok(2 == r
, "EM_REPLACESEL returned %d, expected 4\n", r
);
4568 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4569 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4570 ok(cr
.cpMin
== 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr
.cpMin
);
4571 ok(cr
.cpMax
== 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr
.cpMax
);
4573 /* Test the actual string */
4575 getText
.codepage
= CP_ACP
;
4576 getText
.flags
= GT_DEFAULT
;
4577 getText
.lpDefaultChar
= NULL
;
4578 getText
.lpUsedDefChar
= NULL
;
4579 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4580 ok(strcmp(buffer
, "\r\r") == 0,
4581 "EM_GETTEXTEX returned incorrect string\n");
4583 /* Test number of lines reported after EM_REPLACESEL */
4584 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4585 ok(r
== 3, "EM_GETLINECOUNT returned %d, expected 3\n", r
);
4587 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4588 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r\n");
4589 ok(r
== 3, "EM_REPLACESEL returned %d, expected 3\n", r
);
4590 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4591 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4592 ok(cr
.cpMin
== 1, "EM_EXGETSEL returned cpMin=%d, expected 1\n", cr
.cpMin
);
4593 ok(cr
.cpMax
== 1, "EM_EXGETSEL returned cpMax=%d, expected 1\n", cr
.cpMax
);
4595 /* Test the actual string */
4597 getText
.codepage
= CP_ACP
;
4598 getText
.flags
= GT_DEFAULT
;
4599 getText
.lpDefaultChar
= NULL
;
4600 getText
.lpUsedDefChar
= NULL
;
4601 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4602 ok(strcmp(buffer
, " ") == 0,
4603 "EM_GETTEXTEX returned incorrect string\n");
4605 /* Test number of lines reported after EM_REPLACESEL */
4606 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4607 ok(r
== 1, "EM_GETLINECOUNT returned %d, expected 1\n", r
);
4609 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4610 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r\r\r\r\n\r\r\r");
4611 ok(r
== 9, "EM_REPLACESEL returned %d, expected 9\n", r
);
4612 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4613 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4614 ok(cr
.cpMin
== 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr
.cpMin
);
4615 ok(cr
.cpMax
== 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr
.cpMax
);
4617 /* Test the actual string */
4619 getText
.codepage
= CP_ACP
;
4620 getText
.flags
= GT_DEFAULT
;
4621 getText
.lpDefaultChar
= NULL
;
4622 getText
.lpUsedDefChar
= NULL
;
4623 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4624 ok(strcmp(buffer
, "\r\r\r \r\r\r") == 0,
4625 "EM_GETTEXTEX returned incorrect string\n");
4627 /* Test number of lines reported after EM_REPLACESEL */
4628 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4629 ok(r
== 7, "EM_GETLINECOUNT returned %d, expected 7\n", r
);
4631 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4632 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r\n\r\n");
4633 ok(r
== 5, "EM_REPLACESEL returned %d, expected 5\n", r
);
4634 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4635 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4636 ok(cr
.cpMin
== 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr
.cpMin
);
4637 ok(cr
.cpMax
== 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr
.cpMax
);
4639 /* Test the actual string */
4641 getText
.codepage
= CP_ACP
;
4642 getText
.flags
= GT_DEFAULT
;
4643 getText
.lpDefaultChar
= NULL
;
4644 getText
.lpUsedDefChar
= NULL
;
4645 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4646 ok(strcmp(buffer
, " \r") == 0,
4647 "EM_GETTEXTEX returned incorrect string\n");
4649 /* Test number of lines reported after EM_REPLACESEL */
4650 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4651 ok(r
== 2, "EM_GETLINECOUNT returned %d, expected 2\n", r
);
4653 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4654 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\r\r\n\r\r");
4655 ok(r
== 5, "EM_REPLACESEL returned %d, expected 5\n", r
);
4656 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4657 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4658 ok(cr
.cpMin
== 3, "EM_EXGETSEL returned cpMin=%d, expected 3\n", cr
.cpMin
);
4659 ok(cr
.cpMax
== 3, "EM_EXGETSEL returned cpMax=%d, expected 3\n", cr
.cpMax
);
4661 /* Test the actual string */
4663 getText
.codepage
= CP_ACP
;
4664 getText
.flags
= GT_DEFAULT
;
4665 getText
.lpDefaultChar
= NULL
;
4666 getText
.lpUsedDefChar
= NULL
;
4667 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4668 ok(strcmp(buffer
, " \r\r") == 0,
4669 "EM_GETTEXTEX returned incorrect string\n");
4671 /* Test number of lines reported after EM_REPLACESEL */
4672 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4673 ok(r
== 3, "EM_GETLINECOUNT returned %d, expected 3\n", r
);
4675 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4676 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\rX\r\n\r\r");
4677 ok(r
== 6, "EM_REPLACESEL returned %d, expected 6\n", r
);
4678 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4679 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4680 ok(cr
.cpMin
== 5, "EM_EXGETSEL returned cpMin=%d, expected 5\n", cr
.cpMin
);
4681 ok(cr
.cpMax
== 5, "EM_EXGETSEL returned cpMax=%d, expected 5\n", cr
.cpMax
);
4683 /* Test the actual string */
4685 getText
.codepage
= CP_ACP
;
4686 getText
.flags
= GT_DEFAULT
;
4687 getText
.lpDefaultChar
= NULL
;
4688 getText
.lpUsedDefChar
= NULL
;
4689 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4690 ok(strcmp(buffer
, "\rX\r\r\r") == 0,
4691 "EM_GETTEXTEX returned incorrect string\n");
4693 /* Test number of lines reported after EM_REPLACESEL */
4694 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4695 ok(r
== 5, "EM_GETLINECOUNT returned %d, expected 5\n", r
);
4697 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4698 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\n\n");
4699 ok(2 == r
, "EM_REPLACESEL returned %d, expected 2\n", r
);
4700 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4701 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4702 ok(cr
.cpMin
== 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr
.cpMin
);
4703 ok(cr
.cpMax
== 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr
.cpMax
);
4705 /* Test the actual string */
4707 getText
.codepage
= CP_ACP
;
4708 getText
.flags
= GT_DEFAULT
;
4709 getText
.lpDefaultChar
= NULL
;
4710 getText
.lpUsedDefChar
= NULL
;
4711 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4712 ok(strcmp(buffer
, "\r\r") == 0,
4713 "EM_GETTEXTEX returned incorrect string\n");
4715 /* Test number of lines reported after EM_REPLACESEL */
4716 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4717 ok(r
== 3, "EM_GETLINECOUNT returned %d, expected 3\n", r
);
4719 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4720 r
= SendMessageA(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"\n\n\n\n\r\r\r\r\n");
4721 ok(r
== 9, "EM_REPLACESEL returned %d, expected 9\n", r
);
4722 r
= SendMessageA(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4723 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4724 ok(cr
.cpMin
== 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr
.cpMin
);
4725 ok(cr
.cpMax
== 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr
.cpMax
);
4727 /* Test the actual string */
4729 getText
.codepage
= CP_ACP
;
4730 getText
.flags
= GT_DEFAULT
;
4731 getText
.lpDefaultChar
= NULL
;
4732 getText
.lpUsedDefChar
= NULL
;
4733 SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buffer
);
4734 ok(strcmp(buffer
, "\r\r\r\r\r\r ") == 0,
4735 "EM_GETTEXTEX returned incorrect string\n");
4737 /* Test number of lines reported after EM_REPLACESEL */
4738 r
= SendMessageA(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4739 ok(r
== 7, "EM_GETLINECOUNT returned %d, expected 7\n", r
);
4742 /* This is needed to avoid interferring with keybd_event calls
4743 * on other tests that simulate keyboard events. */
4744 SendMessageA(hwndRichEdit
, WM_SETREDRAW
, TRUE
, 0);
4746 DestroyWindow(hwndRichEdit
);
4749 /* Native riched20 inspects the keyboard state (e.g. GetKeyState)
4750 * to test the state of the modifiers (Ctrl/Alt/Shift).
4752 * Therefore Ctrl-<key> keystrokes need to be simulated with
4753 * keybd_event or by using SetKeyboardState to set the modifiers
4754 * and SendMessage to simulate the keystrokes.
4756 static LRESULT
send_ctrl_key(HWND hwnd
, UINT key
)
4759 hold_key(VK_CONTROL
);
4760 result
= SendMessageA(hwnd
, WM_KEYDOWN
, key
, 1);
4761 release_key(VK_CONTROL
);
4765 static void test_WM_PASTE(void)
4768 char buffer
[1024] = {0};
4769 const char* text1
= "testing paste\r";
4770 const char* text1_step1
= "testing paste\r\ntesting paste\r\n";
4771 const char* text1_after
= "testing paste\r\n";
4772 const char* text2
= "testing paste\r\rtesting paste";
4773 const char* text2_after
= "testing paste\r\n\r\ntesting paste";
4774 const char* text3
= "testing paste\r\npaste\r\ntesting paste";
4775 HWND hwndRichEdit
= new_richedit(NULL
);
4777 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
4778 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 14);
4780 send_ctrl_key(hwndRichEdit
, 'C'); /* Copy */
4781 SendMessageA(hwndRichEdit
, EM_SETSEL
, 14, 14);
4782 send_ctrl_key(hwndRichEdit
, 'V'); /* Paste */
4783 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4784 /* Pasted text should be visible at this step */
4785 result
= strcmp(text1_step1
, buffer
);
4787 "test paste: strcmp = %i, text='%s'\n", result
, buffer
);
4789 send_ctrl_key(hwndRichEdit
, 'Z'); /* Undo */
4790 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4791 /* Text should be the same as before (except for \r -> \r\n conversion) */
4792 result
= strcmp(text1_after
, buffer
);
4794 "test paste: strcmp = %i, text='%s'\n", result
, buffer
);
4796 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
4797 SendMessageA(hwndRichEdit
, EM_SETSEL
, 8, 13);
4798 send_ctrl_key(hwndRichEdit
, 'C'); /* Copy */
4799 SendMessageA(hwndRichEdit
, EM_SETSEL
, 14, 14);
4800 send_ctrl_key(hwndRichEdit
, 'V'); /* Paste */
4801 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4802 /* Pasted text should be visible at this step */
4803 result
= strcmp(text3
, buffer
);
4805 "test paste: strcmp = %i\n", result
);
4806 send_ctrl_key(hwndRichEdit
, 'Z'); /* Undo */
4807 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4808 /* Text should be the same as before (except for \r -> \r\n conversion) */
4809 result
= strcmp(text2_after
, buffer
);
4811 "test paste: strcmp = %i\n", result
);
4812 send_ctrl_key(hwndRichEdit
, 'Y'); /* Redo */
4813 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4814 /* Text should revert to post-paste state */
4815 result
= strcmp(buffer
,text3
);
4817 "test paste: strcmp = %i\n", result
);
4819 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4820 /* Send WM_CHAR to simulate Ctrl-V */
4821 SendMessageA(hwndRichEdit
, WM_CHAR
, 22,
4822 (MapVirtualKeyA('V', MAPVK_VK_TO_VSC
) << 16) | 1);
4823 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4824 /* Shouldn't paste because pasting is handled by WM_KEYDOWN */
4825 result
= strcmp(buffer
,"");
4827 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4829 /* Send keystrokes with WM_KEYDOWN after setting the modifiers
4830 * with SetKeyboard state. */
4832 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4833 /* Simulates paste (Ctrl-V) */
4834 hold_key(VK_CONTROL
);
4835 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'V',
4836 (MapVirtualKeyA('V', MAPVK_VK_TO_VSC
) << 16) | 1);
4837 release_key(VK_CONTROL
);
4838 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4839 result
= strcmp(buffer
,"paste");
4841 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4843 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
4844 SendMessageA(hwndRichEdit
, EM_SETSEL
, 0, 7);
4845 /* Simulates copy (Ctrl-C) */
4846 hold_key(VK_CONTROL
);
4847 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'C',
4848 (MapVirtualKeyA('C', MAPVK_VK_TO_VSC
) << 16) | 1);
4849 release_key(VK_CONTROL
);
4850 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4851 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
4852 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4853 result
= strcmp(buffer
,"testing");
4855 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4857 /* Cut with WM_KEYDOWN to simulate Ctrl-X */
4858 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"cut");
4859 /* Simulates select all (Ctrl-A) */
4860 hold_key(VK_CONTROL
);
4861 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'A',
4862 (MapVirtualKeyA('A', MAPVK_VK_TO_VSC
) << 16) | 1);
4863 /* Simulates select cut (Ctrl-X) */
4864 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'X',
4865 (MapVirtualKeyA('X', MAPVK_VK_TO_VSC
) << 16) | 1);
4866 release_key(VK_CONTROL
);
4867 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4868 result
= strcmp(buffer
,"");
4870 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4871 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4872 SendMessageA(hwndRichEdit
, WM_PASTE
, 0, 0);
4873 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4874 result
= strcmp(buffer
,"cut\r\n");
4875 todo_wine
ok(result
== 0,
4876 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4877 /* Simulates undo (Ctrl-Z) */
4878 hold_key(VK_CONTROL
);
4879 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'Z',
4880 (MapVirtualKeyA('Z', MAPVK_VK_TO_VSC
) << 16) | 1);
4881 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4882 result
= strcmp(buffer
,"");
4884 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4885 /* Simulates redo (Ctrl-Y) */
4886 SendMessageA(hwndRichEdit
, WM_KEYDOWN
, 'Y',
4887 (MapVirtualKeyA('Y', MAPVK_VK_TO_VSC
) << 16) | 1);
4888 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
4889 result
= strcmp(buffer
,"cut\r\n");
4890 todo_wine
ok(result
== 0,
4891 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4892 release_key(VK_CONTROL
);
4894 DestroyWindow(hwndRichEdit
);
4897 static void test_EM_FORMATRANGE(void)
4899 int r
, i
, tpp_x
, tpp_y
;
4901 HWND hwndRichEdit
= new_richedit(NULL
);
4903 BOOL skip_non_english
;
4904 static const struct {
4905 const char *string
; /* The string */
4906 int first
; /* First 'pagebreak', 0 for don't care */
4907 int second
; /* Second 'pagebreak', 0 for don't care */
4909 {"WINE wine", 0, 0},
4910 {"WINE wineWine", 0, 0},
4911 {"WINE\r\nwine\r\nwine", 5, 10},
4912 {"WINE\r\nWINEwine\r\nWINEwine", 5, 14},
4913 {"WINE\r\n\r\nwine\r\nwine", 5, 6}
4916 skip_non_english
= (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH
);
4917 if (skip_non_english
)
4918 skip("Skipping some tests on non-English platform\n");
4920 hdc
= GetDC(hwndRichEdit
);
4921 ok(hdc
!= NULL
, "Could not get HDC\n");
4923 /* Calculate the twips per pixel */
4924 tpp_x
= 1440 / GetDeviceCaps(hdc
, LOGPIXELSX
);
4925 tpp_y
= 1440 / GetDeviceCaps(hdc
, LOGPIXELSY
);
4927 /* Test the simple case where all the text fits in the page rect. */
4928 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
4929 fr
.hdc
= fr
.hdcTarget
= hdc
;
4930 fr
.rc
.top
= fr
.rcPage
.top
= fr
.rc
.left
= fr
.rcPage
.left
= 0;
4931 fr
.rc
.right
= fr
.rcPage
.right
= 500 * tpp_x
;
4932 fr
.rc
.bottom
= fr
.rcPage
.bottom
= 500 * tpp_y
;
4935 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, FALSE
, (LPARAM
)&fr
);
4936 todo_wine
ok(r
== 2, "r=%d expected r=2\n", r
);
4938 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"ab");
4939 fr
.rc
.bottom
= fr
.rcPage
.bottom
;
4940 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, FALSE
, (LPARAM
)&fr
);
4941 todo_wine
ok(r
== 3, "r=%d expected r=3\n", r
);
4943 SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, FALSE
, 0);
4945 for (i
= 0; i
< sizeof(fmtstrings
)/sizeof(fmtstrings
[0]); i
++)
4947 GETTEXTLENGTHEX gtl
;
4951 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)fmtstrings
[i
].string
);
4953 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
4954 gtl
.codepage
= CP_ACP
;
4955 len
= SendMessageA(hwndRichEdit
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
4957 /* Get some size information for the string */
4958 GetTextExtentPoint32A(hdc
, fmtstrings
[i
].string
, strlen(fmtstrings
[i
].string
), &stringsize
);
4960 /* Define the box to be half the width needed and a bit larger than the height.
4961 * Changes to the width means we have at least 2 pages. Changes to the height
4962 * is done so we can check the changing of fr.rc.bottom.
4964 fr
.hdc
= fr
.hdcTarget
= hdc
;
4965 fr
.rc
.top
= fr
.rcPage
.top
= fr
.rc
.left
= fr
.rcPage
.left
= 0;
4966 fr
.rc
.right
= fr
.rcPage
.right
= (stringsize
.cx
/ 2) * tpp_x
;
4967 fr
.rc
.bottom
= fr
.rcPage
.bottom
= (stringsize
.cy
+ 10) * tpp_y
;
4969 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, 0);
4971 ok(r
== len
, "Expected %d, got %d\n", len
, r
);
4974 /* We know that the page can't hold the full string. See how many characters
4975 * are on the first one
4979 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, (LPARAM
)&fr
);
4981 if (! skip_non_english
)
4982 ok(fr
.rc
.bottom
== (stringsize
.cy
* tpp_y
), "Expected bottom to be %d, got %d\n", (stringsize
.cy
* tpp_y
), fr
.rc
.bottom
);
4984 if (fmtstrings
[i
].first
)
4986 ok(r
== fmtstrings
[i
].first
, "Expected %d, got %d\n", fmtstrings
[i
].first
, r
);
4989 ok(r
< len
, "Expected < %d, got %d\n", len
, r
);
4991 /* Do another page */
4993 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, (LPARAM
)&fr
);
4994 if (fmtstrings
[i
].second
)
4996 ok(r
== fmtstrings
[i
].second
, "Expected %d, got %d\n", fmtstrings
[i
].second
, r
);
4998 else if (! skip_non_english
)
4999 ok (r
< len
, "Expected < %d, got %d\n", len
, r
);
5001 /* There is at least on more page, but we don't care */
5003 r
= SendMessageA(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, 0);
5005 ok(r
== len
, "Expected %d, got %d\n", len
, r
);
5009 ReleaseDC(NULL
, hdc
);
5010 DestroyWindow(hwndRichEdit
);
5013 static int nCallbackCount
= 0;
5015 static DWORD CALLBACK
EditStreamCallback(DWORD_PTR dwCookie
, LPBYTE pbBuff
,
5018 const char text
[] = {'t','e','s','t'};
5020 if (sizeof(text
) <= cb
)
5022 if ((int)dwCookie
!= nCallbackCount
)
5028 memcpy (pbBuff
, text
, sizeof(text
));
5029 *pcb
= sizeof(text
);
5036 return 1; /* indicates callback failed */
5039 static DWORD CALLBACK
test_EM_STREAMIN_esCallback(DWORD_PTR dwCookie
,
5044 const char** str
= (const char**)dwCookie
;
5045 int size
= strlen(*str
);
5051 memcpy(pbBuff
, *str
, *pcb
);
5057 static DWORD CALLBACK
test_EM_STREAMIN_esCallback_UTF8Split(DWORD_PTR dwCookie
,
5062 DWORD
*phase
= (DWORD
*)dwCookie
;
5065 static const char first
[] = "\xef\xbb\xbf\xc3\x96\xc3";
5066 *pcb
= sizeof(first
) - 1;
5067 memcpy(pbBuff
, first
, *pcb
);
5068 }else if(*phase
== 1){
5069 static const char second
[] = "\x8f\xc3\x8b";
5070 *pcb
= sizeof(second
) - 1;
5071 memcpy(pbBuff
, second
, *pcb
);
5080 struct StringWithLength
{
5085 /* This callback is used to handled the null characters in a string. */
5086 static DWORD CALLBACK
test_EM_STREAMIN_esCallback2(DWORD_PTR dwCookie
,
5091 struct StringWithLength
* str
= (struct StringWithLength
*)dwCookie
;
5092 int size
= str
->length
;
5098 memcpy(pbBuff
, str
->buffer
, *pcb
);
5099 str
->buffer
+= *pcb
;
5100 str
->length
-= *pcb
;
5105 static void test_EM_STREAMIN(void)
5107 HWND hwndRichEdit
= new_richedit(NULL
);
5111 char buffer
[1024] = {0}, tmp
[16];
5114 const char * streamText0
= "{\\rtf1 TestSomeText}";
5115 const char * streamText0a
= "{\\rtf1 TestSomeText\\par}";
5116 const char * streamText0b
= "{\\rtf1 TestSomeText\\par\\par}";
5119 const char * streamText1
=
5120 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n"
5121 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n"
5124 /* In richedit 2.0 mode, this should NOT be accepted, unlike 1.0 */
5125 const char * streamText2
=
5126 "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;"
5127 "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255"
5128 "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 "
5129 "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 "
5130 "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 "
5131 "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 "
5132 "\\tx11448 \\tx11872 \\tx12296 \\tx12720 \\tx13144 \\cf2 RichEdit1\\line }";
5134 const char * streamText3
= "RichEdit1";
5136 const char * streamTextUTF8BOM
= "\xef\xbb\xbfTestUTF8WithBOM";
5138 const char * streamText4
=
5139 "This text just needs to be long enough to cause run to be split onto "
5140 "two separate lines and make sure the null terminating character is "
5141 "handled properly.\0";
5143 const WCHAR UTF8Split_exp
[4] = {0xd6, 0xcf, 0xcb, 0};
5145 int length4
= strlen(streamText4
) + 1;
5146 struct StringWithLength cookieForStream4
= {
5148 (char *)streamText4
,
5151 const WCHAR streamText5
[] = { 'T', 'e', 's', 't', 'S', 'o', 'm', 'e', 'T', 'e', 'x', 't' };
5152 int length5
= sizeof(streamText5
) / sizeof(WCHAR
);
5153 struct StringWithLength cookieForStream5
= {
5154 sizeof(streamText5
),
5155 (char *)streamText5
,
5158 /* Minimal test without \par at the end */
5159 es
.dwCookie
= (DWORD_PTR
)&streamText0
;
5161 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5162 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5163 ok(result
== 12, "got %ld, expected %d\n", result
, 12);
5165 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5167 "EM_STREAMIN: Test 0 returned %ld, expected 12\n", result
);
5168 result
= strcmp (buffer
,"TestSomeText");
5170 "EM_STREAMIN: Test 0 set wrong text: Result: %s\n",buffer
);
5171 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es
.dwError
, 0);
5173 /* Native richedit 2.0 ignores last \par */
5175 es
.dwCookie
= (DWORD_PTR
)&ptr
;
5177 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5178 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5179 ok(result
== 12, "got %ld, expected %d\n", result
, 12);
5181 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5183 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result
);
5184 result
= strcmp (buffer
,"TestSomeText");
5186 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer
);
5187 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0-a set error %d, expected %d\n", es
.dwError
, 0);
5189 /* Native richedit 2.0 ignores last \par, next-to-last \par appears */
5190 es
.dwCookie
= (DWORD_PTR
)&streamText0b
;
5192 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5193 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5194 ok(result
== 13, "got %ld, expected %d\n", result
, 13);
5196 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5198 "EM_STREAMIN: Test 0-b returned %ld, expected 14\n", result
);
5199 result
= strcmp (buffer
,"TestSomeText\r\n");
5201 "EM_STREAMIN: Test 0-b set wrong text: Result: %s\n",buffer
);
5202 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0-b set error %d, expected %d\n", es
.dwError
, 0);
5204 /* Show that when using SFF_SELECTION the last \par is not ignored. */
5206 es
.dwCookie
= (DWORD_PTR
)&ptr
;
5208 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5209 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5210 ok(result
== 12, "got %ld, expected %d\n", result
, 12);
5212 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5214 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result
);
5215 result
= strcmp (buffer
,"TestSomeText");
5217 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer
);
5218 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0-a set error %d, expected %d\n", es
.dwError
, 0);
5222 result
= SendMessageA(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&range
);
5223 ok (result
== 13, "got %ld\n", result
);
5226 es
.dwCookie
= (DWORD_PTR
)&ptr
;
5228 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5230 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SFF_SELECTION
| SF_RTF
, (LPARAM
)&es
);
5231 ok(result
== 13, "got %ld, expected 13\n", result
);
5233 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5235 "EM_STREAMIN: Test SFF_SELECTION 0-a returned %ld, expected 14\n", result
);
5236 result
= strcmp (buffer
,"TestSomeText\r\n");
5238 "EM_STREAMIN: Test SFF_SELECTION 0-a set wrong text: Result: %s\n",buffer
);
5239 ok(es
.dwError
== 0, "EM_STREAMIN: Test SFF_SELECTION 0-a set error %d, expected %d\n", es
.dwError
, 0);
5241 es
.dwCookie
= (DWORD_PTR
)&streamText1
;
5243 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5244 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5245 ok(result
== 12, "got %ld, expected %d\n", result
, 12);
5247 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5249 "EM_STREAMIN: Test 1 returned %ld, expected 12\n", result
);
5250 result
= strcmp (buffer
,"TestSomeText");
5252 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer
);
5253 ok(es
.dwError
== 0, "EM_STREAMIN: Test 1 set error %d, expected %d\n", es
.dwError
, 0);
5255 es
.dwCookie
= (DWORD_PTR
)&streamText2
;
5257 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5258 ok(result
== 0, "got %ld, expected %d\n", result
, 0);
5260 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5262 "EM_STREAMIN: Test 2 returned %ld, expected 0\n", result
);
5263 ok(!buffer
[0], "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
5264 ok(es
.dwError
== -16, "EM_STREAMIN: Test 2 set error %d, expected %d\n", es
.dwError
, -16);
5266 es
.dwCookie
= (DWORD_PTR
)&streamText3
;
5268 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5269 ok(result
== 0, "got %ld, expected %d\n", result
, 0);
5271 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5273 "EM_STREAMIN: Test 3 returned %ld, expected 0\n", result
);
5274 ok(!buffer
[0], "EM_STREAMIN: Test 3 set wrong text: Result: %s\n",buffer
);
5275 ok(es
.dwError
== -16, "EM_STREAMIN: Test 3 set error %d, expected %d\n", es
.dwError
, -16);
5277 es
.dwCookie
= (DWORD_PTR
)&streamTextUTF8BOM
;
5279 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5280 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
5281 ok(result
== 18, "got %ld, expected %d\n", result
, 18);
5283 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5285 "EM_STREAMIN: Test UTF8WithBOM returned %ld, expected 15\n", result
);
5286 result
= strcmp (buffer
,"TestUTF8WithBOM");
5288 "EM_STREAMIN: Test UTF8WithBOM set wrong text: Result: %s\n",buffer
);
5289 ok(es
.dwError
== 0, "EM_STREAMIN: Test UTF8WithBOM set error %d, expected %d\n", es
.dwError
, 0);
5292 es
.dwCookie
= (DWORD_PTR
)&phase
;
5294 es
.pfnCallback
= test_EM_STREAMIN_esCallback_UTF8Split
;
5295 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
5296 ok(result
== 8, "got %ld\n", result
);
5298 WideCharToMultiByte(CP_ACP
, 0, UTF8Split_exp
, -1, tmp
, sizeof(tmp
), NULL
, NULL
);
5300 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5302 "EM_STREAMIN: Test UTF8Split returned %ld\n", result
);
5303 result
= memcmp (buffer
, tmp
, 3);
5305 "EM_STREAMIN: Test UTF8Split set wrong text: Result: %s\n",buffer
);
5306 ok(es
.dwError
== 0, "EM_STREAMIN: Test UTF8Split set error %d, expected %d\n", es
.dwError
, 0);
5308 es
.dwCookie
= (DWORD_PTR
)&cookieForStream4
;
5310 es
.pfnCallback
= test_EM_STREAMIN_esCallback2
;
5311 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
5312 ok(result
== length4
, "got %ld, expected %d\n", result
, length4
);
5314 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5315 ok (result
== length4
,
5316 "EM_STREAMIN: Test 4 returned %ld, expected %d\n", result
, length4
);
5317 ok(es
.dwError
== 0, "EM_STREAMIN: Test 4 set error %d, expected %d\n", es
.dwError
, 0);
5319 es
.dwCookie
= (DWORD_PTR
)&cookieForStream5
;
5321 es
.pfnCallback
= test_EM_STREAMIN_esCallback2
;
5322 result
= SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
| SF_UNICODE
, (LPARAM
)&es
);
5323 ok(result
== sizeof(streamText5
), "got %ld, expected %u\n", result
, (UINT
)sizeof(streamText5
));
5325 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5326 ok (result
== length5
,
5327 "EM_STREAMIN: Test 5 returned %ld, expected %d\n", result
, length5
);
5328 ok(es
.dwError
== 0, "EM_STREAMIN: Test 5 set error %d, expected %d\n", es
.dwError
, 0);
5330 DestroyWindow(hwndRichEdit
);
5333 static void test_EM_StreamIn_Undo(void)
5335 /* The purpose of this test is to determine when a EM_StreamIn should be
5336 * undoable. This is important because WM_PASTE currently uses StreamIn and
5337 * pasting should always be undoable but streaming isn't always.
5340 * StreamIn plain text without SFF_SELECTION.
5341 * StreamIn plain text with SFF_SELECTION set but a zero-length selection
5342 * StreamIn plain text with SFF_SELECTION and a valid, normal selection
5343 * StreamIn plain text with SFF_SELECTION and a backwards-selection (from>to)
5344 * Feel free to add tests for other text modes or StreamIn things.
5348 HWND hwndRichEdit
= new_richedit(NULL
);
5351 char buffer
[1024] = {0};
5352 const char randomtext
[] = "Some text";
5354 es
.pfnCallback
= EditStreamCallback
;
5356 /* StreamIn, no SFF_SELECTION */
5357 es
.dwCookie
= nCallbackCount
;
5358 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
5359 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)randomtext
);
5360 SendMessageA(hwndRichEdit
, EM_SETSEL
,0,0);
5361 SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
5362 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5363 result
= strcmp (buffer
,"test");
5365 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer
);
5367 result
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
5368 ok (result
== FALSE
,
5369 "EM_STREAMIN without SFF_SELECTION wrongly allows undo\n");
5371 /* StreamIn, SFF_SELECTION, but nothing selected */
5372 es
.dwCookie
= nCallbackCount
;
5373 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
5374 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)randomtext
);
5375 SendMessageA(hwndRichEdit
, EM_SETSEL
,0,0);
5376 SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
|SFF_SELECTION
, (LPARAM
)&es
);
5377 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5378 result
= strcmp (buffer
,"testSome text");
5380 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
5382 result
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
5384 "EM_STREAMIN with SFF_SELECTION but no selection set "
5385 "should create an undo\n");
5387 /* StreamIn, SFF_SELECTION, with a selection */
5388 es
.dwCookie
= nCallbackCount
;
5389 SendMessageA(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
5390 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)randomtext
);
5391 SendMessageA(hwndRichEdit
, EM_SETSEL
,4,5);
5392 SendMessageA(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
|SFF_SELECTION
, (LPARAM
)&es
);
5393 SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buffer
);
5394 result
= strcmp (buffer
,"Sometesttext");
5396 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
5398 result
= SendMessageA(hwndRichEdit
, EM_CANUNDO
, 0, 0);
5400 "EM_STREAMIN with SFF_SELECTION and selection set "
5401 "should create an undo\n");
5403 DestroyWindow(hwndRichEdit
);
5406 static BOOL
is_em_settextex_supported(HWND hwnd
)
5408 SETTEXTEX stex
= { ST_DEFAULT
, CP_ACP
};
5409 return SendMessageA(hwnd
, EM_SETTEXTEX
, (WPARAM
)&stex
, 0) != 0;
5412 static void test_unicode_conversions(void)
5414 static const WCHAR tW
[] = {'t',0};
5415 static const WCHAR teW
[] = {'t','e',0};
5416 static const WCHAR textW
[] = {'t','e','s','t',0};
5417 static const char textA
[] = "test";
5421 int em_settextex_supported
, ret
;
5423 #define set_textA(hwnd, wm_set_text, txt) \
5425 SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; \
5426 UNREFERENCED_LOCAL_VARIABLE(stex); \
5427 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
5428 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
5429 ret = SendMessageA(hwnd, wm_set_text, wparam, (LPARAM)txt); \
5430 ok(ret, "SendMessageA(%02x) error %u\n", wm_set_text, GetLastError()); \
5432 #define expect_textA(hwnd, wm_get_text, txt) \
5434 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
5435 UNREFERENCED_LOCAL_VARIABLE(gtex); \
5436 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
5437 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
5438 memset(bufA, 0xAA, sizeof(bufA)); \
5439 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
5440 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
5441 ret = lstrcmpA(bufA, txt); \
5442 ok(!ret, "%02x: strings do not match: expected %s got %s\n", wm_get_text, txt, bufA); \
5445 #define set_textW(hwnd, wm_set_text, txt) \
5447 SETTEXTEX stex = { ST_DEFAULT, 1200 }; \
5448 UNREFERENCED_LOCAL_VARIABLE(stex); \
5449 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
5450 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
5451 ret = SendMessageW(hwnd, wm_set_text, wparam, (LPARAM)txt); \
5452 ok(ret, "SendMessageW(%02x) error %u\n", wm_set_text, GetLastError()); \
5454 #define expect_textW(hwnd, wm_get_text, txt) \
5456 GETTEXTEX gtex = { 64, GT_DEFAULT, 1200, NULL, NULL }; \
5457 UNREFERENCED_LOCAL_VARIABLE(gtex); \
5458 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
5459 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
5460 memset(bufW, 0xAA, sizeof(bufW)); \
5461 ret = SendMessageW(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
5462 ok(ret, "SendMessageW(%02x) error %u\n", wm_get_text, GetLastError()); \
5463 ret = lstrcmpW(bufW, txt); \
5464 ok(!ret, "%02x: strings do not match: expected[0] %x got[0] %x\n", wm_get_text, txt[0], bufW[0]); \
5466 #define expect_empty(hwnd, wm_get_text) \
5468 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
5469 UNREFERENCED_LOCAL_VARIABLE(gtex); \
5470 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
5471 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
5472 memset(bufA, 0xAA, sizeof(bufA)); \
5473 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
5474 ok(!ret, "empty richedit should return 0, got %d\n", ret); \
5475 ok(!*bufA, "empty richedit should return empty string, got %s\n", bufA); \
5478 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
,
5479 0, 0, 200, 60, 0, 0, 0, 0);
5480 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5482 ret
= IsWindowUnicode(hwnd
);
5483 ok(ret
, "RichEdit20W should be unicode under NT\n");
5485 /* EM_SETTEXTEX is supported starting from version 3.0 */
5486 em_settextex_supported
= is_em_settextex_supported(hwnd
);
5487 trace("EM_SETTEXTEX is %ssupported on this platform\n",
5488 em_settextex_supported
? "" : "NOT ");
5490 expect_empty(hwnd
, WM_GETTEXT
);
5491 expect_empty(hwnd
, EM_GETTEXTEX
);
5493 ret
= SendMessageA(hwnd
, WM_CHAR
, textW
[0], 0);
5494 ok(!ret
, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret
);
5495 expect_textA(hwnd
, WM_GETTEXT
, "t");
5496 expect_textA(hwnd
, EM_GETTEXTEX
, "t");
5497 expect_textW(hwnd
, EM_GETTEXTEX
, tW
);
5499 ret
= SendMessageA(hwnd
, WM_CHAR
, textA
[1], 0);
5500 ok(!ret
, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret
);
5501 expect_textA(hwnd
, WM_GETTEXT
, "te");
5502 expect_textA(hwnd
, EM_GETTEXTEX
, "te");
5503 expect_textW(hwnd
, EM_GETTEXTEX
, teW
);
5505 set_textA(hwnd
, WM_SETTEXT
, NULL
);
5506 expect_empty(hwnd
, WM_GETTEXT
);
5507 expect_empty(hwnd
, EM_GETTEXTEX
);
5509 set_textA(hwnd
, WM_SETTEXT
, textA
);
5510 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5511 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5512 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5514 if (em_settextex_supported
)
5516 set_textA(hwnd
, EM_SETTEXTEX
, textA
);
5517 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5518 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5519 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5522 set_textW(hwnd
, WM_SETTEXT
, textW
);
5523 expect_textW(hwnd
, WM_GETTEXT
, textW
);
5524 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5525 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5526 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5528 if (em_settextex_supported
)
5530 set_textW(hwnd
, EM_SETTEXTEX
, textW
);
5531 expect_textW(hwnd
, WM_GETTEXT
, textW
);
5532 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5533 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5534 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5536 DestroyWindow(hwnd
);
5538 hwnd
= CreateWindowExA(0, "RichEdit20A", NULL
, WS_POPUP
,
5539 0, 0, 200, 60, 0, 0, 0, 0);
5540 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5542 ret
= IsWindowUnicode(hwnd
);
5543 ok(!ret
, "RichEdit20A should NOT be unicode\n");
5545 set_textA(hwnd
, WM_SETTEXT
, textA
);
5546 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5547 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5548 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5550 if (em_settextex_supported
)
5552 set_textA(hwnd
, EM_SETTEXTEX
, textA
);
5553 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5554 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5555 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5558 set_textW(hwnd
, WM_SETTEXT
, textW
);
5559 expect_textW(hwnd
, WM_GETTEXT
, textW
);
5560 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5561 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5562 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5564 if (em_settextex_supported
)
5566 set_textW(hwnd
, EM_SETTEXTEX
, textW
);
5567 expect_textW(hwnd
, WM_GETTEXT
, textW
);
5568 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5569 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5570 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5572 DestroyWindow(hwnd
);
5575 static void test_WM_CHAR(void)
5579 const char * char_list
= "abc\rabc\r";
5580 const char * expected_content_single
= "abcabc";
5581 const char * expected_content_multi
= "abc\r\nabc\r\n";
5582 char buffer
[64] = {0};
5585 /* single-line control must IGNORE carriage returns */
5586 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
,
5587 0, 0, 200, 60, 0, 0, 0, 0);
5588 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5591 while (*p
!= '\0') {
5592 SendMessageA(hwnd
, WM_KEYDOWN
, *p
, 1);
5593 ret
= SendMessageA(hwnd
, WM_CHAR
, *p
, 1);
5594 ok(ret
== 0, "WM_CHAR('%c') ret=%d\n", *p
, ret
);
5595 SendMessageA(hwnd
, WM_KEYUP
, *p
, 1);
5599 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5600 ret
= strcmp(buffer
, expected_content_single
);
5601 ok(ret
== 0, "WM_GETTEXT recovered incorrect string!\n");
5603 DestroyWindow(hwnd
);
5605 /* multi-line control inserts CR normally */
5606 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
|ES_MULTILINE
,
5607 0, 0, 200, 60, 0, 0, 0, 0);
5608 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5611 while (*p
!= '\0') {
5612 SendMessageA(hwnd
, WM_KEYDOWN
, *p
, 1);
5613 ret
= SendMessageA(hwnd
, WM_CHAR
, *p
, 1);
5614 ok(ret
== 0, "WM_CHAR('%c') ret=%d\n", *p
, ret
);
5615 SendMessageA(hwnd
, WM_KEYUP
, *p
, 1);
5619 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5620 ret
= strcmp(buffer
, expected_content_multi
);
5621 ok(ret
== 0, "WM_GETTEXT recovered incorrect string!\n");
5623 DestroyWindow(hwnd
);
5626 static void test_EM_GETTEXTLENGTHEX(void)
5629 GETTEXTLENGTHEX gtl
;
5631 const char * base_string
= "base string";
5632 const char * test_string
= "a\nb\n\n\r\n";
5633 const char * test_string_after
= "a";
5634 const char * test_string_2
= "a\rtest\rstring";
5635 char buffer
[64] = {0};
5638 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
,
5639 0, 0, 200, 60, 0, 0, 0, 0);
5640 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5642 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5643 gtl
.codepage
= CP_ACP
;
5644 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5645 ok(ret
== 0, "ret %d\n",ret
);
5647 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5648 gtl
.codepage
= CP_ACP
;
5649 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5650 ok(ret
== 0, "ret %d\n",ret
);
5652 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)base_string
);
5654 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5655 gtl
.codepage
= CP_ACP
;
5656 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5657 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
5659 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5660 gtl
.codepage
= CP_ACP
;
5661 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5662 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
5664 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)test_string
);
5666 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5667 gtl
.codepage
= CP_ACP
;
5668 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5669 ok(ret
== 1, "ret %d\n",ret
);
5671 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5672 gtl
.codepage
= CP_ACP
;
5673 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5674 ok(ret
== 1, "ret %d\n",ret
);
5676 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5677 ret
= strcmp(buffer
, test_string_after
);
5678 ok(ret
== 0, "WM_GETTEXT recovered incorrect string!\n");
5680 DestroyWindow(hwnd
);
5683 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
| ES_MULTILINE
,
5684 0, 0, 200, 60, 0, 0, 0, 0);
5685 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5687 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5688 gtl
.codepage
= CP_ACP
;
5689 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5690 ok(ret
== 0, "ret %d\n",ret
);
5692 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5693 gtl
.codepage
= CP_ACP
;
5694 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5695 ok(ret
== 0, "ret %d\n",ret
);
5697 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)base_string
);
5699 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5700 gtl
.codepage
= CP_ACP
;
5701 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5702 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
5704 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5705 gtl
.codepage
= CP_ACP
;
5706 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5707 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
5709 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)test_string_2
);
5711 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5712 gtl
.codepage
= CP_ACP
;
5713 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5714 ok(ret
== strlen(test_string_2
) + 2, "ret %d\n",ret
);
5716 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5717 gtl
.codepage
= CP_ACP
;
5718 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5719 ok(ret
== strlen(test_string_2
), "ret %d\n",ret
);
5721 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)test_string
);
5723 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5724 gtl
.codepage
= CP_ACP
;
5725 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5726 ok(ret
== 10, "ret %d\n",ret
);
5728 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5729 gtl
.codepage
= CP_ACP
;
5730 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5731 ok(ret
== 6, "ret %d\n",ret
);
5733 /* Unicode/NUMCHARS/NUMBYTES */
5734 SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)test_string_2
);
5736 gtl
.flags
= GTL_DEFAULT
;
5737 gtl
.codepage
= 1200;
5738 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5739 ok(ret
== lstrlenA(test_string_2
),
5740 "GTL_DEFAULT gave %i, expected %i\n", ret
, lstrlenA(test_string_2
));
5742 gtl
.flags
= GTL_NUMCHARS
;
5743 gtl
.codepage
= 1200;
5744 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5745 ok(ret
== lstrlenA(test_string_2
),
5746 "GTL_NUMCHARS gave %i, expected %i\n", ret
, lstrlenA(test_string_2
));
5748 gtl
.flags
= GTL_NUMBYTES
;
5749 gtl
.codepage
= 1200;
5750 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5751 ok(ret
== lstrlenA(test_string_2
)*2,
5752 "GTL_NUMBYTES gave %i, expected %i\n", ret
, lstrlenA(test_string_2
)*2);
5754 gtl
.flags
= GTL_PRECISE
;
5755 gtl
.codepage
= 1200;
5756 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5757 ok(ret
== lstrlenA(test_string_2
)*2,
5758 "GTL_PRECISE gave %i, expected %i\n", ret
, lstrlenA(test_string_2
)*2);
5760 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5761 gtl
.codepage
= 1200;
5762 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5763 ok(ret
== lstrlenA(test_string_2
),
5764 "GTL_NUMCHAR | GTL_PRECISE gave %i, expected %i\n", ret
, lstrlenA(test_string_2
));
5766 gtl
.flags
= GTL_NUMCHARS
| GTL_NUMBYTES
;
5767 gtl
.codepage
= 1200;
5768 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5769 ok(ret
== E_INVALIDARG
,
5770 "GTL_NUMCHARS | GTL_NUMBYTES gave %i, expected %i\n", ret
, E_INVALIDARG
);
5772 DestroyWindow(hwnd
);
5776 /* globals that parent and child access when checking event masks & notifications */
5777 static HWND eventMaskEditHwnd
= 0;
5778 static int queriedEventMask
;
5779 static int watchForEventMask
= 0;
5781 /* parent proc that queries the edit's event mask when it gets a WM_COMMAND */
5782 static LRESULT WINAPI
ParentMsgCheckProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
5784 if(message
== WM_COMMAND
&& (watchForEventMask
& (wParam
>> 16)))
5786 queriedEventMask
= SendMessageA(eventMaskEditHwnd
, EM_GETEVENTMASK
, 0, 0);
5788 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
5791 /* test event masks in combination with WM_COMMAND */
5792 static void test_eventMask(void)
5797 const char text
[] = "foo bar\n";
5800 /* register class to capture WM_COMMAND */
5802 cls
.lpfnWndProc
= ParentMsgCheckProcA
;
5805 cls
.hInstance
= GetModuleHandleA(0);
5807 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
5808 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
5809 cls
.lpszMenuName
= NULL
;
5810 cls
.lpszClassName
= "EventMaskParentClass";
5811 if(!RegisterClassA(&cls
)) assert(0);
5813 parent
= CreateWindowA(cls
.lpszClassName
, NULL
, WS_POPUP
|WS_VISIBLE
,
5814 0, 0, 200, 60, NULL
, NULL
, NULL
, NULL
);
5815 ok (parent
!= 0, "Failed to create parent window\n");
5817 eventMaskEditHwnd
= new_richedit(parent
);
5818 ok(eventMaskEditHwnd
!= 0, "Failed to create edit window\n");
5820 eventMask
= ENM_CHANGE
| ENM_UPDATE
;
5821 ret
= SendMessageA(eventMaskEditHwnd
, EM_SETEVENTMASK
, 0, eventMask
);
5822 ok(ret
== ENM_NONE
, "wrong event mask\n");
5823 ret
= SendMessageA(eventMaskEditHwnd
, EM_GETEVENTMASK
, 0, 0);
5824 ok(ret
== eventMask
, "failed to set event mask\n");
5826 /* check what happens when we ask for EN_CHANGE and send WM_SETTEXT */
5827 queriedEventMask
= 0; /* initialize to something other than we expect */
5828 watchForEventMask
= EN_CHANGE
;
5829 ret
= SendMessageA(eventMaskEditHwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
5830 ok(ret
== TRUE
, "failed to set text\n");
5831 /* richedit should mask off ENM_CHANGE when it sends an EN_CHANGE
5832 notification in response to WM_SETTEXT */
5833 ok(queriedEventMask
== (eventMask
& ~ENM_CHANGE
),
5834 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
5836 /* check to see if EN_CHANGE is sent when redraw is turned off */
5837 SendMessageA(eventMaskEditHwnd
, WM_CLEAR
, 0, 0);
5838 ok(IsWindowVisible(eventMaskEditHwnd
), "Window should be visible.\n");
5839 SendMessageA(eventMaskEditHwnd
, WM_SETREDRAW
, FALSE
, 0);
5840 /* redraw is disabled by making the window invisible. */
5841 ok(!IsWindowVisible(eventMaskEditHwnd
), "Window shouldn't be visible.\n");
5842 queriedEventMask
= 0; /* initialize to something other than we expect */
5843 SendMessageA(eventMaskEditHwnd
, EM_REPLACESEL
, 0, (LPARAM
)text
);
5844 ok(queriedEventMask
== (eventMask
& ~ENM_CHANGE
),
5845 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
5846 SendMessageA(eventMaskEditHwnd
, WM_SETREDRAW
, TRUE
, 0);
5847 ok(IsWindowVisible(eventMaskEditHwnd
), "Window should be visible.\n");
5849 /* check to see if EN_UPDATE is sent when the editor isn't visible */
5850 SendMessageA(eventMaskEditHwnd
, WM_CLEAR
, 0, 0);
5851 style
= GetWindowLongA(eventMaskEditHwnd
, GWL_STYLE
);
5852 SetWindowLongA(eventMaskEditHwnd
, GWL_STYLE
, style
& ~WS_VISIBLE
);
5853 ok(!IsWindowVisible(eventMaskEditHwnd
), "Window shouldn't be visible.\n");
5854 watchForEventMask
= EN_UPDATE
;
5855 queriedEventMask
= 0; /* initialize to something other than we expect */
5856 SendMessageA(eventMaskEditHwnd
, EM_REPLACESEL
, 0, (LPARAM
)text
);
5857 ok(queriedEventMask
== 0,
5858 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
5859 SetWindowLongA(eventMaskEditHwnd
, GWL_STYLE
, style
);
5860 ok(IsWindowVisible(eventMaskEditHwnd
), "Window should be visible.\n");
5861 queriedEventMask
= 0; /* initialize to something other than we expect */
5862 SendMessageA(eventMaskEditHwnd
, EM_REPLACESEL
, 0, (LPARAM
)text
);
5863 ok(queriedEventMask
== eventMask
,
5864 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
5867 DestroyWindow(parent
);
5870 static int received_WM_NOTIFY
= 0;
5871 static int modify_at_WM_NOTIFY
= 0;
5872 static BOOL filter_on_WM_NOTIFY
= FALSE
;
5873 static HWND hwndRichedit_WM_NOTIFY
;
5875 static LRESULT WINAPI
WM_NOTIFY_ParentMsgCheckProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
5877 if(message
== WM_NOTIFY
)
5879 received_WM_NOTIFY
= 1;
5880 modify_at_WM_NOTIFY
= SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETMODIFY
, 0, 0);
5881 if (filter_on_WM_NOTIFY
) return TRUE
;
5883 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
5886 static void test_WM_NOTIFY(void)
5891 int sel_start
, sel_end
;
5893 /* register class to capture WM_NOTIFY */
5895 cls
.lpfnWndProc
= WM_NOTIFY_ParentMsgCheckProcA
;
5898 cls
.hInstance
= GetModuleHandleA(0);
5900 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
5901 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
5902 cls
.lpszMenuName
= NULL
;
5903 cls
.lpszClassName
= "WM_NOTIFY_ParentClass";
5904 if(!RegisterClassA(&cls
)) assert(0);
5906 parent
= CreateWindowA(cls
.lpszClassName
, NULL
, WS_POPUP
|WS_VISIBLE
,
5907 0, 0, 200, 60, NULL
, NULL
, NULL
, NULL
);
5908 ok (parent
!= 0, "Failed to create parent window\n");
5910 hwndRichedit_WM_NOTIFY
= new_richedit(parent
);
5911 ok(hwndRichedit_WM_NOTIFY
!= 0, "Failed to create edit window\n");
5913 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETEVENTMASK
, 0, ENM_SELCHANGE
);
5915 /* Notifications for selection change should only be sent when selection
5916 actually changes. EM_SETCHARFORMAT is one message that calls
5917 ME_CommitUndo, which should check whether message should be sent */
5918 received_WM_NOTIFY
= 0;
5919 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
5920 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
5921 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
5922 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
5923 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETCHARFORMAT
, 0, (LPARAM
)&cf2
);
5924 ok(received_WM_NOTIFY
== 0, "Unexpected WM_NOTIFY was sent!\n");
5926 /* WM_SETTEXT should NOT cause a WM_NOTIFY to be sent when selection is
5928 received_WM_NOTIFY
= 0;
5929 modify_at_WM_NOTIFY
= 0;
5930 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_SETTEXT
, 0, (LPARAM
)"sometext");
5931 ok(received_WM_NOTIFY
== 0, "Unexpected WM_NOTIFY was sent!\n");
5932 ok(modify_at_WM_NOTIFY
== 0, "WM_NOTIFY callback saw text flagged as modified!\n");
5934 received_WM_NOTIFY
= 0;
5935 modify_at_WM_NOTIFY
= 0;
5936 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETSEL
, 4, 4);
5937 ok(received_WM_NOTIFY
== 1, "Expected WM_NOTIFY was NOT sent!\n");
5939 received_WM_NOTIFY
= 0;
5940 modify_at_WM_NOTIFY
= 0;
5941 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_SETTEXT
, 0, (LPARAM
)"sometext");
5942 ok(received_WM_NOTIFY
== 1, "Expected WM_NOTIFY was NOT sent!\n");
5943 ok(modify_at_WM_NOTIFY
== 0, "WM_NOTIFY callback saw text flagged as modified!\n");
5945 /* Test for WM_NOTIFY messages with redraw disabled. */
5946 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETSEL
, 0, 0);
5947 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_SETREDRAW
, FALSE
, 0);
5948 received_WM_NOTIFY
= 0;
5949 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_REPLACESEL
, FALSE
, (LPARAM
)"inserted");
5950 ok(received_WM_NOTIFY
== 1, "Expected WM_NOTIFY was NOT sent!\n");
5951 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_SETREDRAW
, TRUE
, 0);
5953 /* Test filtering key events. */
5954 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETSEL
, 0, 0);
5955 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_SETEVENTMASK
, 0, ENM_KEYEVENTS
);
5956 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5957 received_WM_NOTIFY
= 0;
5958 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_KEYDOWN
, VK_RIGHT
, 0);
5959 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5960 ok(sel_start
== 1 && sel_end
== 1,
5961 "selections is incorrectly at (%d,%d)\n", sel_start
, sel_end
);
5962 filter_on_WM_NOTIFY
= TRUE
;
5963 received_WM_NOTIFY
= 0;
5964 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_KEYDOWN
, VK_RIGHT
, 0);
5965 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5966 ok(sel_start
== 1 && sel_end
== 1,
5967 "selections is incorrectly at (%d,%d)\n", sel_start
, sel_end
);
5969 /* test with owner set to NULL */
5970 SetWindowLongPtrA(hwndRichedit_WM_NOTIFY
, GWLP_HWNDPARENT
, 0);
5971 SendMessageA(hwndRichedit_WM_NOTIFY
, WM_KEYDOWN
, VK_RIGHT
, 0);
5972 SendMessageA(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5973 ok(sel_start
== 1 && sel_end
== 1,
5974 "selections is incorrectly at (%d,%d)\n", sel_start
, sel_end
);
5976 DestroyWindow(hwndRichedit_WM_NOTIFY
);
5977 DestroyWindow(parent
);
5980 static int cpMin_EN_LINK
= -1;
5981 static int cpMax_EN_LINK
= -1;
5983 static LRESULT WINAPI
EN_LINK_ParentMsgCheckProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
5985 ENLINK
* enlink
= (ENLINK
*)lParam
;
5986 if(message
== WM_NOTIFY
&& enlink
->nmhdr
.code
== EN_LINK
)
5988 cpMin_EN_LINK
= enlink
->chrg
.cpMin
;
5989 cpMax_EN_LINK
= enlink
->chrg
.cpMax
;
5991 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
5994 static void test_EN_LINK(void)
5998 HWND hwndRichedit_EN_LINK
;
6001 /* register class to capture WM_NOTIFY */
6003 cls
.lpfnWndProc
= EN_LINK_ParentMsgCheckProcA
;
6006 cls
.hInstance
= GetModuleHandleA(0);
6008 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
6009 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
6010 cls
.lpszMenuName
= NULL
;
6011 cls
.lpszClassName
= "EN_LINK_ParentClass";
6012 if(!RegisterClassA(&cls
)) assert(0);
6014 parent
= CreateWindowA(cls
.lpszClassName
, NULL
, WS_POPUP
|WS_VISIBLE
,
6015 0, 0, 200, 60, NULL
, NULL
, NULL
, NULL
);
6016 ok(parent
!= 0, "Failed to create parent window\n");
6018 hwndRichedit_EN_LINK
= new_richedit(parent
);
6019 ok(hwndRichedit_EN_LINK
!= 0, "Failed to create edit window\n");
6021 SendMessageA(hwndRichedit_EN_LINK
, EM_SETEVENTMASK
, 0, ENM_LINK
);
6023 cf2
.cbSize
= sizeof(CHARFORMAT2A
);
6024 cf2
.dwMask
= CFM_LINK
;
6025 cf2
.dwEffects
= CFE_LINK
;
6026 SendMessageA(hwndRichedit_EN_LINK
, EM_SETCHARFORMAT
, 0, (LPARAM
)&cf2
);
6027 /* mixing letters and numbers causes runs to be split */
6028 SendMessageA(hwndRichedit_EN_LINK
, WM_SETTEXT
, 0, (LPARAM
)"link text with at least 2 runs");
6029 SendMessageA(hwndRichedit_EN_LINK
, WM_LBUTTONDOWN
, 0, MAKELPARAM(5, 5));
6030 ok(cpMin_EN_LINK
== 0 && cpMax_EN_LINK
== 31, "Expected link range [0,31) got [%i,%i)\n", cpMin_EN_LINK
, cpMax_EN_LINK
);
6032 DestroyWindow(hwndRichedit_EN_LINK
);
6033 DestroyWindow(parent
);
6036 static void test_undo_coalescing(void)
6040 char buffer
[64] = {0};
6042 /* multi-line control inserts CR normally */
6043 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
|ES_MULTILINE
,
6044 0, 0, 200, 60, 0, 0, 0, 0);
6045 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
6047 result
= SendMessageA(hwnd
, EM_CANUNDO
, 0, 0);
6048 ok (result
== FALSE
, "Can undo after window creation.\n");
6049 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6050 ok (result
== FALSE
, "Undo operation successful with nothing to undo.\n");
6051 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
6052 ok (result
== FALSE
, "Can redo after window creation.\n");
6053 result
= SendMessageA(hwnd
, EM_REDO
, 0, 0);
6054 ok (result
== FALSE
, "Redo operation successful with nothing undone.\n");
6056 /* Test the effect of arrows keys during typing on undo transactions*/
6057 simulate_typing_characters(hwnd
, "one two three");
6058 SendMessageA(hwnd
, WM_KEYDOWN
, VK_RIGHT
, 1);
6059 SendMessageA(hwnd
, WM_KEYUP
, VK_RIGHT
, 1);
6060 simulate_typing_characters(hwnd
, " four five six");
6062 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
6063 ok (result
== FALSE
, "Can redo before anything is undone.\n");
6064 result
= SendMessageA(hwnd
, EM_CANUNDO
, 0, 0);
6065 ok (result
== TRUE
, "Cannot undo typed characters.\n");
6066 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6067 ok (result
== TRUE
, "EM_UNDO Failed to undo typed characters.\n");
6068 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
6069 ok (result
== TRUE
, "Cannot redo after undo.\n");
6070 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6071 result
= strcmp(buffer
, "one two three");
6072 ok (result
== 0, "expected '%s' but got '%s'\n", "one two three", buffer
);
6074 result
= SendMessageA(hwnd
, EM_CANUNDO
, 0, 0);
6075 ok (result
== TRUE
, "Cannot undo typed characters.\n");
6076 result
= SendMessageA(hwnd
, WM_UNDO
, 0, 0);
6077 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6078 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6079 result
= strcmp(buffer
, "");
6080 ok (result
== 0, "expected '%s' but got '%s'\n", "", buffer
);
6082 /* Test the effect of focus changes during typing on undo transactions*/
6083 simulate_typing_characters(hwnd
, "one two three");
6084 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
6085 ok (result
== FALSE
, "Redo buffer should have been cleared by typing.\n");
6086 SendMessageA(hwnd
, WM_KILLFOCUS
, 0, 0);
6087 SendMessageA(hwnd
, WM_SETFOCUS
, 0, 0);
6088 simulate_typing_characters(hwnd
, " four five six");
6089 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6090 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6091 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6092 result
= strcmp(buffer
, "one two three");
6093 ok (result
== 0, "expected '%s' but got '%s'\n", "one two three", buffer
);
6095 /* Test the effect of the back key during typing on undo transactions */
6096 SendMessageA(hwnd
, EM_EMPTYUNDOBUFFER
, 0, 0);
6097 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"");
6098 ok (result
== TRUE
, "Failed to clear the text.\n");
6099 simulate_typing_characters(hwnd
, "one two threa");
6100 result
= SendMessageA(hwnd
, EM_CANREDO
, 0, 0);
6101 ok (result
== FALSE
, "Redo buffer should have been cleared by typing.\n");
6102 SendMessageA(hwnd
, WM_KEYDOWN
, VK_BACK
, 1);
6103 SendMessageA(hwnd
, WM_KEYUP
, VK_BACK
, 1);
6104 simulate_typing_characters(hwnd
, "e four five six");
6105 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6106 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6107 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6108 result
= strcmp(buffer
, "");
6109 ok (result
== 0, "expected '%s' but got '%s'\n", "", buffer
);
6111 /* Test the effect of the delete key during typing on undo transactions */
6112 SendMessageA(hwnd
, EM_EMPTYUNDOBUFFER
, 0, 0);
6113 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"abcd");
6114 ok(result
== TRUE
, "Failed to set the text.\n");
6115 SendMessageA(hwnd
, EM_SETSEL
, 1, 1);
6116 SendMessageA(hwnd
, WM_KEYDOWN
, VK_DELETE
, 1);
6117 SendMessageA(hwnd
, WM_KEYUP
, VK_DELETE
, 1);
6118 SendMessageA(hwnd
, WM_KEYDOWN
, VK_DELETE
, 1);
6119 SendMessageA(hwnd
, WM_KEYUP
, VK_DELETE
, 1);
6120 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6121 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6122 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6123 result
= strcmp(buffer
, "acd");
6124 ok (result
== 0, "expected '%s' but got '%s'\n", "acd", buffer
);
6125 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6126 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6127 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6128 result
= strcmp(buffer
, "abcd");
6129 ok (result
== 0, "expected '%s' but got '%s'\n", "abcd", buffer
);
6131 /* Test the effect of EM_STOPGROUPTYPING on undo transactions*/
6132 SendMessageA(hwnd
, EM_EMPTYUNDOBUFFER
, 0, 0);
6133 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"");
6134 ok (result
== TRUE
, "Failed to clear the text.\n");
6135 simulate_typing_characters(hwnd
, "one two three");
6136 result
= SendMessageA(hwnd
, EM_STOPGROUPTYPING
, 0, 0);
6137 ok (result
== 0, "expected %d but got %d\n", 0, result
);
6138 simulate_typing_characters(hwnd
, " four five six");
6139 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6140 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6141 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6142 result
= strcmp(buffer
, "one two three");
6143 ok (result
== 0, "expected '%s' but got '%s'\n", "one two three", buffer
);
6144 result
= SendMessageA(hwnd
, EM_UNDO
, 0, 0);
6145 ok (result
== TRUE
, "Failed to undo typed characters.\n");
6146 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
6147 result
= strcmp(buffer
, "");
6148 ok (result
== 0, "expected '%s' but got '%s'\n", "", buffer
);
6150 DestroyWindow(hwnd
);
6153 static LONG CALLBACK
customWordBreakProc(WCHAR
*text
, int pos
, int bytes
, int code
)
6157 /* MSDN lied, length is actually the number of bytes. */
6158 length
= bytes
/ sizeof(WCHAR
);
6161 case WB_ISDELIMITER
:
6162 return text
[pos
] == 'X';
6164 case WB_MOVEWORDLEFT
:
6165 if (customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
6167 return min(customWordBreakProc(text
, pos
, bytes
, WB_LEFTBREAK
)-1, 0);
6170 while (pos
> 0 && !customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
6174 case WB_MOVEWORDRIGHT
:
6175 if (customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
6177 return min(customWordBreakProc(text
, pos
, bytes
, WB_RIGHTBREAK
)+1, length
);
6180 while (pos
< length
&& !customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
6184 ok(FALSE
, "Unexpected code %d\n", code
);
6190 static void test_word_movement(void)
6194 int sel_start
, sel_end
;
6195 const WCHAR textW
[] = {'o','n','e',' ','t','w','o','X','t','h','r','e','e',0};
6197 /* multi-line control inserts CR normally */
6198 hwnd
= new_richedit(NULL
);
6200 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"one two three");
6201 ok (result
== TRUE
, "Failed to clear the text.\n");
6202 SendMessageA(hwnd
, EM_SETSEL
, 0, 0);
6203 /* |one two three */
6205 send_ctrl_key(hwnd
, VK_RIGHT
);
6206 /* one |two three */
6207 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6208 ok(sel_start
== sel_end
, "Selection should be empty\n");
6209 ok(sel_start
== 4, "Cursor is at %d instead of %d\n", sel_start
, 4);
6211 send_ctrl_key(hwnd
, VK_RIGHT
);
6212 /* one two |three */
6213 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6214 ok(sel_start
== sel_end
, "Selection should be empty\n");
6215 ok(sel_start
== 9, "Cursor is at %d instead of %d\n", sel_start
, 9);
6217 send_ctrl_key(hwnd
, VK_LEFT
);
6218 /* one |two three */
6219 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6220 ok(sel_start
== sel_end
, "Selection should be empty\n");
6221 ok(sel_start
== 4, "Cursor is at %d instead of %d\n", sel_start
, 4);
6223 send_ctrl_key(hwnd
, VK_LEFT
);
6224 /* |one two three */
6225 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6226 ok(sel_start
== sel_end
, "Selection should be empty\n");
6227 ok(sel_start
== 0, "Cursor is at %d instead of %d\n", sel_start
, 0);
6229 SendMessageA(hwnd
, EM_SETSEL
, 8, 8);
6230 /* one two | three */
6231 send_ctrl_key(hwnd
, VK_RIGHT
);
6232 /* one two |three */
6233 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6234 ok(sel_start
== sel_end
, "Selection should be empty\n");
6235 ok(sel_start
== 9, "Cursor is at %d instead of %d\n", sel_start
, 9);
6237 SendMessageA(hwnd
, EM_SETSEL
, 11, 11);
6238 /* one two th|ree */
6239 send_ctrl_key(hwnd
, VK_LEFT
);
6240 /* one two |three */
6241 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6242 ok(sel_start
== sel_end
, "Selection should be empty\n");
6243 ok(sel_start
== 9, "Cursor is at %d instead of %d\n", sel_start
, 9);
6245 /* Test with a custom word break procedure that uses X as the delimiter. */
6246 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"one twoXthree");
6247 ok (result
== TRUE
, "Failed to clear the text.\n");
6248 SendMessageA(hwnd
, EM_SETWORDBREAKPROC
, 0, (LPARAM
)customWordBreakProc
);
6249 /* |one twoXthree */
6250 send_ctrl_key(hwnd
, VK_RIGHT
);
6251 /* one twoX|three */
6252 SendMessageA(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6253 ok(sel_start
== sel_end
, "Selection should be empty\n");
6254 ok(sel_start
== 8, "Cursor is at %d instead of %d\n", sel_start
, 8);
6256 DestroyWindow(hwnd
);
6258 /* Make sure the behaviour is the same with a unicode richedit window,
6259 * and using unicode functions. */
6261 hwnd
= CreateWindowW(RICHEDIT_CLASS20W
, NULL
,
6262 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
6263 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6265 /* Test with a custom word break procedure that uses X as the delimiter. */
6266 result
= SendMessageW(hwnd
, WM_SETTEXT
, 0, (LPARAM
)textW
);
6267 ok (result
== TRUE
, "Failed to clear the text.\n");
6268 SendMessageW(hwnd
, EM_SETWORDBREAKPROC
, 0, (LPARAM
)customWordBreakProc
);
6269 /* |one twoXthree */
6270 send_ctrl_key(hwnd
, VK_RIGHT
);
6271 /* one twoX|three */
6272 SendMessageW(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6273 ok(sel_start
== sel_end
, "Selection should be empty\n");
6274 ok(sel_start
== 8, "Cursor is at %d instead of %d\n", sel_start
, 8);
6276 DestroyWindow(hwnd
);
6279 static void test_EM_CHARFROMPOS(void)
6288 /* multi-line control inserts CR normally */
6289 hwnd
= new_richedit(NULL
);
6290 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0,
6291 (LPARAM
)"one two three four five six seven\reight");
6292 ok(result
== 1, "Expected 1, got %d\n", result
);
6293 GetClientRect(hwnd
, &rcClient
);
6295 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6296 ok(result
== 34, "expected character index of 34 but got %d\n", result
);
6298 /* Test with points outside the bounds of the richedit control. */
6301 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6302 todo_wine
ok(result
== 34, "expected character index of 34 but got %d\n", result
);
6306 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6307 todo_wine
ok(result
== 33, "expected character index of 33 but got %d\n", result
);
6311 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6312 todo_wine
ok(result
== 39, "expected character index of 39 but got %d\n", result
);
6316 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6317 todo_wine
ok(result
== 0, "expected character index of 0 but got %d\n", result
);
6320 point
.y
= rcClient
.bottom
+ 1;
6321 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6322 todo_wine
ok(result
== 34, "expected character index of 34 but got %d\n", result
);
6325 point
.y
= rcClient
.bottom
;
6326 result
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6327 todo_wine
ok(result
== 39, "expected character index of 39 but got %d\n", result
);
6329 DestroyWindow(hwnd
);
6332 static void test_word_wrap(void)
6335 POINTL point
= {0, 60}; /* This point must be below the first line */
6336 const char *text
= "Must be long enough to test line wrapping";
6337 DWORD dwCommonStyle
= WS_VISIBLE
|WS_POPUP
|WS_VSCROLL
|ES_MULTILINE
;
6338 int res
, pos
, lines
;
6340 /* Test the effect of WS_HSCROLL and ES_AUTOHSCROLL styles on wrapping
6341 * when specified on window creation and set later. */
6342 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, dwCommonStyle
,
6343 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6344 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6345 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
6346 ok(res
, "WM_SETTEXT failed.\n");
6347 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6348 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
6349 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6350 ok(lines
> 1, "Line was expected to wrap (lines=%d).\n", lines
);
6352 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
|WS_HSCROLL
|ES_AUTOHSCROLL
);
6353 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6354 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
6355 DestroyWindow(hwnd
);
6357 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, dwCommonStyle
|WS_HSCROLL
,
6358 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6359 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6361 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
6362 ok(res
, "WM_SETTEXT failed.\n");
6363 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6364 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6365 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6366 ok(lines
== 1, "Line wasn't expected to wrap (lines=%d).\n", lines
);
6368 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
);
6369 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6370 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6371 DestroyWindow(hwnd
);
6373 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, dwCommonStyle
|ES_AUTOHSCROLL
,
6374 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6375 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6376 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
6377 ok(res
, "WM_SETTEXT failed.\n");
6378 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6379 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6381 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
);
6382 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6383 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6384 DestroyWindow(hwnd
);
6386 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
,
6387 dwCommonStyle
|WS_HSCROLL
|ES_AUTOHSCROLL
,
6388 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6389 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6390 res
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)text
);
6391 ok(res
, "WM_SETTEXT failed.\n");
6392 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6393 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6395 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
);
6396 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6397 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6399 /* Test the effect of EM_SETTARGETDEVICE on word wrap. */
6400 res
= SendMessageA(hwnd
, EM_SETTARGETDEVICE
, 0, 1);
6401 ok(res
, "EM_SETTARGETDEVICE failed (returned %d).\n", res
);
6402 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6403 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6405 res
= SendMessageA(hwnd
, EM_SETTARGETDEVICE
, 0, 0);
6406 ok(res
, "EM_SETTARGETDEVICE failed (returned %d).\n", res
);
6407 pos
= SendMessageA(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6408 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
6409 DestroyWindow(hwnd
);
6411 /* Test to see if wrapping happens with redraw disabled. */
6412 hwnd
= CreateWindowA(RICHEDIT_CLASS20A
, NULL
, dwCommonStyle
,
6413 0, 0, 400, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6414 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6415 SendMessageA(hwnd
, WM_SETREDRAW
, FALSE
, 0);
6416 res
= SendMessageA(hwnd
, EM_REPLACESEL
, FALSE
, (LPARAM
)text
);
6417 ok(res
, "EM_REPLACESEL failed.\n");
6418 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6419 ok(lines
== 1, "Line wasn't expected to wrap (lines=%d).\n", lines
);
6420 MoveWindow(hwnd
, 0, 0, 200, 80, FALSE
);
6421 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6422 ok(lines
> 1, "Line was expected to wrap (lines=%d).\n", lines
);
6424 SendMessageA(hwnd
, WM_SETREDRAW
, TRUE
, 0);
6425 DestroyWindow(hwnd
);
6428 static void test_autoscroll(void)
6430 HWND hwnd
= new_richedit(NULL
);
6431 int lines
, ret
, redraw
;
6434 for (redraw
= 0; redraw
<= 1; redraw
++) {
6435 trace("testing with WM_SETREDRAW=%d\n", redraw
);
6436 SendMessageA(hwnd
, WM_SETREDRAW
, redraw
, 0);
6437 SendMessageA(hwnd
, EM_REPLACESEL
, 0, (LPARAM
)"1\n2\n3\n4\n5\n6\n7\n8");
6438 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6439 ok(lines
== 8, "%d lines instead of 8\n", lines
);
6440 ret
= SendMessageA(hwnd
, EM_GETSCROLLPOS
, 0, (LPARAM
)&pt
);
6441 ok(ret
== 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret
);
6442 ok(pt
.y
!= 0, "Didn't scroll down after replacing text.\n");
6443 ret
= GetWindowLongA(hwnd
, GWL_STYLE
);
6444 ok(ret
& WS_VSCROLL
, "Scrollbar was not shown yet (style=%x).\n", (UINT
)ret
);
6446 SendMessageA(hwnd
, WM_SETTEXT
, 0, 0);
6447 lines
= SendMessageA(hwnd
, EM_GETLINECOUNT
, 0, 0);
6448 ok(lines
== 1, "%d lines instead of 1\n", lines
);
6449 ret
= SendMessageA(hwnd
, EM_GETSCROLLPOS
, 0, (LPARAM
)&pt
);
6450 ok(ret
== 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret
);
6451 ok(pt
.y
== 0, "y scroll position is %d after clearing text.\n", pt
.y
);
6452 ret
= GetWindowLongA(hwnd
, GWL_STYLE
);
6453 ok(!(ret
& WS_VSCROLL
), "Scrollbar is still shown (style=%x).\n", (UINT
)ret
);
6456 SendMessageA(hwnd
, WM_SETREDRAW
, TRUE
, 0);
6457 DestroyWindow(hwnd
);
6459 /* The WS_VSCROLL and WS_HSCROLL styles implicitly set
6460 * auto vertical/horizontal scrolling options. */
6461 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6462 WS_POPUP
|ES_MULTILINE
|WS_VSCROLL
|WS_HSCROLL
,
6463 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6464 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6465 ret
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
6466 ok(ret
& ECO_AUTOVSCROLL
, "ECO_AUTOVSCROLL isn't set.\n");
6467 ok(ret
& ECO_AUTOHSCROLL
, "ECO_AUTOHSCROLL isn't set.\n");
6468 ret
= GetWindowLongA(hwnd
, GWL_STYLE
);
6469 ok(!(ret
& ES_AUTOVSCROLL
), "ES_AUTOVSCROLL is set.\n");
6470 ok(!(ret
& ES_AUTOHSCROLL
), "ES_AUTOHSCROLL is set.\n");
6471 DestroyWindow(hwnd
);
6473 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6474 WS_POPUP
|ES_MULTILINE
,
6475 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6476 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6477 ret
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
6478 ok(!(ret
& ECO_AUTOVSCROLL
), "ECO_AUTOVSCROLL is set.\n");
6479 ok(!(ret
& ECO_AUTOHSCROLL
), "ECO_AUTOHSCROLL is set.\n");
6480 ret
= GetWindowLongA(hwnd
, GWL_STYLE
);
6481 ok(!(ret
& ES_AUTOVSCROLL
), "ES_AUTOVSCROLL is set.\n");
6482 ok(!(ret
& ES_AUTOHSCROLL
), "ES_AUTOHSCROLL is set.\n");
6483 DestroyWindow(hwnd
);
6487 static void test_format_rect(void)
6490 RECT rc
, expected
, clientRect
;
6494 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6495 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
6496 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6497 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6499 GetClientRect(hwnd
, &clientRect
);
6501 expected
= clientRect
;
6503 expected
.right
-= 1;
6504 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6505 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6506 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6507 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6508 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6509 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6511 for (n
= -3; n
<= 3; n
++)
6518 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6521 expected
.top
= max(0, rc
.top
);
6522 expected
.left
= max(0, rc
.left
);
6523 expected
.bottom
= min(clientRect
.bottom
, rc
.bottom
);
6524 expected
.right
= min(clientRect
.right
, rc
.right
);
6525 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6526 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6527 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6528 "[n=%d] rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6529 n
, rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6530 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6534 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6535 expected
= clientRect
;
6536 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6537 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6538 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6539 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6540 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6541 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6543 /* Adding the selectionbar adds the selectionbar width to the left side. */
6544 SendMessageA(hwnd
, EM_SETOPTIONS
, ECOOP_OR
, ECO_SELECTIONBAR
);
6545 options
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
6546 ok(options
& ECO_SELECTIONBAR
, "EM_SETOPTIONS failed to add selectionbar.\n");
6547 expected
.left
+= 8; /* selection bar width */
6548 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6549 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6550 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6551 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6552 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6553 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6556 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6557 expected
= clientRect
;
6558 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6559 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6560 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6561 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6562 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6563 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6565 /* Removing the selectionbar subtracts the selectionbar width from the left side,
6566 * even if the left side is already 0. */
6567 SendMessageA(hwnd
, EM_SETOPTIONS
, ECOOP_AND
, ~ECO_SELECTIONBAR
);
6568 options
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
6569 ok(!(options
& ECO_SELECTIONBAR
), "EM_SETOPTIONS failed to remove selectionbar.\n");
6570 expected
.left
-= 8; /* selection bar width */
6571 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6572 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6573 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6574 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6575 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6576 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6578 /* Set the absolute value of the formatting rectangle. */
6580 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6581 expected
= clientRect
;
6582 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6583 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6584 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6585 "[n=%d] rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6586 n
, rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6587 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6589 /* MSDN documents the EM_SETRECT message as using the rectangle provided in
6590 * LPARAM as being a relative offset when the WPARAM value is 1, but these
6591 * tests show that this isn't true. */
6594 rc
.bottom
= clientRect
.bottom
- 15;
6595 rc
.right
= clientRect
.right
- 15;
6597 SendMessageA(hwnd
, EM_SETRECT
, 1, (LPARAM
)&rc
);
6598 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6599 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6600 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6601 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6602 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6603 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6605 /* For some reason it does not limit the values to the client rect with
6606 * a WPARAM value of 1. */
6609 rc
.bottom
= clientRect
.bottom
+ 15;
6610 rc
.right
= clientRect
.right
+ 15;
6612 SendMessageA(hwnd
, EM_SETRECT
, 1, (LPARAM
)&rc
);
6613 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6614 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6615 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6616 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6617 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6618 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6620 /* Reset to default rect and check how the format rect adjusts to window
6621 * resize and how it copes with very small windows */
6622 SendMessageA(hwnd
, EM_SETRECT
, 0, 0);
6624 MoveWindow(hwnd
, 0, 0, 100, 30, FALSE
);
6625 GetClientRect(hwnd
, &clientRect
);
6627 expected
= clientRect
;
6629 expected
.right
-= 1;
6630 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6631 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6632 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6633 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6634 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6635 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6637 MoveWindow(hwnd
, 0, 0, 0, 30, FALSE
);
6638 GetClientRect(hwnd
, &clientRect
);
6640 expected
= clientRect
;
6642 expected
.right
-= 1;
6643 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6644 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6645 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6646 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6647 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6648 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6650 MoveWindow(hwnd
, 0, 0, 100, 0, FALSE
);
6651 GetClientRect(hwnd
, &clientRect
);
6653 expected
= clientRect
;
6655 expected
.right
-= 1;
6656 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6657 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6658 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6659 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6660 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6661 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6663 DestroyWindow(hwnd
);
6665 /* The extended window style affects the formatting rectangle. */
6666 hwnd
= CreateWindowExA(WS_EX_CLIENTEDGE
, RICHEDIT_CLASS20A
, NULL
,
6667 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
6668 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6669 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6671 GetClientRect(hwnd
, &clientRect
);
6673 expected
= clientRect
;
6676 expected
.right
-= 1;
6677 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6678 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6679 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6680 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6681 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6682 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6692 expected
.right
+= 1;
6693 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6694 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6695 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6696 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6697 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6698 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6699 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6701 DestroyWindow(hwnd
);
6704 static void test_WM_GETDLGCODE(void)
6710 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6712 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6713 ES_MULTILINE
|ES_WANTRETURN
|WS_POPUP
,
6714 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6715 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6717 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, 0);
6718 expected
= expected
| DLGC_WANTMESSAGE
;
6719 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6721 DestroyWindow(hwnd
);
6723 msg
.message
= WM_KEYDOWN
;
6724 msg
.wParam
= VK_RETURN
;
6725 msg
.lParam
= (MapVirtualKeyA(VK_RETURN
, MAPVK_VK_TO_VSC
) << 16) | 0x0001;
6728 msg
.time
= GetTickCount();
6730 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6731 ES_MULTILINE
|ES_WANTRETURN
|WS_POPUP
,
6732 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6733 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6735 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6736 expected
= expected
| DLGC_WANTMESSAGE
;
6737 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6739 DestroyWindow(hwnd
);
6741 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6742 ES_MULTILINE
|WS_POPUP
,
6743 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6744 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6746 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6747 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6748 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6750 DestroyWindow(hwnd
);
6752 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6753 ES_WANTRETURN
|WS_POPUP
,
6754 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6755 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6757 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6758 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6759 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6761 DestroyWindow(hwnd
);
6763 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6765 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6766 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6768 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6769 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6770 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6772 DestroyWindow(hwnd
);
6774 msg
.wParam
= VK_TAB
;
6775 msg
.lParam
= (MapVirtualKeyA(VK_TAB
, MAPVK_VK_TO_VSC
) << 16) | 0x0001;
6777 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6778 ES_MULTILINE
|WS_POPUP
,
6779 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6780 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6782 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6783 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6784 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6786 DestroyWindow(hwnd
);
6788 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6790 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6791 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6793 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6794 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6795 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6797 DestroyWindow(hwnd
);
6799 hold_key(VK_CONTROL
);
6801 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6802 ES_MULTILINE
|WS_POPUP
,
6803 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6804 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6806 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6807 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6808 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6810 DestroyWindow(hwnd
);
6812 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6814 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6815 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6817 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6818 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6819 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6821 DestroyWindow(hwnd
);
6823 release_key(VK_CONTROL
);
6826 msg
.lParam
= (MapVirtualKeyA('a', MAPVK_VK_TO_VSC
) << 16) | 0x0001;
6828 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6829 ES_MULTILINE
|WS_POPUP
,
6830 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6831 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6833 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6834 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6835 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6837 DestroyWindow(hwnd
);
6839 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6841 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6842 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6844 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6845 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6846 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6848 DestroyWindow(hwnd
);
6850 msg
.message
= WM_CHAR
;
6852 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6853 ES_MULTILINE
|WS_POPUP
,
6854 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6855 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6857 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6858 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6859 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6861 DestroyWindow(hwnd
);
6863 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6865 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6866 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6868 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6869 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6870 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6872 DestroyWindow(hwnd
);
6874 hwnd
= CreateWindowExA(0, RICHEDIT_CLASS20A
, NULL
,
6875 WS_POPUP
|ES_SAVESEL
,
6876 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6877 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
6878 res
= SendMessageA(hwnd
, WM_GETDLGCODE
, 0, 0);
6879 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
;
6880 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6882 DestroyWindow(hwnd
);
6885 static void test_zoom(void)
6891 int numerator
, denominator
;
6893 hwnd
= new_richedit(NULL
);
6894 GetClientRect(hwnd
, &rc
);
6895 pt
.x
= (rc
.right
- rc
.left
) / 2;
6896 pt
.y
= (rc
.bottom
- rc
.top
) / 2;
6897 ClientToScreen(hwnd
, &pt
);
6899 /* Test initial zoom value */
6900 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6901 ok(numerator
== 0, "Numerator should be initialized to 0 (got %d).\n", numerator
);
6902 ok(denominator
== 0, "Denominator should be initialized to 0 (got %d).\n", denominator
);
6903 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6905 /* test scroll wheel */
6906 hold_key(VK_CONTROL
);
6907 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
6908 MAKELPARAM(pt
.x
, pt
.y
));
6909 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6910 release_key(VK_CONTROL
);
6912 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6913 ok(numerator
== 110, "incorrect numerator is %d\n", numerator
);
6914 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6915 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6917 /* Test how much the mouse wheel can zoom in and out. */
6918 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 490, 100);
6919 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6921 hold_key(VK_CONTROL
);
6922 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
6923 MAKELPARAM(pt
.x
, pt
.y
));
6924 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6925 release_key(VK_CONTROL
);
6927 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6928 ok(numerator
== 500, "incorrect numerator is %d\n", numerator
);
6929 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6930 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6932 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 491, 100);
6933 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6935 hold_key(VK_CONTROL
);
6936 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
6937 MAKELPARAM(pt
.x
, pt
.y
));
6938 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6939 release_key(VK_CONTROL
);
6941 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6942 ok(numerator
== 491, "incorrect numerator is %d\n", numerator
);
6943 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6944 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6946 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 20, 100);
6947 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6949 hold_key(VK_CONTROL
);
6950 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, -WHEEL_DELTA
),
6951 MAKELPARAM(pt
.x
, pt
.y
));
6952 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6953 release_key(VK_CONTROL
);
6955 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6956 ok(numerator
== 10, "incorrect numerator is %d\n", numerator
);
6957 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6958 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6960 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 19, 100);
6961 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6963 hold_key(VK_CONTROL
);
6964 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, -WHEEL_DELTA
),
6965 MAKELPARAM(pt
.x
, pt
.y
));
6966 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6967 release_key(VK_CONTROL
);
6969 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6970 ok(numerator
== 19, "incorrect numerator is %d\n", numerator
);
6971 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6972 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6974 /* Test how WM_SCROLLWHEEL treats our custom denominator. */
6975 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 50, 13);
6976 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6978 hold_key(VK_CONTROL
);
6979 ret
= SendMessageA(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
6980 MAKELPARAM(pt
.x
, pt
.y
));
6981 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6982 release_key(VK_CONTROL
);
6984 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6985 ok(numerator
== 394, "incorrect numerator is %d\n", numerator
);
6986 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6987 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6989 /* Test bounds checking on EM_SETZOOM */
6990 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 2, 127);
6991 ok(ret
== TRUE
, "EM_SETZOOM rejected valid values (%d).\n", ret
);
6993 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 127, 2);
6994 ok(ret
== TRUE
, "EM_SETZOOM rejected valid values (%d).\n", ret
);
6996 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 2, 128);
6997 ok(ret
== FALSE
, "EM_SETZOOM accepted invalid values (%d).\n", ret
);
6999 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
7000 ok(numerator
== 127, "incorrect numerator is %d\n", numerator
);
7001 ok(denominator
== 2, "incorrect denominator is %d\n", denominator
);
7002 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
7004 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 128, 2);
7005 ok(ret
== FALSE
, "EM_SETZOOM accepted invalid values (%d).\n", ret
);
7007 /* See if negative numbers are accepted. */
7008 ret
= SendMessageA(hwnd
, EM_SETZOOM
, -100, -100);
7009 ok(ret
== FALSE
, "EM_SETZOOM accepted invalid values (%d).\n", ret
);
7011 /* See if negative numbers are accepted. */
7012 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 0, 100);
7013 ok(ret
== FALSE
, "EM_SETZOOM failed (%d).\n", ret
);
7015 ret
= SendMessageA(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
7016 ok(numerator
== 127, "incorrect numerator is %d\n", numerator
);
7017 ok(denominator
== 2, "incorrect denominator is %d\n", denominator
);
7018 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
7020 /* Reset the zoom value */
7021 ret
= SendMessageA(hwnd
, EM_SETZOOM
, 0, 0);
7022 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
7024 DestroyWindow(hwnd
);
7027 struct dialog_mode_messages
7029 int wm_getdefid
, wm_close
, wm_nextdlgctl
;
7032 static struct dialog_mode_messages dm_messages
;
7034 #define test_dm_messages(wmclose, wmgetdefid, wmnextdlgctl) \
7035 ok(dm_messages.wm_close == wmclose, "expected %d WM_CLOSE message, " \
7036 "got %d\n", wmclose, dm_messages.wm_close); \
7037 ok(dm_messages.wm_getdefid == wmgetdefid, "expected %d WM_GETDIFID message, " \
7038 "got %d\n", wmgetdefid, dm_messages.wm_getdefid);\
7039 ok(dm_messages.wm_nextdlgctl == wmnextdlgctl, "expected %d WM_NEXTDLGCTL message, " \
7040 "got %d\n", wmnextdlgctl, dm_messages.wm_nextdlgctl)
7042 static LRESULT CALLBACK
dialog_mode_wnd_proc(HWND hwnd
, UINT iMsg
, WPARAM wParam
, LPARAM lParam
)
7047 dm_messages
.wm_getdefid
++;
7048 return MAKELONG(ID_RICHEDITTESTDBUTTON
, DC_HASDEFID
);
7050 dm_messages
.wm_nextdlgctl
++;
7053 dm_messages
.wm_close
++;
7057 return DefWindowProcA(hwnd
, iMsg
, wParam
, lParam
);
7060 static void test_dialogmode(void)
7062 HWND hwRichEdit
, hwParent
, hwButton
;
7068 cls
.lpfnWndProc
= dialog_mode_wnd_proc
;
7071 cls
.hInstance
= GetModuleHandleA(0);
7073 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
7074 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
7075 cls
.lpszMenuName
= NULL
;
7076 cls
.lpszClassName
= "DialogModeParentClass";
7077 if(!RegisterClassA(&cls
)) assert(0);
7079 hwParent
= CreateWindowA("DialogModeParentClass", NULL
, WS_OVERLAPPEDWINDOW
,
7080 CW_USEDEFAULT
, 0, 200, 120, NULL
, NULL
, GetModuleHandleA(0), NULL
);
7082 /* Test richedit(ES_MULTILINE) */
7084 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, hwParent
);
7086 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7087 ok(0 == r
, "expected 0, got %d\n", r
);
7088 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7089 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7091 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, 0);
7092 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
7094 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7095 ok(0 == r
, "expected 0, got %d\n", r
);
7096 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7097 ok(3 == lcount
, "expected 3, got %d\n", lcount
);
7099 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7100 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
7101 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7102 ok(0 == r
, "expected 0, got %d\n", r
);
7103 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7104 ok(3 == lcount
, "expected 3, got %d\n", lcount
);
7106 DestroyWindow(hwRichEdit
);
7108 /* Test standalone richedit(ES_MULTILINE) */
7110 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, NULL
);
7112 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7113 ok(0 == r
, "expected 0, got %d\n", r
);
7114 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7115 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7117 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7118 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
7120 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7121 ok(0 == r
, "expected 0, got %d\n", r
);
7122 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7123 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7125 DestroyWindow(hwRichEdit
);
7127 /* Check a destination for messages */
7129 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, hwParent
);
7131 SetWindowLongA(hwRichEdit
, GWL_STYLE
, GetWindowLongA(hwRichEdit
, GWL_STYLE
)& ~WS_POPUP
);
7132 SetParent( hwRichEdit
, NULL
);
7134 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7135 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
7137 memset(&dm_messages
, 0, sizeof(dm_messages
));
7138 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7139 ok(0 == r
, "expected 0, got %d\n", r
);
7140 test_dm_messages(0, 1, 0);
7142 memset(&dm_messages
, 0, sizeof(dm_messages
));
7143 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7144 ok(0 == r
, "expected 0, got %d\n", r
);
7145 test_dm_messages(0, 0, 1);
7147 DestroyWindow(hwRichEdit
);
7149 /* Check messages from richedit(ES_MULTILINE) */
7151 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
, hwParent
);
7153 memset(&dm_messages
, 0, sizeof(dm_messages
));
7154 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7155 ok(0 == r
, "expected 0, got %d\n", r
);
7156 test_dm_messages(0, 0, 0);
7158 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7159 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7161 memset(&dm_messages
, 0, sizeof(dm_messages
));
7162 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7163 ok(0 == r
, "expected 0, got %d\n", r
);
7164 test_dm_messages(0, 0, 0);
7166 memset(&dm_messages
, 0, sizeof(dm_messages
));
7167 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7168 ok(0 == r
, "expected 0, got %d\n", r
);
7169 test_dm_messages(0, 0, 0);
7171 memset(&dm_messages
, 0, sizeof(dm_messages
));
7172 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7173 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
7174 test_dm_messages(0, 0, 0);
7176 memset(&dm_messages
, 0, sizeof(dm_messages
));
7177 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7178 ok(0 == r
, "expected 0, got %d\n", r
);
7179 test_dm_messages(0, 1, 0);
7181 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7182 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7184 memset(&dm_messages
, 0, sizeof(dm_messages
));
7185 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7186 ok(0 == r
, "expected 0, got %d\n", r
);
7187 test_dm_messages(0, 0, 0);
7189 memset(&dm_messages
, 0, sizeof(dm_messages
));
7190 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7191 ok(0 == r
, "expected 0, got %d\n", r
);
7192 test_dm_messages(0, 0, 1);
7194 hwButton
= CreateWindowA("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
7195 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
7196 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
7198 memset(&dm_messages
, 0, sizeof(dm_messages
));
7199 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7200 ok(0 == r
, "expected 0, got %d\n", r
);
7201 test_dm_messages(0, 1, 1);
7203 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7204 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7206 DestroyWindow(hwButton
);
7207 DestroyWindow(hwRichEdit
);
7209 /* Check messages from richedit(ES_MULTILINE|ES_WANTRETURN) */
7211 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_MULTILINE
|ES_WANTRETURN
, hwParent
);
7213 memset(&dm_messages
, 0, sizeof(dm_messages
));
7214 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7215 ok(0 == r
, "expected 0, got %d\n", r
);
7216 test_dm_messages(0, 0, 0);
7218 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7219 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
7221 memset(&dm_messages
, 0, sizeof(dm_messages
));
7222 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7223 ok(0 == r
, "expected 0, got %d\n", r
);
7224 test_dm_messages(0, 0, 0);
7226 memset(&dm_messages
, 0, sizeof(dm_messages
));
7227 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7228 ok(0 == r
, "expected 0, got %d\n", r
);
7229 test_dm_messages(0, 0, 0);
7231 memset(&dm_messages
, 0, sizeof(dm_messages
));
7232 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7233 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
7234 test_dm_messages(0, 0, 0);
7236 memset(&dm_messages
, 0, sizeof(dm_messages
));
7237 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7238 ok(0 == r
, "expected 0, got %d\n", r
);
7239 test_dm_messages(0, 0, 0);
7241 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7242 ok(3 == lcount
, "expected 3, got %d\n", lcount
);
7244 memset(&dm_messages
, 0, sizeof(dm_messages
));
7245 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7246 ok(0 == r
, "expected 0, got %d\n", r
);
7247 test_dm_messages(0, 0, 0);
7249 memset(&dm_messages
, 0, sizeof(dm_messages
));
7250 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7251 ok(0 == r
, "expected 0, got %d\n", r
);
7252 test_dm_messages(0, 0, 1);
7254 hwButton
= CreateWindowA("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
7255 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
7256 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
7258 memset(&dm_messages
, 0, sizeof(dm_messages
));
7259 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7260 ok(0 == r
, "expected 0, got %d\n", r
);
7261 test_dm_messages(0, 0, 0);
7263 lcount
= SendMessageA(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
7264 ok(4 == lcount
, "expected 4, got %d\n", lcount
);
7266 DestroyWindow(hwButton
);
7267 DestroyWindow(hwRichEdit
);
7269 /* Check messages from richedit(0) */
7271 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, 0, hwParent
);
7273 memset(&dm_messages
, 0, sizeof(dm_messages
));
7274 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7275 ok(0 == r
, "expected 0, got %d\n", r
);
7276 test_dm_messages(0, 0, 0);
7278 memset(&dm_messages
, 0, sizeof(dm_messages
));
7279 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7280 ok(0 == r
, "expected 0, got %d\n", r
);
7281 test_dm_messages(0, 0, 0);
7283 memset(&dm_messages
, 0, sizeof(dm_messages
));
7284 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7285 ok(0 == r
, "expected 0, got %d\n", r
);
7286 test_dm_messages(0, 0, 0);
7288 memset(&dm_messages
, 0, sizeof(dm_messages
));
7289 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7290 ok(0x8b == r
, "expected 0x8b, got 0x%x\n", r
);
7291 test_dm_messages(0, 0, 0);
7293 memset(&dm_messages
, 0, sizeof(dm_messages
));
7294 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7295 ok(0 == r
, "expected 0, got %d\n", r
);
7296 test_dm_messages(0, 1, 0);
7298 memset(&dm_messages
, 0, sizeof(dm_messages
));
7299 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7300 ok(0 == r
, "expected 0, got %d\n", r
);
7301 test_dm_messages(0, 0, 0);
7303 memset(&dm_messages
, 0, sizeof(dm_messages
));
7304 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7305 ok(0 == r
, "expected 0, got %d\n", r
);
7306 test_dm_messages(0, 0, 1);
7308 hwButton
= CreateWindowA("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
7309 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
7310 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
7312 memset(&dm_messages
, 0, sizeof(dm_messages
));
7313 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7314 ok(0 == r
, "expected 0, got %d\n", r
);
7315 test_dm_messages(0, 1, 1);
7317 DestroyWindow(hwRichEdit
);
7319 /* Check messages from richedit(ES_WANTRETURN) */
7321 hwRichEdit
= new_window(RICHEDIT_CLASS20A
, ES_WANTRETURN
, hwParent
);
7323 memset(&dm_messages
, 0, sizeof(dm_messages
));
7324 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7325 ok(0 == r
, "expected 0, got %d\n", r
);
7326 test_dm_messages(0, 0, 0);
7328 memset(&dm_messages
, 0, sizeof(dm_messages
));
7329 r
= SendMessageA(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7330 ok(0x8b == r
, "expected 0x8b, got 0x%x\n", r
);
7331 test_dm_messages(0, 0, 0);
7333 memset(&dm_messages
, 0, sizeof(dm_messages
));
7334 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7335 ok(0 == r
, "expected 0, got %d\n", r
);
7336 test_dm_messages(0, 0, 0);
7338 hwButton
= CreateWindowA("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
7339 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
7340 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
7342 memset(&dm_messages
, 0, sizeof(dm_messages
));
7343 r
= SendMessageA(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7344 ok(0 == r
, "expected 0, got %d\n", r
);
7345 test_dm_messages(0, 0, 0);
7347 DestroyWindow(hwRichEdit
);
7348 DestroyWindow(hwParent
);
7351 static void test_EM_FINDWORDBREAK_W(void)
7353 static const struct {
7355 BOOL isdelimiter
; /* expected result of WB_ISDELIMITER */
7356 } delimiter_tests
[] = {
7357 {0x0a, FALSE
}, /* newline */
7358 {0x0b, FALSE
}, /* vertical tab */
7359 {0x0c, FALSE
}, /* form feed */
7360 {0x0d, FALSE
}, /* carriage return */
7361 {0x20, TRUE
}, /* space */
7362 {0x61, FALSE
}, /* capital letter a */
7363 {0xa0, FALSE
}, /* no-break space */
7364 {0x2000, FALSE
}, /* en quad */
7365 {0x3000, FALSE
}, /* Ideographic space */
7366 {0x1100, FALSE
}, /* Hangul Choseong Kiyeok (G sound) Ordinary Letter*/
7367 {0x11ff, FALSE
}, /* Hangul Jongseoung Kiyeok-Hieuh (Hard N sound) Ordinary Letter*/
7368 {0x115f, FALSE
}, /* Hangul Choseong Filler (no sound, used with two letter Hangul words) Ordinary Letter */
7369 {0xac00, FALSE
}, /* Hangul character GA*/
7370 {0xd7af, FALSE
}, /* End of Hangul character chart */
7371 {0xf020, TRUE
}, /* MS private for CP_SYMBOL round trip?, see kb897872 */
7372 {0xff20, FALSE
}, /* fullwidth commercial @ */
7373 {WCH_EMBEDDING
, FALSE
}, /* object replacement character*/
7376 HWND hwndRichEdit
= new_richeditW(NULL
);
7377 ok(IsWindowUnicode(hwndRichEdit
), "window should be unicode\n");
7378 for (i
= 0; i
< sizeof(delimiter_tests
)/sizeof(delimiter_tests
[0]); i
++)
7383 wbuf
[0] = delimiter_tests
[i
].c
;
7385 SendMessageW(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)wbuf
);
7386 result
= SendMessageW(hwndRichEdit
, EM_FINDWORDBREAK
, WB_ISDELIMITER
,0);
7387 if (wbuf
[0] == 0x20 || wbuf
[0] == 0xf020)
7389 ok(result
== delimiter_tests
[i
].isdelimiter
,
7390 "wanted ISDELIMITER_W(0x%x) %d, got %d\n",
7391 delimiter_tests
[i
].c
, delimiter_tests
[i
].isdelimiter
,result
);
7393 ok(result
== delimiter_tests
[i
].isdelimiter
,
7394 "wanted ISDELIMITER_W(0x%x) %d, got %d\n",
7395 delimiter_tests
[i
].c
, delimiter_tests
[i
].isdelimiter
, result
);
7397 DestroyWindow(hwndRichEdit
);
7400 static void test_EM_FINDWORDBREAK_A(void)
7402 static const struct {
7404 BOOL isdelimiter
; /* expected result of WB_ISDELIMITER */
7405 } delimiter_tests
[] = {
7406 {0x0a, FALSE
}, /* newline */
7407 {0x0b, FALSE
}, /* vertical tab */
7408 {0x0c, FALSE
}, /* form feed */
7409 {0x0d, FALSE
}, /* carriage return */
7410 {0x20, TRUE
}, /* space */
7411 {0x61, FALSE
}, /* capital letter a */
7414 HWND hwndRichEdit
= new_richedit(NULL
);
7416 ok(!IsWindowUnicode(hwndRichEdit
), "window should not be unicode\n");
7417 for (i
= 0; i
< sizeof(delimiter_tests
)/sizeof(delimiter_tests
[0]); i
++)
7421 buf
[0] = delimiter_tests
[i
].c
;
7423 SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buf
);
7424 result
= SendMessageA(hwndRichEdit
, EM_FINDWORDBREAK
, WB_ISDELIMITER
, 0);
7427 ok(result
== delimiter_tests
[i
].isdelimiter
,
7428 "wanted ISDELIMITER_A(0x%x) %d, got %d\n",
7429 delimiter_tests
[i
].c
, delimiter_tests
[i
].isdelimiter
,result
);
7431 ok(result
== delimiter_tests
[i
].isdelimiter
,
7432 "wanted ISDELIMITER_A(0x%x) %d, got %d\n",
7433 delimiter_tests
[i
].c
, delimiter_tests
[i
].isdelimiter
, result
);
7435 DestroyWindow(hwndRichEdit
);
7439 * This test attempts to show the effect of enter on a richedit
7440 * control v1.0 inserts CRLF whereas for higher versions it only
7441 * inserts CR. If shows that EM_GETTEXTEX with GT_USECRLF == WM_GETTEXT
7442 * and also shows that GT_USECRLF has no effect in richedit 1.0, but
7443 * does for higher. The same test is cloned in riched32 and riched20.
7445 static void test_enter(void)
7447 static const struct {
7448 const char *initialtext
;
7450 const char *expectedwmtext
;
7451 const char *expectedemtext
;
7452 const char *expectedemtextcrlf
;
7453 } testenteritems
[] = {
7454 { "aaabbb\r\n", 3, "aaa\r\nbbb\r\n", "aaa\rbbb\r", "aaa\r\nbbb\r\n"},
7455 { "aaabbb\r\n", 6, "aaabbb\r\n\r\n", "aaabbb\r\r", "aaabbb\r\n\r\n"},
7456 { "aa\rabbb\r\n", 7, "aa\r\nabbb\r\n\r\n", "aa\rabbb\r\r", "aa\r\nabbb\r\n\r\n"},
7457 { "aa\rabbb\r\n", 3, "aa\r\n\r\nabbb\r\n", "aa\r\rabbb\r", "aa\r\n\r\nabbb\r\n"},
7458 { "aa\rabbb\r\n", 2, "aa\r\n\r\nabbb\r\n", "aa\r\rabbb\r", "aa\r\n\r\nabbb\r\n"}
7461 char expectedbuf
[1024];
7462 char resultbuf
[1024];
7463 HWND hwndRichEdit
= new_richedit(NULL
);
7466 for (i
= 0; i
< sizeof(testenteritems
)/sizeof(testenteritems
[0]); i
++) {
7468 char buf
[1024] = {0};
7471 const char *expected
;
7473 /* Set the text to the initial text */
7474 result
= SendMessageA(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)testenteritems
[i
].initialtext
);
7475 ok (result
== 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i
, result
);
7478 SendMessageA(hwndRichEdit
, EM_SETSEL
, testenteritems
[i
].cursor
, testenteritems
[i
].cursor
);
7479 simulate_typing_characters(hwndRichEdit
, "\r");
7481 /* 1. Retrieve with WM_GETTEXT */
7483 result
= SendMessageA(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
)buf
);
7484 expected
= testenteritems
[i
].expectedwmtext
;
7487 for (j
= 0; j
< (UINT
)result
; j
++)
7488 sprintf(resultbuf
+strlen(resultbuf
), "%02x", buf
[j
] & 0xFF);
7489 expectedbuf
[0] = '\0';
7490 for (j
= 0; j
< strlen(expected
); j
++)
7491 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", expected
[j
] & 0xFF);
7493 result
= strcmp(expected
, buf
);
7495 "[%d] WM_GETTEXT unexpected '%s' expected '%s'\n",
7496 i
, resultbuf
, expectedbuf
);
7498 /* 2. Retrieve with EM_GETTEXTEX, GT_DEFAULT */
7499 getText
.cb
= sizeof(buf
);
7500 getText
.flags
= GT_DEFAULT
;
7501 getText
.codepage
= CP_ACP
;
7502 getText
.lpDefaultChar
= NULL
;
7503 getText
.lpUsedDefChar
= NULL
;
7505 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
7506 expected
= testenteritems
[i
].expectedemtext
;
7509 for (j
= 0; j
< (UINT
)result
; j
++)
7510 sprintf(resultbuf
+strlen(resultbuf
), "%02x", buf
[j
] & 0xFF);
7511 expectedbuf
[0] = '\0';
7512 for (j
= 0; j
< strlen(expected
); j
++)
7513 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", expected
[j
] & 0xFF);
7515 result
= strcmp(expected
, buf
);
7517 "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n",
7518 i
, resultbuf
, expectedbuf
);
7520 /* 3. Retrieve with EM_GETTEXTEX, GT_USECRLF */
7521 getText
.cb
= sizeof(buf
);
7522 getText
.flags
= GT_USECRLF
;
7523 getText
.codepage
= CP_ACP
;
7524 getText
.lpDefaultChar
= NULL
;
7525 getText
.lpUsedDefChar
= NULL
;
7527 result
= SendMessageA(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
)buf
);
7528 expected
= testenteritems
[i
].expectedemtextcrlf
;
7531 for (j
= 0; j
< (UINT
)result
; j
++)
7532 sprintf(resultbuf
+strlen(resultbuf
), "%02x", buf
[j
] & 0xFF);
7533 expectedbuf
[0] = '\0';
7534 for (j
= 0; j
< strlen(expected
); j
++)
7535 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", expected
[j
] & 0xFF);
7537 result
= strcmp(expected
, buf
);
7539 "[%d] EM_GETTEXTEX, GT_USECRLF unexpected '%s', expected '%s'\n",
7540 i
, resultbuf
, expectedbuf
);
7543 DestroyWindow(hwndRichEdit
);
7546 static void test_WM_CREATE(void)
7548 static const WCHAR titleW
[] = {'l','i','n','e','1','\n','l','i','n','e','2',0};
7549 static const char title
[] = "line1\nline2";
7556 rich_edit
= CreateWindowA(RICHEDIT_CLASS20A
, title
, WS_POPUP
|WS_VISIBLE
,
7557 0, 0, 200, 80, NULL
, NULL
, NULL
, NULL
);
7558 ok(rich_edit
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS20A
, (int) GetLastError());
7560 len
= GetWindowTextA(rich_edit
, buf
, sizeof(buf
));
7561 ok(len
== 5, "GetWindowText returned %d\n", len
);
7562 ok(!strcmp(buf
, "line1"), "buf = %s\n", buf
);
7564 res
= SendMessageA(rich_edit
, EM_GETSEL
, 0, 0);
7565 ok(res
== 0, "SendMessage(EM_GETSEL) returned %lx\n", res
);
7567 DestroyWindow(rich_edit
);
7569 rich_edit
= CreateWindowW(RICHEDIT_CLASS20W
, titleW
, WS_POPUP
|WS_VISIBLE
|ES_MULTILINE
,
7570 0, 0, 200, 80, NULL
, NULL
, NULL
, NULL
);
7571 ok(rich_edit
!= NULL
, "class: %s, error: %d\n", wine_dbgstr_w(RICHEDIT_CLASS20W
), (int) GetLastError());
7573 len
= GetWindowTextA(rich_edit
, buf
, sizeof(buf
));
7574 ok(len
== 12, "GetWindowText returned %d\n", len
);
7575 ok(!strcmp(buf
, "line1\r\nline2"), "buf = %s\n", buf
);
7577 res
= SendMessageA(rich_edit
, EM_GETSEL
, 0, 0);
7578 ok(res
== 0, "SendMessage(EM_GETSEL) returned %lx\n", res
);
7580 DestroyWindow(rich_edit
);
7583 /*******************************************************************
7584 * Test that after deleting all of the text, the first paragraph
7585 * format reverts to the default.
7587 static void test_reset_default_para_fmt( void )
7589 HWND richedit
= new_richeditW( NULL
);
7591 WORD def_align
, new_align
;
7593 memset( &fmt
, 0, sizeof(fmt
) );
7594 fmt
.cbSize
= sizeof(PARAFORMAT2
);
7596 SendMessageA( richedit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
7597 def_align
= fmt
.wAlignment
;
7598 new_align
= (def_align
== PFA_LEFT
) ? PFA_RIGHT
: PFA_LEFT
;
7600 simulate_typing_characters( richedit
, "123" );
7602 SendMessageA( richedit
, EM_SETSEL
, 0, -1 );
7603 fmt
.dwMask
= PFM_ALIGNMENT
;
7604 fmt
.wAlignment
= new_align
;
7605 SendMessageA( richedit
, EM_SETPARAFORMAT
, 0, (LPARAM
)&fmt
);
7607 SendMessageA( richedit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
7608 ok( fmt
.wAlignment
== new_align
, "got %d expect %d\n", fmt
.wAlignment
, new_align
);
7610 SendMessageA( richedit
, EM_SETSEL
, 0, -1 );
7611 SendMessageA( richedit
, WM_CUT
, 0, 0 );
7613 SendMessageA( richedit
, EM_GETPARAFORMAT
, 0, (LPARAM
)&fmt
);
7614 ok( fmt
.wAlignment
== def_align
, "got %d exppect %d\n", fmt
.wAlignment
, def_align
);
7616 DestroyWindow( richedit
);
7619 static void test_EM_SETREADONLY(void)
7621 HWND richedit
= new_richeditW(NULL
);
7625 res
= SendMessageA(richedit
, EM_SETREADONLY
, TRUE
, 0);
7626 ok(res
== 1, "EM_SETREADONLY\n");
7627 dwStyle
= GetWindowLongA(richedit
, GWL_STYLE
);
7628 ok(dwStyle
& ES_READONLY
, "got wrong value: 0x%x\n", dwStyle
& ES_READONLY
);
7630 res
= SendMessageA(richedit
, EM_SETREADONLY
, FALSE
, 0);
7631 ok(res
== 1, "EM_SETREADONLY\n");
7632 dwStyle
= GetWindowLongA(richedit
, GWL_STYLE
);
7633 ok(!(dwStyle
& ES_READONLY
), "got wrong value: 0x%x\n", dwStyle
& ES_READONLY
);
7635 DestroyWindow(richedit
);
7638 START_TEST( editor
)
7641 /* Must explicitly LoadLibrary(). The test has no references to functions in
7642 * RICHED20.DLL, so the linker doesn't actually link to it. */
7643 hmoduleRichEdit
= LoadLibraryA("riched20.dll");
7644 ok(hmoduleRichEdit
!= NULL
, "error: %d\n", (int) GetLastError());
7647 test_EM_FINDTEXT(FALSE
);
7648 test_EM_FINDTEXT(TRUE
);
7650 test_EM_POSFROMCHAR();
7651 test_EM_SCROLLCARET();
7653 test_scrollbar_visibility();
7655 test_EM_LINELENGTH();
7656 test_EM_SETCHARFORMAT();
7657 test_EM_SETTEXTMODE();
7658 test_TM_PLAINTEXT();
7659 test_EM_SETOPTIONS();
7661 test_EM_GETTEXTRANGE();
7662 test_EM_GETSELTEXT();
7663 test_EM_SETUNDOLIMIT();
7665 test_EM_SETTEXTEX();
7666 test_EM_LIMITTEXT();
7667 test_EM_EXLIMITTEXT();
7668 test_EM_GETLIMITTEXT();
7670 test_EM_GETMODIFY();
7675 test_EM_STREAMOUT();
7676 test_EM_STREAMOUT_FONTTBL();
7677 test_EM_StreamIn_Undo();
7678 test_EM_FORMATRANGE();
7679 test_unicode_conversions();
7680 test_EM_GETTEXTLENGTHEX();
7681 test_EM_REPLACESEL(1);
7682 test_EM_REPLACESEL(0);
7685 test_EM_AUTOURLDETECT();
7687 test_undo_coalescing();
7688 test_word_movement();
7689 test_EM_CHARFROMPOS();
7690 test_SETPARAFORMAT();
7694 test_WM_GETDLGCODE();
7697 test_EM_FINDWORDBREAK_W();
7698 test_EM_FINDWORDBREAK_A();
7701 test_reset_default_para_fmt();
7702 test_EM_SETREADONLY();
7704 /* Set the environment variable WINETEST_RICHED20 to keep windows
7705 * responsive and open for 30 seconds. This is useful for debugging.
7707 if (getenv( "WINETEST_RICHED20" )) {
7708 keep_responsive(30);
7711 OleFlushClipboard();
7712 ret
= FreeLibrary(hmoduleRichEdit
);
7713 ok(ret
, "error: %d\n", (int) GetLastError());