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