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_CLASS
, 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 (PeekMessage(&msg
, NULL
, 0, 0, PM_REMOVE
)) {
87 TranslateMessage(&msg
);
88 DispatchMessage(&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 void check_EM_FINDTEXT(HWND hwnd
, const char *name
, struct find_s
*f
, int id
) {
223 memset(&ft
, 0, sizeof(ft
));
224 ft
.chrg
.cpMin
= f
->start
;
225 ft
.chrg
.cpMax
= f
->end
;
226 ft
.lpstrText
= f
->needle
;
227 findloc
= SendMessage(hwnd
, EM_FINDTEXT
, f
->flags
, (LPARAM
) &ft
);
228 ok(findloc
== f
->expected_loc
,
229 "EM_FINDTEXT(%s,%d) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
230 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
, f
->expected_loc
);
233 static void check_EM_FINDTEXTEX(HWND hwnd
, const char *name
, struct find_s
*f
,
237 int expected_end_loc
;
239 memset(&ft
, 0, sizeof(ft
));
240 ft
.chrg
.cpMin
= f
->start
;
241 ft
.chrg
.cpMax
= f
->end
;
242 ft
.lpstrText
= f
->needle
;
243 findloc
= SendMessage(hwnd
, EM_FINDTEXTEX
, f
->flags
, (LPARAM
) &ft
);
244 ok(findloc
== f
->expected_loc
,
245 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
246 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, findloc
);
247 ok(ft
.chrgText
.cpMin
== f
->expected_loc
,
248 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
249 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, ft
.chrgText
.cpMin
);
250 expected_end_loc
= ((f
->expected_loc
== -1) ? -1
251 : f
->expected_loc
+ strlen(f
->needle
));
252 ok(ft
.chrgText
.cpMax
== expected_end_loc
,
253 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n",
254 name
, id
, f
->needle
, f
->start
, f
->end
, f
->flags
, ft
.chrgText
.cpMax
, expected_end_loc
);
257 static void run_tests_EM_FINDTEXT(HWND hwnd
, const char *name
, struct find_s
*find
,
262 for (i
= 0; i
< num_tests
; i
++) {
263 check_EM_FINDTEXT(hwnd
, name
, &find
[i
], i
);
264 check_EM_FINDTEXTEX(hwnd
, name
, &find
[i
], i
);
268 static void test_EM_FINDTEXT(void)
270 HWND hwndRichEdit
= new_richedit(NULL
);
273 /* Empty rich edit control */
274 run_tests_EM_FINDTEXT(hwndRichEdit
, "1", find_tests
,
275 sizeof(find_tests
)/sizeof(struct find_s
));
277 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) haystack
);
280 run_tests_EM_FINDTEXT(hwndRichEdit
, "2", find_tests2
,
281 sizeof(find_tests2
)/sizeof(struct find_s
));
283 /* Setting a format on an arbitrary range should have no effect in search
284 results. This tests correct offset reporting across runs. */
285 cf2
.cbSize
= sizeof(CHARFORMAT2
);
286 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
287 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
288 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
289 SendMessage(hwndRichEdit
, EM_SETSEL
, 6, 20);
290 SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &cf2
);
292 /* Haystack text, again */
293 run_tests_EM_FINDTEXT(hwndRichEdit
, "2-bis", find_tests2
,
294 sizeof(find_tests2
)/sizeof(struct find_s
));
296 /* Yet another range */
297 cf2
.dwMask
= CFM_BOLD
| cf2
.dwMask
;
298 cf2
.dwEffects
= CFE_BOLD
^ cf2
.dwEffects
;
299 SendMessage(hwndRichEdit
, EM_SETSEL
, 11, 15);
300 SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &cf2
);
302 /* Haystack text, again */
303 run_tests_EM_FINDTEXT(hwndRichEdit
, "2-bisbis", find_tests2
,
304 sizeof(find_tests2
)/sizeof(struct find_s
));
306 DestroyWindow(hwndRichEdit
);
309 static const struct getline_s
{
314 {0, 10, "foo bar\r"},
319 /* Buffer smaller than line length */
325 static void test_EM_GETLINE(void)
328 HWND hwndRichEdit
= new_richedit(NULL
);
329 static const int nBuf
= 1024;
330 char dest
[1024], origdest
[1024];
331 const char text
[] = "foo bar\n"
335 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
337 memset(origdest
, 0xBB, nBuf
);
338 for (i
= 0; i
< sizeof(gl
)/sizeof(struct getline_s
); i
++)
341 int expected_nCopied
= min(gl
[i
].buffer_len
, strlen(gl
[i
].text
));
342 int expected_bytes_written
= min(gl
[i
].buffer_len
, strlen(gl
[i
].text
));
343 memset(dest
, 0xBB, nBuf
);
344 *(WORD
*) dest
= gl
[i
].buffer_len
;
346 /* EM_GETLINE appends a "\r\0" to the end of the line
347 * nCopied counts up to and including the '\r' */
348 nCopied
= SendMessage(hwndRichEdit
, EM_GETLINE
, gl
[i
].line
, (LPARAM
) dest
);
349 ok(nCopied
== expected_nCopied
, "%d: %d!=%d\n", i
, nCopied
,
351 /* two special cases since a parameter is passed via dest */
352 if (gl
[i
].buffer_len
== 0)
353 ok(!dest
[0] && !dest
[1] && !strncmp(dest
+2, origdest
+2, nBuf
-2),
355 else if (gl
[i
].buffer_len
== 1)
356 ok(dest
[0] == gl
[i
].text
[0] && !dest
[1] &&
357 !strncmp(dest
+2, origdest
+2, nBuf
-2), "buffer_len=1\n");
360 /* Prepare hex strings of buffers to dump on failure. */
361 char expectedbuf
[1024];
362 char resultbuf
[1024];
365 for (j
= 0; j
< 32; j
++)
366 sprintf(resultbuf
+strlen(resultbuf
), "%02x", dest
[j
] & 0xFF);
367 expectedbuf
[0] = '\0';
368 for (j
= 0; j
< expected_bytes_written
; j
++) /* Written bytes */
369 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", gl
[i
].text
[j
] & 0xFF);
370 for (; j
< gl
[i
].buffer_len
; j
++) /* Ignored bytes */
371 sprintf(expectedbuf
+strlen(expectedbuf
), "??");
372 for (; j
< 32; j
++) /* Bytes after declared buffer size */
373 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", origdest
[j
] & 0xFF);
375 /* Test the part of the buffer that is expected to be written according
376 * to the MSDN documentation fo EM_GETLINE, which does not state that
377 * a NULL terminating character will be added unless no text is copied.
379 * Windows NT does not append a NULL terminating character, but
380 * Windows 2000 and up do append a NULL terminating character if there
381 * is space in the buffer. The test will ignore this difference. */
382 ok(!strncmp(dest
, gl
[i
].text
, expected_bytes_written
),
383 "%d: expected_bytes_written=%d\n" "expected=0x%s\n" "but got= 0x%s\n",
384 i
, expected_bytes_written
, expectedbuf
, resultbuf
);
385 /* Test the part of the buffer after the declared length to make sure
386 * there are no buffer overruns. */
387 ok(!strncmp(dest
+ gl
[i
].buffer_len
, origdest
+ gl
[i
].buffer_len
,
388 nBuf
- gl
[i
].buffer_len
),
389 "%d: expected_bytes_written=%d\n" "expected=0x%s\n" "but got= 0x%s\n",
390 i
, expected_bytes_written
, expectedbuf
, resultbuf
);
394 DestroyWindow(hwndRichEdit
);
397 static void test_EM_LINELENGTH(void)
399 HWND hwndRichEdit
= new_richedit(NULL
);
405 int offset_test
[10][2] = {
420 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
422 for (i
= 0; i
< 10; i
++) {
423 result
= SendMessage(hwndRichEdit
, EM_LINELENGTH
, offset_test
[i
][0], 0);
424 ok(result
== offset_test
[i
][1], "Length of line at offset %d is %ld, expected %d\n",
425 offset_test
[i
][0], result
, offset_test
[i
][1]);
428 DestroyWindow(hwndRichEdit
);
431 static int get_scroll_pos_y(HWND hwnd
)
434 SendMessage(hwnd
, EM_GETSCROLLPOS
, 0, (LPARAM
) &p
);
435 ok(p
.x
!= -1 && p
.y
!= -1, "p.x:%d p.y:%d\n", p
.x
, p
.y
);
439 static void move_cursor(HWND hwnd
, LONG charindex
)
442 cr
.cpMax
= charindex
;
443 cr
.cpMin
= charindex
;
444 SendMessage(hwnd
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
447 static void line_scroll(HWND hwnd
, int amount
)
449 SendMessage(hwnd
, EM_LINESCROLL
, 0, amount
);
452 static void test_EM_SCROLLCARET(void)
455 const char text
[] = "aa\n"
456 "this is a long line of text that should be longer than the "
464 /* The richedit window height needs to be large enough vertically to fit in
465 * more than two lines of text, so the new_richedit function can't be used
466 * since a height of 60 was not large enough on some systems.
468 HWND hwndRichEdit
= CreateWindow(RICHEDIT_CLASS
, NULL
,
469 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
470 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
471 ok(hwndRichEdit
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS
, (int) GetLastError());
473 /* Can't verify this */
474 SendMessage(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
476 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
478 /* Caret above visible window */
479 line_scroll(hwndRichEdit
, 3);
480 prevY
= get_scroll_pos_y(hwndRichEdit
);
481 SendMessage(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
482 curY
= get_scroll_pos_y(hwndRichEdit
);
483 ok(prevY
!= curY
, "%d == %d\n", prevY
, curY
);
485 /* Caret below visible window */
486 move_cursor(hwndRichEdit
, sizeof(text
) - 1);
487 line_scroll(hwndRichEdit
, -3);
488 prevY
= get_scroll_pos_y(hwndRichEdit
);
489 SendMessage(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
490 curY
= get_scroll_pos_y(hwndRichEdit
);
491 ok(prevY
!= curY
, "%d == %d\n", prevY
, curY
);
493 /* Caret in visible window */
494 move_cursor(hwndRichEdit
, sizeof(text
) - 2);
495 prevY
= get_scroll_pos_y(hwndRichEdit
);
496 SendMessage(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
497 curY
= get_scroll_pos_y(hwndRichEdit
);
498 ok(prevY
== curY
, "%d != %d\n", prevY
, curY
);
500 /* Caret still in visible window */
501 line_scroll(hwndRichEdit
, -1);
502 prevY
= get_scroll_pos_y(hwndRichEdit
);
503 SendMessage(hwndRichEdit
, EM_SCROLLCARET
, 0, 0);
504 curY
= get_scroll_pos_y(hwndRichEdit
);
505 ok(prevY
== curY
, "%d != %d\n", prevY
, curY
);
507 DestroyWindow(hwndRichEdit
);
510 static void test_EM_POSFROMCHAR(void)
512 HWND hwndRichEdit
= new_richedit(NULL
);
515 unsigned int height
= 0;
520 static const char text
[] = "aa\n"
521 "this is a long line of text that should be longer than the "
530 rtl
= (GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_FONTSIGNATURE
,
531 (LPSTR
) &sig
, sizeof(LOCALESIGNATURE
)) &&
532 (sig
.lsUsb
[3] & 0x08000000) != 0);
534 /* Fill the control to lines to ensure that most of them are offscreen */
535 for (i
= 0; i
< 50; i
++)
537 /* Do not modify the string; it is exactly 16 characters long. */
538 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 0);
539 SendMessage(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"0123456789ABCDE\n");
543 Richedit 1.0 receives a POINTL* on wParam and character offset on lParam, returns void.
544 Richedit 2.0 receives character offset on wParam, ignores lParam, returns MAKELONG(x,y)
545 Richedit 3.0 accepts either of the above API conventions.
548 /* Testing Richedit 2.0 API format */
550 /* Testing start of lines. X-offset should be constant on all cases (native is 1).
551 Since all lines are identical and drawn with the same font,
552 they should have the same height... right?
554 for (i
= 0; i
< 50; i
++)
556 /* All the lines are 16 characters long */
557 result
= SendMessage(hwndRichEdit
, EM_POSFROMCHAR
, i
* 16, 0);
560 ok(HIWORD(result
) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result
));
561 ok(LOWORD(result
) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
562 xpos
= LOWORD(result
);
566 ok(HIWORD(result
) > 0, "EM_POSFROMCHAR reports y=%d, expected > 0\n", HIWORD(result
));
567 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
568 height
= HIWORD(result
);
572 ok(HIWORD(result
) == i
* height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), i
* height
);
573 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
577 /* Testing position at end of text */
578 result
= SendMessage(hwndRichEdit
, EM_POSFROMCHAR
, 50 * 16, 0);
579 ok(HIWORD(result
) == 50 * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), 50 * height
);
580 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
582 /* Testing position way past end of text */
583 result
= SendMessage(hwndRichEdit
, EM_POSFROMCHAR
, 55 * 16, 0);
584 ok(HIWORD(result
) == 50 * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), 50 * height
);
585 expected
= (rtl
? 8 : 1);
586 ok(LOWORD(result
) == expected
, "EM_POSFROMCHAR reports x=%d, expected %d\n", LOWORD(result
), expected
);
588 /* Testing that vertical scrolling does, in fact, have an effect on EM_POSFROMCHAR */
589 SendMessage(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0); /* line down */
590 for (i
= 0; i
< 50; i
++)
592 /* All the lines are 16 characters long */
593 result
= SendMessage(hwndRichEdit
, EM_POSFROMCHAR
, i
* 16, 0);
594 ok((signed short)(HIWORD(result
)) == (i
- 1) * height
,
595 "EM_POSFROMCHAR reports y=%hd, expected %d\n",
596 (signed short)(HIWORD(result
)), (i
- 1) * height
);
597 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
600 /* Testing position at end of text */
601 result
= SendMessage(hwndRichEdit
, EM_POSFROMCHAR
, 50 * 16, 0);
602 ok(HIWORD(result
) == (50 - 1) * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), (50 - 1) * height
);
603 ok(LOWORD(result
) == xpos
, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
605 /* Testing position way past end of text */
606 result
= SendMessage(hwndRichEdit
, EM_POSFROMCHAR
, 55 * 16, 0);
607 ok(HIWORD(result
) == (50 - 1) * height
, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result
), (50 - 1) * height
);
608 expected
= (rtl
? 8 : 1);
609 ok(LOWORD(result
) == expected
, "EM_POSFROMCHAR reports x=%d, expected %d\n", LOWORD(result
), expected
);
611 /* Testing that horizontal scrolling does, in fact, have an effect on EM_POSFROMCHAR */
612 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
613 SendMessage(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0); /* line up */
615 result
= SendMessage(hwndRichEdit
, EM_POSFROMCHAR
, 0, 0);
616 ok(HIWORD(result
) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result
));
617 ok(LOWORD(result
) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result
));
618 xpos
= LOWORD(result
);
620 SendMessage(hwndRichEdit
, WM_HSCROLL
, SB_LINERIGHT
, 0);
621 result
= SendMessage(hwndRichEdit
, EM_POSFROMCHAR
, 0, 0);
622 ok(HIWORD(result
) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result
));
623 ok((signed short)(LOWORD(result
)) < xpos
,
624 "EM_POSFROMCHAR reports x=%hd, expected value less than %d\n",
625 (signed short)(LOWORD(result
)), xpos
);
626 SendMessage(hwndRichEdit
, WM_HSCROLL
, SB_LINELEFT
, 0);
628 /* Test around end of text that doesn't end in a newline. */
629 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "12345678901234");
630 SendMessage(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
,
631 SendMessage(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0)-1);
632 ok(pt
.x
> 1, "pt.x = %d\n", pt
.x
);
634 SendMessage(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
,
635 SendMessage(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0));
636 ok(pt
.x
> xpos
, "pt.x = %d\n", pt
.x
);
637 xpos
= (rtl
? pt
.x
+ 7 : pt
.x
);
638 SendMessage(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
,
639 SendMessage(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0)+1);
640 ok(pt
.x
== xpos
, "pt.x = %d\n", pt
.x
);
642 /* Try a negative position. */
643 SendMessage(hwndRichEdit
, EM_POSFROMCHAR
, (WPARAM
)&pt
, -1);
644 ok(pt
.x
== 1, "pt.x = %d\n", pt
.x
);
646 DestroyWindow(hwndRichEdit
);
649 static void test_EM_SETCHARFORMAT(void)
651 HWND hwndRichEdit
= new_richedit(NULL
);
654 int tested_effects
[] = {
670 rtl
= (GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_FONTSIGNATURE
,
671 (LPSTR
) &sig
, sizeof(LOCALESIGNATURE
)) &&
672 (sig
.lsUsb
[3] & 0x08000000) != 0);
674 /* Invalid flags, CHARFORMAT2 structure blanked out */
675 memset(&cf2
, 0, sizeof(cf2
));
676 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) 0xfffffff0,
678 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
680 /* A valid flag, CHARFORMAT2 structure blanked out */
681 memset(&cf2
, 0, sizeof(cf2
));
682 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) SCF_DEFAULT
,
684 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
686 /* A valid flag, CHARFORMAT2 structure blanked out */
687 memset(&cf2
, 0, sizeof(cf2
));
688 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) SCF_SELECTION
,
690 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
692 /* A valid flag, CHARFORMAT2 structure blanked out */
693 memset(&cf2
, 0, sizeof(cf2
));
694 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) SCF_WORD
,
696 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
698 /* A valid flag, CHARFORMAT2 structure blanked out */
699 memset(&cf2
, 0, sizeof(cf2
));
700 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) SCF_ALL
,
702 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
704 /* Invalid flags, CHARFORMAT2 structure minimally filled */
705 memset(&cf2
, 0, sizeof(cf2
));
706 cf2
.cbSize
= sizeof(CHARFORMAT2
);
707 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) 0xfffffff0,
709 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
710 rc
= SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0);
711 ok(rc
== FALSE
, "Should not be able to undo here.\n");
712 SendMessage(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
714 /* A valid flag, CHARFORMAT2 structure minimally filled */
715 memset(&cf2
, 0, sizeof(cf2
));
716 cf2
.cbSize
= sizeof(CHARFORMAT2
);
717 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) SCF_DEFAULT
,
719 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
720 rc
= SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0);
721 ok(rc
== FALSE
, "Should not be able to undo here.\n");
722 SendMessage(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
724 /* A valid flag, CHARFORMAT2 structure minimally filled */
725 memset(&cf2
, 0, sizeof(cf2
));
726 cf2
.cbSize
= sizeof(CHARFORMAT2
);
727 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) SCF_SELECTION
,
729 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
730 rc
= SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0);
731 ok(rc
== FALSE
, "Should not be able to undo here.\n");
732 SendMessage(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
734 /* A valid flag, CHARFORMAT2 structure minimally filled */
735 memset(&cf2
, 0, sizeof(cf2
));
736 cf2
.cbSize
= sizeof(CHARFORMAT2
);
737 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) SCF_WORD
,
739 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
740 rc
= SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0);
741 todo_wine
ok(rc
== TRUE
, "Should not be able to undo here.\n");
742 SendMessage(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
744 /* A valid flag, CHARFORMAT2 structure minimally filled */
745 memset(&cf2
, 0, sizeof(cf2
));
746 cf2
.cbSize
= sizeof(CHARFORMAT2
);
747 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) SCF_ALL
,
749 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
750 rc
= SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0);
751 ok(rc
== TRUE
, "Should not be able to undo here.\n");
752 SendMessage(hwndRichEdit
, EM_EMPTYUNDOBUFFER
, 0, 0);
754 cf2
.cbSize
= sizeof(CHARFORMAT2
);
755 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_DEFAULT
,
758 /* Test state of modify flag before and after valid EM_SETCHARFORMAT */
759 cf2
.cbSize
= sizeof(CHARFORMAT2
);
760 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_DEFAULT
,
762 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
763 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
765 /* wParam==0 is default char format, does not set modify */
766 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
767 rc
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
768 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
769 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, 0, (LPARAM
) &cf2
);
770 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
773 rc
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
774 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
777 skip("RTL language found\n");
779 /* wParam==SCF_SELECTION sets modify if nonempty selection */
780 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
781 rc
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
782 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
783 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &cf2
);
784 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
785 rc
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
786 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
788 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
789 rc
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
790 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
791 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &cf2
);
792 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
793 rc
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
794 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
795 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 2);
796 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &cf2
);
797 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
798 rc
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
799 ok(rc
== -1, "Text not marked as modified, expected modified! (%d)\n", rc
);
801 /* wParam==SCF_ALL sets modify regardless of whether text is present */
802 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
803 rc
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
804 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
805 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) SCF_ALL
, (LPARAM
) &cf2
);
806 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
807 rc
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
808 ok(rc
== -1, "Text not marked as modified, expected modified! (%d)\n", rc
);
810 DestroyWindow(hwndRichEdit
);
812 /* EM_GETCHARFORMAT tests */
813 for (i
= 0; tested_effects
[i
]; i
++)
815 hwndRichEdit
= new_richedit(NULL
);
816 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
818 /* Need to set a TrueType font to get consistent CFM_BOLD results */
819 memset(&cf2
, 0, sizeof(CHARFORMAT2
));
820 cf2
.cbSize
= sizeof(CHARFORMAT2
);
821 cf2
.dwMask
= CFM_FACE
|CFM_WEIGHT
;
823 strcpy(cf2
.szFaceName
, "Courier New");
824 cf2
.wWeight
= FW_DONTCARE
;
825 SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
) &cf2
);
827 memset(&cf2
, 0, sizeof(CHARFORMAT2
));
828 cf2
.cbSize
= sizeof(CHARFORMAT2
);
829 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 4);
830 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &cf2
);
831 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
832 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
834 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
835 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
836 ok((cf2
.dwEffects
& tested_effects
[i
]) == 0,
837 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
839 memset(&cf2
, 0, sizeof(CHARFORMAT2
));
840 cf2
.cbSize
= sizeof(CHARFORMAT2
);
841 cf2
.dwMask
= tested_effects
[i
];
842 if (cf2
.dwMask
== CFE_SUBSCRIPT
|| cf2
.dwMask
== CFE_SUPERSCRIPT
)
843 cf2
.dwMask
= CFM_SUPERSCRIPT
;
844 cf2
.dwEffects
= tested_effects
[i
];
845 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 2);
846 SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &cf2
);
848 memset(&cf2
, 0, sizeof(CHARFORMAT2
));
849 cf2
.cbSize
= sizeof(CHARFORMAT2
);
850 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 2);
851 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &cf2
);
852 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
853 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
855 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
856 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
857 ok((cf2
.dwEffects
& tested_effects
[i
]) == tested_effects
[i
],
858 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
860 memset(&cf2
, 0, sizeof(CHARFORMAT2
));
861 cf2
.cbSize
= sizeof(CHARFORMAT2
);
862 SendMessage(hwndRichEdit
, EM_SETSEL
, 2, 4);
863 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &cf2
);
864 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
865 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
867 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
868 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
869 ok((cf2
.dwEffects
& tested_effects
[i
]) == 0,
870 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
872 memset(&cf2
, 0, sizeof(CHARFORMAT2
));
873 cf2
.cbSize
= sizeof(CHARFORMAT2
);
874 SendMessage(hwndRichEdit
, EM_SETSEL
, 1, 3);
875 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &cf2
);
876 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
877 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == 0)
879 (cf2
.dwMask
& tested_effects
[i
]) == 0),
880 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i
, cf2
.dwMask
, tested_effects
[i
]);
882 DestroyWindow(hwndRichEdit
);
885 for (i
= 0; tested_effects
[i
]; i
++)
887 hwndRichEdit
= new_richedit(NULL
);
888 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
890 /* Need to set a TrueType font to get consistent CFM_BOLD results */
891 memset(&cf2
, 0, sizeof(CHARFORMAT2
));
892 cf2
.cbSize
= sizeof(CHARFORMAT2
);
893 cf2
.dwMask
= CFM_FACE
|CFM_WEIGHT
;
895 strcpy(cf2
.szFaceName
, "Courier New");
896 cf2
.wWeight
= FW_DONTCARE
;
897 SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
) &cf2
);
899 memset(&cf2
, 0, sizeof(CHARFORMAT2
));
900 cf2
.cbSize
= sizeof(CHARFORMAT2
);
901 cf2
.dwMask
= tested_effects
[i
];
902 if (cf2
.dwMask
== CFE_SUBSCRIPT
|| cf2
.dwMask
== CFE_SUPERSCRIPT
)
903 cf2
.dwMask
= CFM_SUPERSCRIPT
;
904 cf2
.dwEffects
= tested_effects
[i
];
905 SendMessage(hwndRichEdit
, EM_SETSEL
, 2, 4);
906 SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &cf2
);
908 memset(&cf2
, 0, sizeof(CHARFORMAT2
));
909 cf2
.cbSize
= sizeof(CHARFORMAT2
);
910 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 2);
911 SendMessage(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(CHARFORMAT2
));
921 cf2
.cbSize
= sizeof(CHARFORMAT2
);
922 SendMessage(hwndRichEdit
, EM_SETSEL
, 2, 4);
923 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &cf2
);
924 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
925 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == CFM_SUPERSCRIPT
)
927 (cf2
.dwMask
& tested_effects
[i
]) == tested_effects
[i
]),
928 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, tested_effects
[i
]);
929 ok((cf2
.dwEffects
& tested_effects
[i
]) == tested_effects
[i
],
930 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
932 memset(&cf2
, 0, sizeof(CHARFORMAT2
));
933 cf2
.cbSize
= sizeof(CHARFORMAT2
);
934 SendMessage(hwndRichEdit
, EM_SETSEL
, 1, 3);
935 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &cf2
);
936 ok ((((tested_effects
[i
] == CFE_SUBSCRIPT
|| tested_effects
[i
] == CFE_SUPERSCRIPT
) &&
937 (cf2
.dwMask
& CFM_SUPERSCRIPT
) == 0)
939 (cf2
.dwMask
& tested_effects
[i
]) == 0),
940 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i
, cf2
.dwMask
, tested_effects
[i
]);
941 ok((cf2
.dwEffects
& tested_effects
[i
]) == tested_effects
[i
],
942 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x set\n", i
, cf2
.dwEffects
, tested_effects
[i
]);
944 DestroyWindow(hwndRichEdit
);
947 /* Effects applied on an empty selection should take effect when selection is
948 replaced with text */
949 hwndRichEdit
= new_richedit(NULL
);
950 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
951 SendMessage(hwndRichEdit
, EM_SETSEL
, 2, 2); /* Empty selection */
953 memset(&cf2
, 0, sizeof(CHARFORMAT2
));
954 cf2
.cbSize
= sizeof(CHARFORMAT2
);
955 cf2
.dwMask
= CFM_BOLD
;
956 cf2
.dwEffects
= CFE_BOLD
;
957 SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &cf2
);
959 /* Selection is now nonempty */
960 SendMessage(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
962 memset(&cf2
, 0, sizeof(CHARFORMAT2
));
963 cf2
.cbSize
= sizeof(CHARFORMAT2
);
964 SendMessage(hwndRichEdit
, EM_SETSEL
, 2, 6);
965 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &cf2
);
967 ok (((cf2
.dwMask
& CFM_BOLD
) == CFM_BOLD
),
968 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, CFM_BOLD
);
969 ok((cf2
.dwEffects
& CFE_BOLD
) == CFE_BOLD
,
970 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, CFE_BOLD
);
973 /* Set two effects on an empty selection */
974 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
975 SendMessage(hwndRichEdit
, EM_SETSEL
, 2, 2); /* Empty selection */
977 memset(&cf2
, 0, sizeof(CHARFORMAT2
));
978 cf2
.cbSize
= sizeof(CHARFORMAT2
);
979 cf2
.dwMask
= CFM_BOLD
;
980 cf2
.dwEffects
= CFE_BOLD
;
981 SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &cf2
);
982 cf2
.dwMask
= CFM_ITALIC
;
983 cf2
.dwEffects
= CFE_ITALIC
;
984 SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &cf2
);
986 /* Selection is now nonempty */
987 SendMessage(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
989 memset(&cf2
, 0, sizeof(CHARFORMAT2
));
990 cf2
.cbSize
= sizeof(CHARFORMAT2
);
991 SendMessage(hwndRichEdit
, EM_SETSEL
, 2, 6);
992 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &cf2
);
994 ok (((cf2
.dwMask
& (CFM_BOLD
|CFM_ITALIC
)) == (CFM_BOLD
|CFM_ITALIC
)),
995 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, (CFM_BOLD
|CFM_ITALIC
));
996 ok((cf2
.dwEffects
& (CFE_BOLD
|CFE_ITALIC
)) == (CFE_BOLD
|CFE_ITALIC
),
997 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, (CFE_BOLD
|CFE_ITALIC
));
999 /* Setting the (empty) selection to exactly the same place as before should
1000 NOT clear the insertion style! */
1001 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1002 SendMessage(hwndRichEdit
, EM_SETSEL
, 2, 2); /* Empty selection */
1004 memset(&cf2
, 0, sizeof(CHARFORMAT2
));
1005 cf2
.cbSize
= sizeof(CHARFORMAT2
);
1006 cf2
.dwMask
= CFM_BOLD
;
1007 cf2
.dwEffects
= CFE_BOLD
;
1008 SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &cf2
);
1010 /* Empty selection in same place, insert style should NOT be forgotten here. */
1011 SendMessage(hwndRichEdit
, EM_SETSEL
, 2, 2);
1013 /* Selection is now nonempty */
1014 SendMessage(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1016 memset(&cf2
, 0, sizeof(CHARFORMAT2
));
1017 cf2
.cbSize
= sizeof(CHARFORMAT2
);
1018 SendMessage(hwndRichEdit
, EM_SETSEL
, 2, 6);
1019 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &cf2
);
1021 ok (((cf2
.dwMask
& CFM_BOLD
) == CFM_BOLD
),
1022 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, CFM_BOLD
);
1023 ok((cf2
.dwEffects
& CFE_BOLD
) == CFE_BOLD
,
1024 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, CFE_BOLD
);
1026 /* Ditto with EM_EXSETSEL */
1027 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"wine");
1028 cr
.cpMin
= 2; cr
.cpMax
= 2;
1029 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
); /* Empty selection */
1031 memset(&cf2
, 0, sizeof(CHARFORMAT2
));
1032 cf2
.cbSize
= sizeof(CHARFORMAT2
);
1033 cf2
.dwMask
= CFM_BOLD
;
1034 cf2
.dwEffects
= CFE_BOLD
;
1035 SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &cf2
);
1037 /* Empty selection in same place, insert style should NOT be forgotten here. */
1038 cr
.cpMin
= 2; cr
.cpMax
= 2;
1039 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
); /* Empty selection */
1041 /* Selection is now nonempty */
1042 SendMessage(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)"newi");
1044 memset(&cf2
, 0, sizeof(CHARFORMAT2
));
1045 cf2
.cbSize
= sizeof(CHARFORMAT2
);
1046 cr
.cpMin
= 2; cr
.cpMax
= 6;
1047 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
)&cr
); /* Empty selection */
1048 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &cf2
);
1050 ok (((cf2
.dwMask
& CFM_BOLD
) == CFM_BOLD
),
1051 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i
, cf2
.dwMask
, CFM_BOLD
);
1052 ok((cf2
.dwEffects
& CFE_BOLD
) == CFE_BOLD
,
1053 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i
, cf2
.dwEffects
, CFE_BOLD
);
1055 DestroyWindow(hwndRichEdit
);
1058 static void test_EM_SETTEXTMODE(void)
1060 HWND hwndRichEdit
= new_richedit(NULL
);
1061 CHARFORMAT2 cf2
, cf2test
;
1065 /*Attempt to use mutually exclusive modes*/
1066 rc
= SendMessage(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
) TM_PLAINTEXT
|TM_RICHTEXT
, 0);
1067 ok(rc
== E_INVALIDARG
,
1068 "EM_SETTEXTMODE: using mutually exclusive mode flags - returned: %x\n", rc
);
1070 /*Test that EM_SETTEXTMODE fails if text exists within the control*/
1071 /*Insert text into the control*/
1073 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "wine");
1075 /*Attempt to change the control to plain text mode*/
1076 rc
= SendMessage(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
) TM_PLAINTEXT
, 0);
1077 ok(rc
== E_UNEXPECTED
,
1078 "EM_SETTEXTMODE: changed text mode in control containing text - returned: %x\n", rc
);
1080 /*Test that EM_SETTEXTMODE does not allow rich edit text to be pasted.
1081 If rich text is pasted, it should have the same formatting as the rest
1082 of the text in the control*/
1084 /*Italicize the text
1085 *NOTE: If the default text was already italicized, the test will simply
1086 reverse; in other words, it will copy a regular "wine" into a plain
1087 text window that uses an italicized format*/
1088 cf2
.cbSize
= sizeof(CHARFORMAT2
);
1089 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_DEFAULT
,
1092 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
1093 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
1095 rc
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1096 ok(rc
== 0, "Text marked as modified, expected not modified!\n");
1098 /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine;
1099 however, SCF_ALL has been implemented*/
1100 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) SCF_ALL
, (LPARAM
) &cf2
);
1101 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1103 rc
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
1104 ok(rc
== -1, "Text not marked as modified, expected modified! (%d)\n", rc
);
1106 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "wine");
1108 /*Select the string "wine"*/
1111 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
1113 /*Copy the italicized "wine" to the clipboard*/
1114 SendMessage(hwndRichEdit
, WM_COPY
, 0, 0);
1116 /*Reset the formatting to default*/
1117 cf2
.dwEffects
= CFE_ITALIC
^cf2
.dwEffects
;
1118 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, (WPARAM
) SCF_ALL
, (LPARAM
) &cf2
);
1119 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1121 /*Clear the text in the control*/
1122 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "");
1124 /*Switch to Plain Text Mode*/
1125 rc
= SendMessage(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
) TM_PLAINTEXT
, 0);
1126 ok(rc
== 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control: returned: %d\n", rc
);
1128 /*Input "wine" again in normal format*/
1129 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "wine");
1131 /*Paste the italicized "wine" into the control*/
1132 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
1134 /*Select a character from the first "wine" string*/
1137 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
1139 /*Retrieve its formatting*/
1140 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_SELECTION
,
1143 /*Select a character from the second "wine" string*/
1146 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
1148 /*Retrieve its formatting*/
1149 cf2test
.cbSize
= sizeof(CHARFORMAT2
);
1150 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_SELECTION
,
1153 /*Compare the two formattings*/
1154 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
1155 "two formats found in plain text mode - cf2.dwEffects: %x cf2test.dwEffects: %x\n",
1156 cf2
.dwEffects
, cf2test
.dwEffects
);
1157 /*Test TM_RICHTEXT by: switching back to Rich Text mode
1158 printing "wine" in the current format(normal)
1159 pasting "wine" from the clipboard(italicized)
1160 comparing the two formats(should differ)*/
1162 /*Attempt to switch with text in control*/
1163 rc
= SendMessage(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
) TM_RICHTEXT
, 0);
1164 ok(rc
!= 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc
);
1167 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "");
1169 /*Switch into Rich Text mode*/
1170 rc
= SendMessage(hwndRichEdit
, EM_SETTEXTMODE
, (WPARAM
) TM_RICHTEXT
, 0);
1171 ok(rc
== 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc
);
1173 /*Print "wine" in normal formatting into the control*/
1174 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "wine");
1176 /*Paste italicized "wine" into the control*/
1177 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
1179 /*Select text from the first "wine" string*/
1182 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
1184 /*Retrieve its formatting*/
1185 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_SELECTION
,
1188 /*Select text from the second "wine" string*/
1191 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
1193 /*Retrieve its formatting*/
1194 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, (WPARAM
) SCF_SELECTION
,
1197 /*Test that the two formattings are not the same*/
1198 todo_wine
ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
!= cf2test
.dwEffects
),
1199 "expected different formats - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1200 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
1202 DestroyWindow(hwndRichEdit
);
1205 static void test_SETPARAFORMAT(void)
1207 HWND hwndRichEdit
= new_richedit(NULL
);
1210 LONG expectedMask
= PFM_ALL2
& ~PFM_TABLEROWDELIMITER
;
1211 fmt
.cbSize
= sizeof(PARAFORMAT2
);
1212 fmt
.dwMask
= PFM_ALIGNMENT
;
1213 fmt
.wAlignment
= PFA_LEFT
;
1215 ret
= SendMessage(hwndRichEdit
, EM_SETPARAFORMAT
, 0, (LPARAM
) &fmt
);
1216 ok(ret
!= 0, "expected non-zero got %d\n", ret
);
1218 fmt
.cbSize
= sizeof(PARAFORMAT2
);
1220 ret
= SendMessage(hwndRichEdit
, EM_GETPARAFORMAT
, 0, (LPARAM
) &fmt
);
1221 /* Ignore the PFM_TABLEROWDELIMITER bit because it changes
1222 * between richedit different native builds of riched20.dll
1223 * used on different Windows versions. */
1224 ret
&= ~PFM_TABLEROWDELIMITER
;
1225 fmt
.dwMask
&= ~PFM_TABLEROWDELIMITER
;
1227 ok(ret
== expectedMask
, "expected %x got %x\n", expectedMask
, ret
);
1228 ok(fmt
.dwMask
== expectedMask
, "expected %x got %x\n", expectedMask
, fmt
.dwMask
);
1230 DestroyWindow(hwndRichEdit
);
1233 static void test_TM_PLAINTEXT(void)
1235 /*Tests plain text properties*/
1237 HWND hwndRichEdit
= new_richedit(NULL
);
1238 CHARFORMAT2 cf2
, cf2test
;
1242 /*Switch to plain text mode*/
1244 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "");
1245 SendMessage(hwndRichEdit
, EM_SETTEXTMODE
, TM_PLAINTEXT
, 0);
1247 /*Fill control with text*/
1249 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "Is Wine an emulator? No it's not");
1251 /*Select some text and bold it*/
1255 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
1256 cf2
.cbSize
= sizeof(CHARFORMAT2
);
1257 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
1259 cf2
.dwMask
= CFM_BOLD
| cf2
.dwMask
;
1260 cf2
.dwEffects
= CFE_BOLD
^ cf2
.dwEffects
;
1262 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1263 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
1265 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_WORD
| SCF_SELECTION
, (LPARAM
)&cf2
);
1266 ok(rc
== 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc
);
1268 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
1269 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1271 /*Get the formatting of those characters*/
1273 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1275 /*Get the formatting of some other characters*/
1276 cf2test
.cbSize
= sizeof(CHARFORMAT2
);
1279 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
1280 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2test
);
1282 /*Test that they are the same as plain text allows only one formatting*/
1284 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
1285 "two selections' formats differ - cf2.dwMask: %x, cf2test.dwMask %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1286 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
1288 /*Fill the control with a "wine" string, which when inserted will be bold*/
1290 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "wine");
1292 /*Copy the bolded "wine" string*/
1296 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
1297 SendMessage(hwndRichEdit
, WM_COPY
, 0, 0);
1299 /*Swap back to rich text*/
1301 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "");
1302 SendMessage(hwndRichEdit
, EM_SETTEXTMODE
, TM_RICHTEXT
, 0);
1304 /*Set the default formatting to bold italics*/
1306 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
1307 cf2
.dwMask
|= CFM_ITALIC
;
1308 cf2
.dwEffects
^= CFE_ITALIC
;
1309 rc
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
1310 ok(rc
== 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc
);
1312 /*Set the text in the control to "wine", which will be bold and italicized*/
1314 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "wine");
1316 /*Paste the plain text "wine" string, which should take the insert
1317 formatting, which at the moment is bold italics*/
1319 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
1321 /*Select the first "wine" string and retrieve its formatting*/
1325 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
1326 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2
);
1328 /*Select the second "wine" string and retrieve its formatting*/
1332 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
1333 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
)&cf2test
);
1335 /*Compare the two formattings. They should be the same.*/
1337 ok((cf2
.dwMask
== cf2test
.dwMask
) && (cf2
.dwEffects
== cf2test
.dwEffects
),
1338 "Copied text retained formatting - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1339 cf2
.dwMask
, cf2test
.dwMask
, cf2
.dwEffects
, cf2test
.dwEffects
);
1340 DestroyWindow(hwndRichEdit
);
1343 static void test_WM_GETTEXT(void)
1345 HWND hwndRichEdit
= new_richedit(NULL
);
1346 static const char text
[] = "Hello. My name is RichEdit!";
1347 static const char text2
[] = "Hello. My name is RichEdit!\r";
1348 static const char text2_after
[] = "Hello. My name is RichEdit!\r\n";
1349 char buffer
[1024] = {0};
1352 /* Baseline test with normal-sized buffer */
1353 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
1354 result
= SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1355 ok(result
== lstrlen(buffer
),
1356 "WM_GETTEXT returned %d, expected %d\n", result
, lstrlen(buffer
));
1357 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1358 result
= strcmp(buffer
,text
);
1360 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1362 /* Test for returned value of WM_GETTEXTLENGTH */
1363 result
= SendMessage(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0);
1364 ok(result
== lstrlen(text
),
1365 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
1366 result
, lstrlen(text
));
1368 /* Test for behavior in overflow case */
1369 memset(buffer
, 0, 1024);
1370 result
= SendMessage(hwndRichEdit
, WM_GETTEXT
, strlen(text
), (LPARAM
)buffer
);
1372 result
== lstrlenA(text
) - 1, /* XP, win2k3 */
1373 "WM_GETTEXT returned %d, expected 0 or %d\n", result
, lstrlenA(text
) - 1);
1374 result
= strcmp(buffer
,text
);
1376 result
= strncmp(buffer
, text
, lstrlenA(text
) - 1); /* XP, win2k3 */
1378 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1380 /* Baseline test with normal-sized buffer and carriage return */
1381 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text2
);
1382 result
= SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1383 ok(result
== lstrlen(buffer
),
1384 "WM_GETTEXT returned %d, expected %d\n", result
, lstrlen(buffer
));
1385 result
= strcmp(buffer
,text2_after
);
1387 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1389 /* Test for returned value of WM_GETTEXTLENGTH */
1390 result
= SendMessage(hwndRichEdit
, WM_GETTEXTLENGTH
, 0, 0);
1391 ok(result
== lstrlen(text2_after
),
1392 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
1393 result
, lstrlen(text2_after
));
1395 /* Test for behavior of CRLF conversion in case of overflow */
1396 memset(buffer
, 0, 1024);
1397 result
= SendMessage(hwndRichEdit
, WM_GETTEXT
, strlen(text2
), (LPARAM
)buffer
);
1399 result
== lstrlenA(text2
) - 1, /* XP, win2k3 */
1400 "WM_GETTEXT returned %d, expected 0 or %d\n", result
, lstrlenA(text2
) - 1);
1401 result
= strcmp(buffer
,text2
);
1403 result
= strncmp(buffer
, text2
, lstrlenA(text2
) - 1); /* XP, win2k3 */
1405 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result
);
1407 DestroyWindow(hwndRichEdit
);
1410 static void test_EM_GETTEXTRANGE(void)
1412 HWND hwndRichEdit
= new_richedit(NULL
);
1413 const char * text1
= "foo bar\r\nfoo bar";
1414 const char * text2
= "foo bar\rfoo bar";
1415 const char * expect
= "bar\rfoo";
1416 char buffer
[1024] = {0};
1418 TEXTRANGEA textRange
;
1420 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
1422 textRange
.lpstrText
= buffer
;
1423 textRange
.chrg
.cpMin
= 4;
1424 textRange
.chrg
.cpMax
= 11;
1425 result
= SendMessage(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1426 ok(result
== 7, "EM_GETTEXTRANGE returned %ld\n", result
);
1427 ok(!strcmp(expect
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1429 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
1431 textRange
.lpstrText
= buffer
;
1432 textRange
.chrg
.cpMin
= 4;
1433 textRange
.chrg
.cpMax
= 11;
1434 result
= SendMessage(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1435 ok(result
== 7, "EM_GETTEXTRANGE returned %ld\n", result
);
1436 ok(!strcmp(expect
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1438 /* cpMax of text length is used instead of -1 in this case */
1439 textRange
.lpstrText
= buffer
;
1440 textRange
.chrg
.cpMin
= 0;
1441 textRange
.chrg
.cpMax
= -1;
1442 result
= SendMessage(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1443 ok(result
== strlen(text2
), "EM_GETTEXTRANGE returned %ld\n", result
);
1444 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1446 /* cpMin < 0 causes no text to be copied, and 0 to be returned */
1447 textRange
.lpstrText
= buffer
;
1448 textRange
.chrg
.cpMin
= -1;
1449 textRange
.chrg
.cpMax
= 1;
1450 result
= SendMessage(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1451 ok(result
== 0, "EM_GETTEXTRANGE returned %ld\n", result
);
1452 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1454 /* cpMax of -1 is not replaced with text length if cpMin != 0 */
1455 textRange
.lpstrText
= buffer
;
1456 textRange
.chrg
.cpMin
= 1;
1457 textRange
.chrg
.cpMax
= -1;
1458 result
= SendMessage(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1459 ok(result
== 0, "EM_GETTEXTRANGE returned %ld\n", result
);
1460 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1462 /* no end character is copied if cpMax - cpMin < 0 */
1463 textRange
.lpstrText
= buffer
;
1464 textRange
.chrg
.cpMin
= 5;
1465 textRange
.chrg
.cpMax
= 5;
1466 result
= SendMessage(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1467 ok(result
== 0, "EM_GETTEXTRANGE returned %ld\n", result
);
1468 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1470 /* cpMax of text length is used if cpMax > text length*/
1471 textRange
.lpstrText
= buffer
;
1472 textRange
.chrg
.cpMin
= 0;
1473 textRange
.chrg
.cpMax
= 1000;
1474 result
= SendMessage(hwndRichEdit
, EM_GETTEXTRANGE
, 0, (LPARAM
)&textRange
);
1475 ok(result
== strlen(text2
), "EM_GETTEXTRANGE returned %ld\n", result
);
1476 ok(!strcmp(text2
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1478 DestroyWindow(hwndRichEdit
);
1481 static void test_EM_GETSELTEXT(void)
1483 HWND hwndRichEdit
= new_richedit(NULL
);
1484 const char * text1
= "foo bar\r\nfoo bar";
1485 const char * text2
= "foo bar\rfoo bar";
1486 const char * expect
= "bar\rfoo";
1487 char buffer
[1024] = {0};
1490 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text1
);
1492 SendMessage(hwndRichEdit
, EM_SETSEL
, 4, 11);
1493 result
= SendMessage(hwndRichEdit
, EM_GETSELTEXT
, 0, (LPARAM
)buffer
);
1494 ok(result
== 7, "EM_GETTEXTRANGE returned %ld\n", result
);
1495 ok(!strcmp(expect
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1497 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text2
);
1499 SendMessage(hwndRichEdit
, EM_SETSEL
, 4, 11);
1500 result
= SendMessage(hwndRichEdit
, EM_GETSELTEXT
, 0, (LPARAM
)buffer
);
1501 ok(result
== 7, "EM_GETTEXTRANGE returned %ld\n", result
);
1502 ok(!strcmp(expect
, buffer
), "EM_GETTEXTRANGE filled %s\n", buffer
);
1504 DestroyWindow(hwndRichEdit
);
1507 /* FIXME: need to test unimplemented options and robustly test wparam */
1508 static void test_EM_SETOPTIONS(void)
1511 static const char text
[] = "Hello. My name is RichEdit!";
1512 char buffer
[1024] = {0};
1513 DWORD dwStyle
, options
, oldOptions
;
1514 DWORD optionStyles
= ES_AUTOVSCROLL
|ES_AUTOHSCROLL
|ES_NOHIDESEL
|
1515 ES_READONLY
|ES_WANTRETURN
|ES_SAVESEL
|
1516 ES_SELECTIONBAR
|ES_VERTICAL
;
1518 /* Test initial options. */
1519 hwndRichEdit
= CreateWindow(RICHEDIT_CLASS
, NULL
, WS_POPUP
,
1520 0, 0, 200, 60, NULL
, NULL
,
1521 hmoduleRichEdit
, NULL
);
1522 ok(hwndRichEdit
!= NULL
, "class: %s, error: %d\n",
1523 RICHEDIT_CLASS
, (int) GetLastError());
1524 options
= SendMessage(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1525 ok(options
== 0, "Incorrect initial options %x\n", options
);
1526 DestroyWindow(hwndRichEdit
);
1528 hwndRichEdit
= CreateWindow(RICHEDIT_CLASS
, NULL
,
1529 WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
1530 0, 0, 200, 60, NULL
, NULL
,
1531 hmoduleRichEdit
, NULL
);
1532 ok(hwndRichEdit
!= NULL
, "class: %s, error: %d\n",
1533 RICHEDIT_CLASS
, (int) GetLastError());
1534 options
= SendMessage(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1535 /* WS_[VH]SCROLL cause the ECO_AUTO[VH]SCROLL options to be set */
1536 ok(options
== (ECO_AUTOVSCROLL
|ECO_AUTOHSCROLL
),
1537 "Incorrect initial options %x\n", options
);
1539 /* NEGATIVE TESTING - NO OPTIONS SET */
1540 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
1541 SendMessage(hwndRichEdit
, EM_SETOPTIONS
, ECOOP_SET
, 0);
1543 /* testing no readonly by sending 'a' to the control*/
1544 SendMessage(hwndRichEdit
, WM_CHAR
, 'a', 0x1E0001);
1545 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1547 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text
, buffer
);
1548 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
1550 /* READONLY - sending 'a' to the control */
1551 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
1552 SendMessage(hwndRichEdit
, EM_SETOPTIONS
, ECOOP_SET
, ECO_READONLY
);
1553 SendMessage(hwndRichEdit
, WM_CHAR
, 'a', 0x1E0001);
1554 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1555 ok(buffer
[0]==text
[0],
1556 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text
, buffer
);
1558 /* EM_SETOPTIONS changes the window style, but changing the
1559 * window style does not change the options. */
1560 dwStyle
= GetWindowLong(hwndRichEdit
, GWL_STYLE
);
1561 ok(dwStyle
& ES_READONLY
, "Readonly style not set by EM_SETOPTIONS\n");
1562 SetWindowLong(hwndRichEdit
, GWL_STYLE
, dwStyle
& ~ES_READONLY
);
1563 options
= SendMessage(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1564 ok(options
& ES_READONLY
, "Readonly option set by SetWindowLong\n");
1565 /* Confirm that the text is still read only. */
1566 SendMessage(hwndRichEdit
, WM_CHAR
, 'a', ('a' << 16) | 0x0001);
1567 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
1568 ok(buffer
[0]==text
[0],
1569 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text
, buffer
);
1571 oldOptions
= options
;
1572 SetWindowLong(hwndRichEdit
, GWL_STYLE
, dwStyle
|optionStyles
);
1573 options
= SendMessage(hwndRichEdit
, EM_GETOPTIONS
, 0, 0);
1574 ok(options
== oldOptions
,
1575 "Options set by SetWindowLong (%x -> %x)\n", oldOptions
, options
);
1577 DestroyWindow(hwndRichEdit
);
1580 static int check_CFE_LINK_selection(HWND hwnd
, int sel_start
, int sel_end
)
1582 CHARFORMAT2W text_format
;
1583 text_format
.cbSize
= sizeof(text_format
);
1584 SendMessage(hwnd
, EM_SETSEL
, sel_start
, sel_end
);
1585 SendMessage(hwnd
, EM_GETCHARFORMAT
, SCF_SELECTION
, (LPARAM
) &text_format
);
1586 return (text_format
.dwEffects
& CFE_LINK
) ? 1 : 0;
1589 static void check_CFE_LINK_rcvd(HWND hwnd
, int is_url
, const char * url
)
1591 int link_present
= 0;
1593 link_present
= check_CFE_LINK_selection(hwnd
, 0, 1);
1595 { /* control text is url; should get CFE_LINK */
1596 ok(0 != link_present
, "URL Case: CFE_LINK not set for [%s].\n", url
);
1600 ok(0 == link_present
, "Non-URL Case: CFE_LINK set for [%s].\n", url
);
1604 static HWND
new_static_wnd(HWND parent
) {
1605 return new_window("Static", 0, parent
);
1608 static void test_EM_AUTOURLDETECT(void)
1610 /* DO NOT change the properties of the first two elements. To shorten the
1611 tests, all tests after WM_SETTEXT test just the first two elements -
1612 one non-URL and one URL */
1618 {"http://www.winehq.org", 1},
1619 {"http//winehq.org", 0},
1620 {"ww.winehq.org", 0},
1621 {"www.winehq.org", 1},
1622 {"ftp://192.168.1.1", 1},
1623 {"ftp//192.168.1.1", 0},
1624 {"mailto:your@email.com", 1},
1625 {"prospero:prosperoserver", 1},
1627 {"news:newserver", 1},
1628 {"wais:waisserver", 1}
1633 HWND hwndRichEdit
, parent
;
1635 /* All of the following should cause the URL to be detected */
1636 const char * templates_delim
[] = {
1637 "This is some text with X on it",
1638 "This is some text with (X) on it",
1639 "This is some text with X\r on it",
1640 "This is some text with ---X--- on it",
1641 "This is some text with \"X\" on it",
1642 "This is some text with 'X' on it",
1643 "This is some text with 'X' on it",
1644 "This is some text with :X: on it",
1646 "This text ends with X",
1648 "This is some text with X) on it",
1649 "This is some text with X--- on it",
1650 "This is some text with X\" on it",
1651 "This is some text with X' on it",
1652 "This is some text with X: on it",
1654 "This is some text with (X on it",
1655 "This is some text with \rX on it",
1656 "This is some text with ---X on it",
1657 "This is some text with \"X on it",
1658 "This is some text with 'X on it",
1659 "This is some text with :X on it",
1661 /* None of these should cause the URL to be detected */
1662 const char * templates_non_delim
[] = {
1663 "This is some text with |X| on it",
1664 "This is some text with *X* on it",
1665 "This is some text with /X/ on it",
1666 "This is some text with +X+ on it",
1667 "This is some text with %X% on it",
1668 "This is some text with #X# on it",
1669 "This is some text with @X@ on it",
1670 "This is some text with \\X\\ on it",
1671 "This is some text with |X on it",
1672 "This is some text with *X on it",
1673 "This is some text with /X on it",
1674 "This is some text with +X on it",
1675 "This is some text with %X on it",
1676 "This is some text with #X on it",
1677 "This is some text with @X on it",
1678 "This is some text with \\X on it",
1680 /* All of these cause the URL detection to be extended by one more byte,
1681 thus demonstrating that the tested character is considered as part
1683 const char * templates_xten_delim
[] = {
1684 "This is some text with X| on it",
1685 "This is some text with X* on it",
1686 "This is some text with X/ on it",
1687 "This is some text with X+ on it",
1688 "This is some text with X% on it",
1689 "This is some text with X# on it",
1690 "This is some text with X@ on it",
1691 "This is some text with X\\ on it",
1695 parent
= new_static_wnd(NULL
);
1696 hwndRichEdit
= new_richedit(parent
);
1697 /* Try and pass EM_AUTOURLDETECT some test wParam values */
1698 urlRet
=SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, FALSE
, 0);
1699 ok(urlRet
==0, "Good wParam: urlRet is: %d\n", urlRet
);
1700 urlRet
=SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, 1, 0);
1701 ok(urlRet
==0, "Good wParam2: urlRet is: %d\n", urlRet
);
1702 /* Windows returns -2147024809 (0x80070057) on bad wParam values */
1703 urlRet
=SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, 8, 0);
1704 ok(urlRet
==E_INVALIDARG
, "Bad wParam: urlRet is: %d\n", urlRet
);
1705 urlRet
=SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, (WPARAM
)"h", (LPARAM
)"h");
1706 ok(urlRet
==E_INVALIDARG
, "Bad wParam2: urlRet is: %d\n", urlRet
);
1707 /* for each url, check the text to see if CFE_LINK effect is present */
1708 for (i
= 0; i
< sizeof(urls
)/sizeof(struct urls_s
); i
++) {
1710 SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, FALSE
, 0);
1711 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) urls
[i
].text
);
1712 check_CFE_LINK_rcvd(hwndRichEdit
, 0, urls
[i
].text
);
1714 /* Link detection should happen immediately upon WM_SETTEXT */
1715 SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1716 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) urls
[i
].text
);
1717 check_CFE_LINK_rcvd(hwndRichEdit
, urls
[i
].is_url
, urls
[i
].text
);
1719 DestroyWindow(hwndRichEdit
);
1721 /* Test detection of URLs within normal text - WM_SETTEXT case. */
1722 for (i
= 0; i
< sizeof(urls
)/sizeof(struct urls_s
); i
++) {
1723 hwndRichEdit
= new_richedit(parent
);
1725 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
1730 at_pos
= strchr(templates_delim
[j
], 'X');
1731 at_offset
= at_pos
- templates_delim
[j
];
1732 strncpy(buffer
, templates_delim
[j
], at_offset
);
1733 buffer
[at_offset
] = '\0';
1734 strcat(buffer
, urls
[i
].text
);
1735 strcat(buffer
, templates_delim
[j
] + at_offset
+ 1);
1736 end_offset
= at_offset
+ strlen(urls
[i
].text
);
1738 SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1739 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) buffer
);
1741 /* This assumes no templates start with the URL itself, and that they
1742 have at least two characters before the URL text */
1743 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1744 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1745 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1746 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1747 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1748 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
1752 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1753 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
1754 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1755 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1759 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1760 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
1761 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1762 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1764 if (buffer
[end_offset
] != '\0')
1766 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1767 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
1768 if (buffer
[end_offset
+1] != '\0')
1770 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
1771 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
1776 for (j
= 0; j
< sizeof(templates_non_delim
) / sizeof(const char *); j
++) {
1781 at_pos
= strchr(templates_non_delim
[j
], 'X');
1782 at_offset
= at_pos
- templates_non_delim
[j
];
1783 strncpy(buffer
, templates_non_delim
[j
], at_offset
);
1784 buffer
[at_offset
] = '\0';
1785 strcat(buffer
, urls
[i
].text
);
1786 strcat(buffer
, templates_non_delim
[j
] + at_offset
+ 1);
1787 end_offset
= at_offset
+ strlen(urls
[i
].text
);
1789 SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1790 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) buffer
);
1792 /* This assumes no templates start with the URL itself, and that they
1793 have at least two characters before the URL text */
1794 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1795 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1796 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1797 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1798 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1799 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
1801 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1802 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
1803 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1804 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1805 if (buffer
[end_offset
] != '\0')
1807 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1808 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
1809 if (buffer
[end_offset
+1] != '\0')
1811 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
1812 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
1817 for (j
= 0; j
< sizeof(templates_xten_delim
) / sizeof(const char *); j
++) {
1822 at_pos
= strchr(templates_xten_delim
[j
], 'X');
1823 at_offset
= at_pos
- templates_xten_delim
[j
];
1824 strncpy(buffer
, templates_xten_delim
[j
], at_offset
);
1825 buffer
[at_offset
] = '\0';
1826 strcat(buffer
, urls
[i
].text
);
1827 strcat(buffer
, templates_xten_delim
[j
] + at_offset
+ 1);
1828 end_offset
= at_offset
+ strlen(urls
[i
].text
);
1830 SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1831 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) buffer
);
1833 /* This assumes no templates start with the URL itself, and that they
1834 have at least two characters before the URL text */
1835 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1836 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1837 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1838 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1839 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1840 "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 not 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 not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1848 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1849 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
, end_offset
+1, buffer
);
1853 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1854 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
1855 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1856 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1857 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1858 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+1, buffer
);
1860 if (buffer
[end_offset
+1] != '\0')
1862 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
1863 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+ 2, buffer
);
1864 if (buffer
[end_offset
+2] != '\0')
1866 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+2, end_offset
+3),
1867 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+2, end_offset
+3, buffer
);
1872 DestroyWindow(hwndRichEdit
);
1873 hwndRichEdit
= NULL
;
1876 /* Test detection of URLs within normal text - WM_CHAR case. */
1877 /* Test only the first two URL examples for brevity */
1878 for (i
= 0; i
< 2; i
++) {
1879 hwndRichEdit
= new_richedit(parent
);
1881 /* Also for brevity, test only the first three delimiters */
1882 for (j
= 0; j
< 3; j
++) {
1888 at_pos
= strchr(templates_delim
[j
], 'X');
1889 at_offset
= at_pos
- templates_delim
[j
];
1890 end_offset
= at_offset
+ strlen(urls
[i
].text
);
1892 SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
1893 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
1894 for (u
= 0; templates_delim
[j
][u
]; u
++) {
1895 if (templates_delim
[j
][u
] == '\r') {
1896 simulate_typing_characters(hwndRichEdit
, "\r");
1897 } else if (templates_delim
[j
][u
] != 'X') {
1898 SendMessage(hwndRichEdit
, WM_CHAR
, templates_delim
[j
][u
], 1);
1900 for (v
= 0; urls
[i
].text
[v
]; v
++) {
1901 SendMessage(hwndRichEdit
, WM_CHAR
, urls
[i
].text
[v
], 1);
1905 SendMessage(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
1907 /* This assumes no templates start with the URL itself, and that they
1908 have at least two characters before the URL text */
1909 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1910 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1911 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1912 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1913 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1914 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
1918 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1919 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
1920 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1921 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1925 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1926 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
1927 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1928 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1930 if (buffer
[end_offset
] != '\0')
1932 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
1933 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
1934 if (buffer
[end_offset
+1] != '\0')
1936 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
1937 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
1941 /* The following will insert a paragraph break after the first character
1942 of the URL candidate, thus breaking the URL. It is expected that the
1943 CFE_LINK attribute should break across both pieces of the URL */
1944 SendMessage(hwndRichEdit
, EM_SETSEL
, at_offset
+1, at_offset
+1);
1945 simulate_typing_characters(hwndRichEdit
, "\r");
1946 SendMessage(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
1948 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1949 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1950 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1951 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1952 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1953 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
1955 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1956 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
1957 /* end_offset moved because of paragraph break */
1958 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1959 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+1, buffer
);
1960 ok(buffer
[end_offset
], "buffer \"%s\" ended prematurely. Is it missing a newline character?\n", buffer
);
1961 if (buffer
[end_offset
] != 0 && buffer
[end_offset
+1] != '\0')
1963 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
1964 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
1965 if (buffer
[end_offset
+2] != '\0')
1967 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+2, end_offset
+3),
1968 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+2, end_offset
+3, buffer
);
1972 /* The following will remove the just-inserted paragraph break, thus
1973 restoring the URL */
1974 SendMessage(hwndRichEdit
, EM_SETSEL
, at_offset
+2, at_offset
+2);
1975 simulate_typing_characters(hwndRichEdit
, "\b");
1976 SendMessage(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
1978 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
1979 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
1980 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
1981 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
1982 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
1983 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
1987 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1988 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
1989 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1990 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1994 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
1995 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
1996 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
1997 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
1999 if (buffer
[end_offset
] != '\0')
2001 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2002 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2003 if (buffer
[end_offset
+1] != '\0')
2005 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2006 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2010 DestroyWindow(hwndRichEdit
);
2011 hwndRichEdit
= NULL
;
2014 /* Test detection of URLs within normal text - EM_SETTEXTEX case. */
2015 /* Test just the first two URL examples for brevity */
2016 for (i
= 0; i
< 2; i
++) {
2019 hwndRichEdit
= new_richedit(parent
);
2021 /* There are at least three ways in which EM_SETTEXTEX must cause URLs to
2023 1) Set entire text, a la WM_SETTEXT
2024 2) Set a selection of the text to the URL
2025 3) Set a portion of the text at a time, which eventually results in
2027 All of them should give equivalent results
2030 /* Set entire text in one go, like WM_SETTEXT */
2031 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2036 st
.codepage
= CP_ACP
;
2037 st
.flags
= ST_DEFAULT
;
2039 at_pos
= strchr(templates_delim
[j
], 'X');
2040 at_offset
= at_pos
- templates_delim
[j
];
2041 strncpy(buffer
, templates_delim
[j
], at_offset
);
2042 buffer
[at_offset
] = '\0';
2043 strcat(buffer
, urls
[i
].text
);
2044 strcat(buffer
, templates_delim
[j
] + at_offset
+ 1);
2045 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2047 SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2048 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
) buffer
);
2050 /* This assumes no templates start with the URL itself, and that they
2051 have at least two characters before the URL text */
2052 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2053 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2054 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2055 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2056 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2057 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2061 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2062 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2063 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2064 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2068 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2069 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2070 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2071 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2073 if (buffer
[end_offset
] != '\0')
2075 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2076 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2077 if (buffer
[end_offset
+1] != '\0')
2079 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2080 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2085 /* Set selection with X to the URL */
2086 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2091 at_pos
= strchr(templates_delim
[j
], 'X');
2092 at_offset
= at_pos
- templates_delim
[j
];
2093 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2095 st
.codepage
= CP_ACP
;
2096 st
.flags
= ST_DEFAULT
;
2097 SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2098 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
) templates_delim
[j
]);
2099 st
.flags
= ST_SELECTION
;
2100 SendMessage(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2101 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
) urls
[i
].text
);
2102 SendMessage(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2104 /* This assumes no templates start with the URL itself, and that they
2105 have at least two characters before the URL text */
2106 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2107 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2108 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2109 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2110 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2111 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2115 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2116 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2117 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2118 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2122 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2123 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2124 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2125 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2127 if (buffer
[end_offset
] != '\0')
2129 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2130 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2131 if (buffer
[end_offset
+1] != '\0')
2133 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2134 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2139 /* Set selection with X to the first character of the URL, then the rest */
2140 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2145 at_pos
= strchr(templates_delim
[j
], 'X');
2146 at_offset
= at_pos
- templates_delim
[j
];
2147 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2149 strcpy(buffer
, "YY");
2150 buffer
[0] = urls
[i
].text
[0];
2152 st
.codepage
= CP_ACP
;
2153 st
.flags
= ST_DEFAULT
;
2154 SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2155 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
) templates_delim
[j
]);
2156 st
.flags
= ST_SELECTION
;
2157 SendMessage(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2158 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
) buffer
);
2159 SendMessage(hwndRichEdit
, EM_SETSEL
, at_offset
+1, at_offset
+2);
2160 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&st
, (LPARAM
)(urls
[i
].text
+ 1));
2161 SendMessage(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2163 /* This assumes no templates start with the URL itself, and that they
2164 have at least two characters before the URL text */
2165 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2166 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2167 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2168 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2169 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2170 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2174 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2175 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2176 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2177 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2181 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2182 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2183 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2184 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2186 if (buffer
[end_offset
] != '\0')
2188 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2189 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2190 if (buffer
[end_offset
+1] != '\0')
2192 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2193 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2198 DestroyWindow(hwndRichEdit
);
2199 hwndRichEdit
= NULL
;
2202 /* Test detection of URLs within normal text - EM_REPLACESEL case. */
2203 /* Test just the first two URL examples for brevity */
2204 for (i
= 0; i
< 2; i
++) {
2205 hwndRichEdit
= new_richedit(parent
);
2207 /* Set selection with X to the URL */
2208 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2213 at_pos
= strchr(templates_delim
[j
], 'X');
2214 at_offset
= at_pos
- templates_delim
[j
];
2215 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2217 SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2218 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) templates_delim
[j
]);
2219 SendMessage(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2220 SendMessage(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
) urls
[i
].text
);
2221 SendMessage(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2223 /* This assumes no templates start with the URL itself, and that they
2224 have at least two characters before the URL text */
2225 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2226 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2227 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2228 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2229 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2230 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2234 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2235 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2236 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2237 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2241 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2242 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2243 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2244 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2246 if (buffer
[end_offset
] != '\0')
2248 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2249 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2250 if (buffer
[end_offset
+1] != '\0')
2252 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2253 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2258 /* Set selection with X to the first character of the URL, then the rest */
2259 for (j
= 0; j
< sizeof(templates_delim
) / sizeof(const char *); j
++) {
2264 at_pos
= strchr(templates_delim
[j
], 'X');
2265 at_offset
= at_pos
- templates_delim
[j
];
2266 end_offset
= at_offset
+ strlen(urls
[i
].text
);
2268 strcpy(buffer
, "YY");
2269 buffer
[0] = urls
[i
].text
[0];
2271 SendMessage(hwndRichEdit
, EM_AUTOURLDETECT
, TRUE
, 0);
2272 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) templates_delim
[j
]);
2273 SendMessage(hwndRichEdit
, EM_SETSEL
, at_offset
, at_offset
+1);
2274 SendMessage(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
) buffer
);
2275 SendMessage(hwndRichEdit
, EM_SETSEL
, at_offset
+1, at_offset
+2);
2276 SendMessage(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
)(urls
[i
].text
+ 1));
2277 SendMessage(hwndRichEdit
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
2279 /* This assumes no templates start with the URL itself, and that they
2280 have at least two characters before the URL text */
2281 ok(!check_CFE_LINK_selection(hwndRichEdit
, 0, 1),
2282 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer
);
2283 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-2, at_offset
-1),
2284 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-2, at_offset
-1, buffer
);
2285 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
-1, at_offset
),
2286 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
-1, at_offset
, buffer
);
2290 ok(check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2291 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset
, at_offset
+1, buffer
);
2292 ok(check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2293 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2297 ok(!check_CFE_LINK_selection(hwndRichEdit
, at_offset
, at_offset
+1),
2298 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset
, at_offset
+ 1, buffer
);
2299 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
-1, end_offset
),
2300 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
-1, end_offset
, buffer
);
2302 if (buffer
[end_offset
] != '\0')
2304 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
, end_offset
+1),
2305 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
, end_offset
+ 1, buffer
);
2306 if (buffer
[end_offset
+1] != '\0')
2308 ok(!check_CFE_LINK_selection(hwndRichEdit
, end_offset
+1, end_offset
+2),
2309 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset
+1, end_offset
+2, buffer
);
2314 DestroyWindow(hwndRichEdit
);
2315 hwndRichEdit
= NULL
;
2318 DestroyWindow(parent
);
2321 static void test_EM_SCROLL(void)
2324 int r
; /* return value */
2325 int expr
; /* expected return value */
2326 HWND hwndRichEdit
= new_richedit(NULL
);
2327 int y_before
, y_after
; /* units of lines of text */
2329 /* test a richedit box containing a single line of text */
2330 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "a");/* one line of text */
2332 for (i
= 0; i
< 4; i
++) {
2333 static const int cmd
[4] = { SB_PAGEDOWN
, SB_PAGEUP
, SB_LINEDOWN
, SB_LINEUP
};
2335 r
= SendMessage(hwndRichEdit
, EM_SCROLL
, cmd
[i
], 0);
2336 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2337 ok(expr
== r
, "EM_SCROLL improper return value returned (i == %d). "
2338 "Got 0x%08x, expected 0x%08x\n", i
, r
, expr
);
2339 ok(y_after
== 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 "
2340 "(i == %d)\n", y_after
, i
);
2344 * test a richedit box that will scroll. There are two general
2345 * cases: the case without any long lines and the case with a long
2348 for (i
= 0; i
< 2; i
++) { /* iterate through different bodies of text */
2350 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "a\nb\nc\nd\ne");
2352 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)
2353 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
2354 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
2355 "LONG LINE \nb\nc\nd\ne");
2356 for (j
= 0; j
< 12; j
++) /* reset scroll position to top */
2357 SendMessage(hwndRichEdit
, EM_SCROLL
, SB_PAGEUP
, 0);
2359 /* get first visible line */
2360 y_before
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2361 r
= SendMessage(hwndRichEdit
, EM_SCROLL
, SB_PAGEDOWN
, 0); /* page down */
2363 /* get new current first visible line */
2364 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2366 ok(((r
& 0xffffff00) == 0x00010000) &&
2367 ((r
& 0x000000ff) != 0x00000000),
2368 "EM_SCROLL page down didn't scroll by a small positive number of "
2369 "lines (r == 0x%08x)\n", r
);
2370 ok(y_after
> y_before
, "EM_SCROLL page down not functioning "
2371 "(line %d scrolled to line %d\n", y_before
, y_after
);
2375 r
= SendMessage(hwndRichEdit
, EM_SCROLL
, SB_PAGEUP
, 0); /* page up */
2376 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2377 ok(((r
& 0xffffff00) == 0x0001ff00),
2378 "EM_SCROLL page up didn't scroll by a small negative number of lines "
2379 "(r == 0x%08x)\n", r
);
2380 ok(y_after
< y_before
, "EM_SCROLL page up not functioning (line "
2381 "%d scrolled to line %d\n", y_before
, y_after
);
2385 r
= SendMessage(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0); /* line down */
2387 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2389 ok(r
== 0x00010001, "EM_SCROLL line down didn't scroll by one line "
2390 "(r == 0x%08x)\n", r
);
2391 ok(y_after
-1 == y_before
, "EM_SCROLL line down didn't go down by "
2392 "1 line (%d scrolled to %d)\n", y_before
, y_after
);
2396 r
= SendMessage(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0); /* line up */
2398 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2400 ok(r
== 0x0001ffff, "EM_SCROLL line up didn't scroll by one line "
2401 "(r == 0x%08x)\n", r
);
2402 ok(y_after
+1 == y_before
, "EM_SCROLL line up didn't go up by 1 "
2403 "line (%d scrolled to %d)\n", y_before
, y_after
);
2407 r
= SendMessage(hwndRichEdit
, EM_SCROLL
,
2408 SB_LINEUP
, 0); /* lineup beyond top */
2410 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2413 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r
);
2414 ok(y_before
== y_after
,
2415 "EM_SCROLL line up beyond top worked (%d)\n", y_after
);
2419 r
= SendMessage(hwndRichEdit
, EM_SCROLL
,
2420 SB_PAGEUP
, 0);/*page up beyond top */
2422 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2425 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r
);
2426 ok(y_before
== y_after
,
2427 "EM_SCROLL page up beyond top worked (%d)\n", y_after
);
2429 for (j
= 0; j
< 12; j
++) /* page down all the way to the bottom */
2430 SendMessage(hwndRichEdit
, EM_SCROLL
, SB_PAGEDOWN
, 0);
2431 y_before
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2432 r
= SendMessage(hwndRichEdit
, EM_SCROLL
,
2433 SB_PAGEDOWN
, 0); /* page down beyond bot */
2434 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2437 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r
);
2438 ok(y_before
== y_after
,
2439 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n",
2442 y_before
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2443 r
= SendMessage(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0); /* line down beyond bot */
2444 y_after
= SendMessage(hwndRichEdit
, EM_GETFIRSTVISIBLELINE
, 0, 0);
2447 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r
);
2448 ok(y_before
== y_after
,
2449 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n",
2452 DestroyWindow(hwndRichEdit
);
2455 static unsigned int recursionLevel
= 0;
2456 static unsigned int WM_SIZE_recursionLevel
= 0;
2457 static BOOL bailedOutOfRecursion
= FALSE
;
2458 static LRESULT (WINAPI
*richeditProc
)(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
);
2460 static LRESULT WINAPI
RicheditStupidOverrideProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
2464 if (bailedOutOfRecursion
) return 0;
2465 if (recursionLevel
>= 32) {
2466 bailedOutOfRecursion
= TRUE
;
2473 WM_SIZE_recursionLevel
++;
2474 r
= richeditProc(hwnd
, message
, wParam
, lParam
);
2475 /* Because, uhhhh... I never heard of ES_DISABLENOSCROLL */
2476 ShowScrollBar(hwnd
, SB_VERT
, TRUE
);
2477 WM_SIZE_recursionLevel
--;
2480 r
= richeditProc(hwnd
, message
, wParam
, lParam
);
2487 static void test_scrollbar_visibility(void)
2490 const char * text
="a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n";
2495 /* These tests show that richedit should temporarily refrain from automatically
2496 hiding or showing its scrollbars (vertical at least) when an explicit request
2497 is made via ShowScrollBar() or similar, outside of standard richedit logic.
2498 Some applications depend on forced showing (when otherwise richedit would
2499 hide the vertical scrollbar) and are thrown on an endless recursive loop
2500 if richedit auto-hides the scrollbar again. Apparently they never heard of
2501 the ES_DISABLENOSCROLL style... */
2503 hwndRichEdit
= new_richedit(NULL
);
2505 /* Test default scrollbar visibility behavior */
2506 memset(&si
, 0, sizeof(si
));
2507 si
.cbSize
= sizeof(si
);
2508 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2509 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2510 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2511 "Vertical scrollbar is visible, should be invisible.\n");
2512 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2513 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2514 si
.nPage
, si
.nMin
, si
.nMax
);
2516 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2517 memset(&si
, 0, sizeof(si
));
2518 si
.cbSize
= sizeof(si
);
2519 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2520 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2521 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2522 "Vertical scrollbar is visible, should be invisible.\n");
2523 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2524 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2525 si
.nPage
, si
.nMin
, si
.nMax
);
2527 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2528 memset(&si
, 0, sizeof(si
));
2529 si
.cbSize
= sizeof(si
);
2530 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2531 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2532 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2533 "Vertical scrollbar is invisible, should be visible.\n");
2534 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2535 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2536 si
.nPage
, si
.nMin
, si
.nMax
);
2538 /* Oddly, setting text to NULL does *not* reset the scrollbar range,
2539 even though it hides the scrollbar */
2540 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2541 memset(&si
, 0, sizeof(si
));
2542 si
.cbSize
= sizeof(si
);
2543 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2544 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2545 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2546 "Vertical scrollbar is visible, should be invisible.\n");
2547 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2548 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2549 si
.nPage
, si
.nMin
, si
.nMax
);
2551 /* Setting non-scrolling text again does *not* reset scrollbar range */
2552 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2553 memset(&si
, 0, sizeof(si
));
2554 si
.cbSize
= sizeof(si
);
2555 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2556 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2557 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2558 "Vertical scrollbar is visible, should be invisible.\n");
2559 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2560 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2561 si
.nPage
, si
.nMin
, si
.nMax
);
2563 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2564 memset(&si
, 0, sizeof(si
));
2565 si
.cbSize
= sizeof(si
);
2566 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2567 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2568 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2569 "Vertical scrollbar is visible, should be invisible.\n");
2570 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2571 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2572 si
.nPage
, si
.nMin
, si
.nMax
);
2574 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2575 memset(&si
, 0, sizeof(si
));
2576 si
.cbSize
= sizeof(si
);
2577 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2578 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2579 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2580 "Vertical scrollbar is visible, should be invisible.\n");
2581 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2582 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2583 si
.nPage
, si
.nMin
, si
.nMax
);
2585 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
2586 memset(&si
, 0, sizeof(si
));
2587 si
.cbSize
= sizeof(si
);
2588 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2589 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2590 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2591 "Vertical scrollbar is visible, should be invisible.\n");
2592 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2593 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2594 si
.nPage
, si
.nMin
, si
.nMax
);
2596 DestroyWindow(hwndRichEdit
);
2598 /* Test again, with ES_DISABLENOSCROLL style */
2599 hwndRichEdit
= new_window(RICHEDIT_CLASS
, ES_MULTILINE
|ES_DISABLENOSCROLL
, NULL
);
2601 /* Test default scrollbar visibility behavior */
2602 memset(&si
, 0, sizeof(si
));
2603 si
.cbSize
= sizeof(si
);
2604 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2605 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2606 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2607 "Vertical scrollbar is invisible, should be visible.\n");
2608 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 1,
2609 "reported page/range is %d (%d..%d) expected 0 (0..1)\n",
2610 si
.nPage
, si
.nMin
, si
.nMax
);
2612 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2613 memset(&si
, 0, sizeof(si
));
2614 si
.cbSize
= sizeof(si
);
2615 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2616 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2617 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2618 "Vertical scrollbar is invisible, should be visible.\n");
2619 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 1,
2620 "reported page/range is %d (%d..%d) expected 0 (0..1)\n",
2621 si
.nPage
, si
.nMin
, si
.nMax
);
2623 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2624 memset(&si
, 0, sizeof(si
));
2625 si
.cbSize
= sizeof(si
);
2626 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2627 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2628 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2629 "Vertical scrollbar is invisible, should be visible.\n");
2630 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2631 "reported page/range is %d (%d..%d)\n",
2632 si
.nPage
, si
.nMin
, si
.nMax
);
2634 /* Oddly, setting text to NULL does *not* reset the scrollbar range */
2635 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2636 memset(&si
, 0, sizeof(si
));
2637 si
.cbSize
= sizeof(si
);
2638 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2639 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2640 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2641 "Vertical scrollbar is invisible, should be visible.\n");
2642 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2643 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2644 si
.nPage
, si
.nMin
, si
.nMax
);
2646 /* Setting non-scrolling text again does *not* reset scrollbar range */
2647 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2648 memset(&si
, 0, sizeof(si
));
2649 si
.cbSize
= sizeof(si
);
2650 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2651 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2652 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2653 "Vertical scrollbar is invisible, should be visible.\n");
2654 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2655 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2656 si
.nPage
, si
.nMin
, si
.nMax
);
2658 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2659 memset(&si
, 0, sizeof(si
));
2660 si
.cbSize
= sizeof(si
);
2661 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2662 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2663 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2664 "Vertical scrollbar is invisible, should be visible.\n");
2665 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2666 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2667 si
.nPage
, si
.nMin
, si
.nMax
);
2669 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2670 memset(&si
, 0, sizeof(si
));
2671 si
.cbSize
= sizeof(si
);
2672 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2673 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2674 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2675 "Vertical scrollbar is invisible, should be visible.\n");
2676 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2677 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2678 si
.nPage
, si
.nMin
, si
.nMax
);
2680 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"");
2681 memset(&si
, 0, sizeof(si
));
2682 si
.cbSize
= sizeof(si
);
2683 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2684 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2685 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2686 "Vertical scrollbar is invisible, should be visible.\n");
2687 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
> 1,
2688 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2689 si
.nPage
, si
.nMin
, si
.nMax
);
2691 DestroyWindow(hwndRichEdit
);
2693 /* Test behavior with explicit visibility request, using ShowScrollBar() */
2694 hwndRichEdit
= new_richedit(NULL
);
2696 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */
2697 ShowScrollBar(hwndRichEdit
, SB_VERT
, TRUE
);
2698 memset(&si
, 0, sizeof(si
));
2699 si
.cbSize
= sizeof(si
);
2700 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2701 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2702 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2703 "Vertical scrollbar is invisible, should be visible.\n");
2705 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2706 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2707 si
.nPage
, si
.nMin
, si
.nMax
);
2710 /* Ditto, see above */
2711 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2712 memset(&si
, 0, sizeof(si
));
2713 si
.cbSize
= sizeof(si
);
2714 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2715 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2716 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2717 "Vertical scrollbar is invisible, should be visible.\n");
2719 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2720 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2721 si
.nPage
, si
.nMin
, si
.nMax
);
2724 /* Ditto, see above */
2725 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2726 memset(&si
, 0, sizeof(si
));
2727 si
.cbSize
= sizeof(si
);
2728 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2729 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2730 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2731 "Vertical scrollbar is invisible, should be visible.\n");
2733 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2734 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2735 si
.nPage
, si
.nMin
, si
.nMax
);
2738 /* Ditto, see above */
2739 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a\na");
2740 memset(&si
, 0, sizeof(si
));
2741 si
.cbSize
= sizeof(si
);
2742 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2743 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2744 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2745 "Vertical scrollbar is invisible, should be visible.\n");
2747 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2748 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2749 si
.nPage
, si
.nMin
, si
.nMax
);
2752 /* Ditto, see above */
2753 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2754 memset(&si
, 0, sizeof(si
));
2755 si
.cbSize
= sizeof(si
);
2756 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2757 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2758 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2759 "Vertical scrollbar is invisible, should be visible.\n");
2761 ok(si
.nPage
== 0 && si
.nMin
== 0 && si
.nMax
== 100,
2762 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
2763 si
.nPage
, si
.nMin
, si
.nMax
);
2766 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2767 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2768 memset(&si
, 0, sizeof(si
));
2769 si
.cbSize
= sizeof(si
);
2770 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2771 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2772 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2773 "Vertical scrollbar is visible, should be invisible.\n");
2774 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2775 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2776 si
.nPage
, si
.nMin
, si
.nMax
);
2778 DestroyWindow(hwndRichEdit
);
2780 hwndRichEdit
= new_richedit(NULL
);
2782 ShowScrollBar(hwndRichEdit
, SB_VERT
, FALSE
);
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 visible, should be invisible.\n");
2789 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2790 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2791 si
.nPage
, si
.nMin
, si
.nMax
);
2793 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2794 memset(&si
, 0, sizeof(si
));
2795 si
.cbSize
= sizeof(si
);
2796 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2797 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2798 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2799 "Vertical scrollbar is visible, should be invisible.\n");
2800 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2801 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2802 si
.nPage
, si
.nMin
, si
.nMax
);
2804 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2805 memset(&si
, 0, sizeof(si
));
2806 si
.cbSize
= sizeof(si
);
2807 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2808 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2809 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2810 "Vertical scrollbar is visible, should be invisible.\n");
2811 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2812 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2813 si
.nPage
, si
.nMin
, si
.nMax
);
2815 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2816 memset(&si
, 0, sizeof(si
));
2817 si
.cbSize
= sizeof(si
);
2818 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2819 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2820 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2821 "Vertical scrollbar is visible, should be invisible.\n");
2822 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2823 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2824 si
.nPage
, si
.nMin
, si
.nMax
);
2826 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2827 memset(&si
, 0, sizeof(si
));
2828 si
.cbSize
= sizeof(si
);
2829 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2830 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2831 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2832 "Vertical scrollbar is invisible, should be visible.\n");
2833 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2834 "reported page/range is %d (%d..%d)\n",
2835 si
.nPage
, si
.nMin
, si
.nMax
);
2837 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */
2838 ShowScrollBar(hwndRichEdit
, SB_VERT
, FALSE
);
2839 memset(&si
, 0, sizeof(si
));
2840 si
.cbSize
= sizeof(si
);
2841 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2842 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2843 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2844 "Vertical scrollbar is visible, should be invisible.\n");
2845 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2846 "reported page/range is %d (%d..%d)\n",
2847 si
.nPage
, si
.nMin
, si
.nMax
);
2849 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2850 memset(&si
, 0, sizeof(si
));
2851 si
.cbSize
= sizeof(si
);
2852 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2853 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2854 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2855 "Vertical scrollbar is visible, should be invisible.\n");
2856 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2857 "reported page/range is %d (%d..%d)\n",
2858 si
.nPage
, si
.nMin
, si
.nMax
);
2860 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that
2861 EM_SCROLL will make visible any forcefully invisible scrollbar */
2862 SendMessage(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0);
2863 memset(&si
, 0, sizeof(si
));
2864 si
.cbSize
= sizeof(si
);
2865 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2866 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2867 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2868 "Vertical scrollbar is invisible, should be visible.\n");
2869 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2870 "reported page/range is %d (%d..%d)\n",
2871 si
.nPage
, si
.nMin
, si
.nMax
);
2873 ShowScrollBar(hwndRichEdit
, SB_VERT
, FALSE
);
2874 memset(&si
, 0, sizeof(si
));
2875 si
.cbSize
= sizeof(si
);
2876 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2877 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2878 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2879 "Vertical scrollbar is visible, should be invisible.\n");
2880 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2881 "reported page/range is %d (%d..%d)\n",
2882 si
.nPage
, si
.nMin
, si
.nMax
);
2884 /* Again, EM_SCROLL, with SB_LINEUP */
2885 SendMessage(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0);
2886 memset(&si
, 0, sizeof(si
));
2887 si
.cbSize
= sizeof(si
);
2888 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2889 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2890 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2891 "Vertical scrollbar is invisible, should be visible.\n");
2892 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2893 "reported page/range is %d (%d..%d)\n",
2894 si
.nPage
, si
.nMin
, si
.nMax
);
2896 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2897 memset(&si
, 0, sizeof(si
));
2898 si
.cbSize
= sizeof(si
);
2899 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2900 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2901 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2902 "Vertical scrollbar is visible, should be invisible.\n");
2903 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2904 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2905 si
.nPage
, si
.nMin
, si
.nMax
);
2907 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2908 memset(&si
, 0, sizeof(si
));
2909 si
.cbSize
= sizeof(si
);
2910 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2911 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2912 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2913 "Vertical scrollbar is invisible, should be visible.\n");
2914 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2915 "reported page/range is %d (%d..%d)\n",
2916 si
.nPage
, si
.nMin
, si
.nMax
);
2918 DestroyWindow(hwndRichEdit
);
2921 /* Test behavior with explicit visibility request, using SetWindowLong()() */
2922 hwndRichEdit
= new_richedit(NULL
);
2924 #define ENABLE_WS_VSCROLL(hwnd) \
2925 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) | WS_VSCROLL)
2926 #define DISABLE_WS_VSCROLL(hwnd) \
2927 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) & ~WS_VSCROLL)
2929 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */
2930 ENABLE_WS_VSCROLL(hwndRichEdit
);
2931 memset(&si
, 0, sizeof(si
));
2932 si
.cbSize
= sizeof(si
);
2933 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2934 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2935 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2936 "Vertical scrollbar is invisible, should be visible.\n");
2937 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2938 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2939 si
.nPage
, si
.nMin
, si
.nMax
);
2941 /* Ditto, see above */
2942 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2943 memset(&si
, 0, sizeof(si
));
2944 si
.cbSize
= sizeof(si
);
2945 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2946 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2947 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2948 "Vertical scrollbar is invisible, should be visible.\n");
2949 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2950 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2951 si
.nPage
, si
.nMin
, si
.nMax
);
2953 /* Ditto, see above */
2954 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
2955 memset(&si
, 0, sizeof(si
));
2956 si
.cbSize
= sizeof(si
);
2957 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2958 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2959 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2960 "Vertical scrollbar is invisible, should be visible.\n");
2961 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2962 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2963 si
.nPage
, si
.nMin
, si
.nMax
);
2965 /* Ditto, see above */
2966 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a\na");
2967 memset(&si
, 0, sizeof(si
));
2968 si
.cbSize
= sizeof(si
);
2969 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2970 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2971 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2972 "Vertical scrollbar is invisible, should be visible.\n");
2973 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2974 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2975 si
.nPage
, si
.nMin
, si
.nMax
);
2977 /* Ditto, see above */
2978 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2979 memset(&si
, 0, sizeof(si
));
2980 si
.cbSize
= sizeof(si
);
2981 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2982 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2983 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
2984 "Vertical scrollbar is invisible, should be visible.\n");
2985 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
2986 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2987 si
.nPage
, si
.nMin
, si
.nMax
);
2989 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
2990 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
2991 memset(&si
, 0, sizeof(si
));
2992 si
.cbSize
= sizeof(si
);
2993 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
2994 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
2995 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
2996 "Vertical scrollbar is visible, should be invisible.\n");
2997 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
2998 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2999 si
.nPage
, si
.nMin
, si
.nMax
);
3001 DestroyWindow(hwndRichEdit
);
3003 hwndRichEdit
= new_richedit(NULL
);
3005 DISABLE_WS_VSCROLL(hwndRichEdit
);
3006 memset(&si
, 0, sizeof(si
));
3007 si
.cbSize
= sizeof(si
);
3008 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3009 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3010 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3011 "Vertical scrollbar is visible, should be invisible.\n");
3012 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3013 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3014 si
.nPage
, si
.nMin
, si
.nMax
);
3016 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3017 memset(&si
, 0, sizeof(si
));
3018 si
.cbSize
= sizeof(si
);
3019 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3020 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3021 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3022 "Vertical scrollbar is visible, should be invisible.\n");
3023 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3024 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3025 si
.nPage
, si
.nMin
, si
.nMax
);
3027 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
3028 memset(&si
, 0, sizeof(si
));
3029 si
.cbSize
= sizeof(si
);
3030 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3031 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3032 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3033 "Vertical scrollbar is visible, should be invisible.\n");
3034 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3035 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3036 si
.nPage
, si
.nMin
, si
.nMax
);
3038 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3039 memset(&si
, 0, sizeof(si
));
3040 si
.cbSize
= sizeof(si
);
3041 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3042 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3043 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3044 "Vertical scrollbar is visible, should be invisible.\n");
3045 ok(si
.nPage
== 0 && si
.nMin
== 0 && (si
.nMax
== 0 || si
.nMax
== 100),
3046 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3047 si
.nPage
, si
.nMin
, si
.nMax
);
3049 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3050 memset(&si
, 0, sizeof(si
));
3051 si
.cbSize
= sizeof(si
);
3052 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3053 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3054 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3055 "Vertical scrollbar is invisible, should be visible.\n");
3056 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3057 "reported page/range is %d (%d..%d)\n",
3058 si
.nPage
, si
.nMin
, si
.nMax
);
3060 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */
3061 DISABLE_WS_VSCROLL(hwndRichEdit
);
3062 memset(&si
, 0, sizeof(si
));
3063 si
.cbSize
= sizeof(si
);
3064 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3065 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3066 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3067 "Vertical scrollbar is visible, should be invisible.\n");
3068 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3069 "reported page/range is %d (%d..%d)\n",
3070 si
.nPage
, si
.nMin
, si
.nMax
);
3072 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
3073 memset(&si
, 0, sizeof(si
));
3074 si
.cbSize
= sizeof(si
);
3075 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3076 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3077 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3078 "Vertical scrollbar is visible, should be invisible.\n");
3079 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3080 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3081 si
.nPage
, si
.nMin
, si
.nMax
);
3083 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)text
);
3084 memset(&si
, 0, sizeof(si
));
3085 si
.cbSize
= sizeof(si
);
3086 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3087 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3088 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3089 "Vertical scrollbar is invisible, should be visible.\n");
3090 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3091 "reported page/range is %d (%d..%d)\n",
3092 si
.nPage
, si
.nMin
, si
.nMax
);
3094 DISABLE_WS_VSCROLL(hwndRichEdit
);
3095 memset(&si
, 0, sizeof(si
));
3096 si
.cbSize
= sizeof(si
);
3097 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3098 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3099 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3100 "Vertical scrollbar is visible, should be invisible.\n");
3101 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3102 "reported page/range is %d (%d..%d)\n",
3103 si
.nPage
, si
.nMin
, si
.nMax
);
3105 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that
3106 EM_SCROLL will make visible any forcefully invisible scrollbar */
3107 SendMessage(hwndRichEdit
, EM_SCROLL
, SB_LINEDOWN
, 0);
3108 memset(&si
, 0, sizeof(si
));
3109 si
.cbSize
= sizeof(si
);
3110 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3111 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3112 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3113 "Vertical scrollbar is invisible, should be visible.\n");
3114 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3115 "reported page/range is %d (%d..%d)\n",
3116 si
.nPage
, si
.nMin
, si
.nMax
);
3118 DISABLE_WS_VSCROLL(hwndRichEdit
);
3119 memset(&si
, 0, sizeof(si
));
3120 si
.cbSize
= sizeof(si
);
3121 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3122 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3123 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) == 0),
3124 "Vertical scrollbar is visible, should be invisible.\n");
3125 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3126 "reported page/range is %d (%d..%d)\n",
3127 si
.nPage
, si
.nMin
, si
.nMax
);
3129 /* Again, EM_SCROLL, with SB_LINEUP */
3130 SendMessage(hwndRichEdit
, EM_SCROLL
, SB_LINEUP
, 0);
3131 memset(&si
, 0, sizeof(si
));
3132 si
.cbSize
= sizeof(si
);
3133 si
.fMask
= SIF_PAGE
| SIF_RANGE
;
3134 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3135 ok (((GetWindowLongA(hwndRichEdit
, GWL_STYLE
) & WS_VSCROLL
) != 0),
3136 "Vertical scrollbar is invisible, should be visible.\n");
3137 ok(si
.nPage
!= 0 && si
.nMin
== 0 && si
.nMax
!= 0,
3138 "reported page/range is %d (%d..%d)\n",
3139 si
.nPage
, si
.nMin
, si
.nMax
);
3141 DestroyWindow(hwndRichEdit
);
3143 /* This window proc models what is going on with Corman Lisp 3.0.
3144 At WM_SIZE, this proc unconditionally calls ShowScrollBar() to
3145 force the scrollbar into visibility. Recursion should NOT happen
3146 as a result of this action.
3148 r
= GetClassInfoA(NULL
, RICHEDIT_CLASS
, &cls
);
3150 richeditProc
= cls
.lpfnWndProc
;
3151 cls
.lpfnWndProc
= RicheditStupidOverrideProcA
;
3152 cls
.lpszClassName
= "RicheditStupidOverride";
3153 if(!RegisterClassA(&cls
)) assert(0);
3156 WM_SIZE_recursionLevel
= 0;
3157 bailedOutOfRecursion
= FALSE
;
3158 hwndRichEdit
= new_window(cls
.lpszClassName
, ES_MULTILINE
, NULL
);
3159 ok(!bailedOutOfRecursion
,
3160 "WM_SIZE/scrollbar mutual recursion detected, expected none!\n");
3163 WM_SIZE_recursionLevel
= 0;
3164 bailedOutOfRecursion
= FALSE
;
3165 MoveWindow(hwndRichEdit
, 0, 0, 250, 100, TRUE
);
3166 ok(!bailedOutOfRecursion
,
3167 "WM_SIZE/scrollbar mutual recursion detected, expected none!\n");
3169 /* Unblock window in order to process WM_DESTROY */
3171 bailedOutOfRecursion
= FALSE
;
3172 WM_SIZE_recursionLevel
= 0;
3173 DestroyWindow(hwndRichEdit
);
3177 static void test_EM_SETUNDOLIMIT(void)
3179 /* cases we test for:
3180 * default behaviour - limiting at 100 undo's
3181 * undo disabled - setting a limit of 0
3182 * undo limited - undo limit set to some to some number, like 2
3183 * bad input - sending a negative number should default to 100 undo's */
3185 HWND hwndRichEdit
= new_richedit(NULL
);
3190 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "x");
3193 SendMessage(hwndRichEdit
, WM_COPY
, 0, 0);
3194 /*Load "x" into the clipboard. Paste is an easy, undo'able operation.
3195 also, multiple pastes don't combine like WM_CHAR would */
3196 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
3198 /* first case - check the default */
3199 SendMessage(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
3200 for (i
=0; i
<101; i
++) /* Put 101 undo's on the stack */
3201 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
3202 for (i
=0; i
<100; i
++) /* Undo 100 of them */
3203 SendMessage(hwndRichEdit
, WM_UNDO
, 0, 0);
3204 ok(!SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0),
3205 "EM_SETUNDOLIMIT allowed more than a hundred undo's by default.\n");
3207 /* second case - cannot undo */
3208 SendMessage(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0, 0);
3209 SendMessage(hwndRichEdit
, EM_SETUNDOLIMIT
, 0, 0);
3210 SendMessage(hwndRichEdit
,
3211 WM_PASTE
, 0, 0); /* Try to put something in the undo stack */
3212 ok(!SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0),
3213 "EM_SETUNDOLIMIT allowed undo with UNDOLIMIT set to 0\n");
3215 /* third case - set it to an arbitrary number */
3216 SendMessage(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0, 0);
3217 SendMessage(hwndRichEdit
, EM_SETUNDOLIMIT
, 2, 0);
3218 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
3219 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
3220 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
3221 /* If SETUNDOLIMIT is working, there should only be two undo's after this */
3222 ok(SendMessage(hwndRichEdit
, EM_CANUNDO
, 0,0),
3223 "EM_SETUNDOLIMIT didn't allow the first undo with UNDOLIMIT set to 2\n");
3224 SendMessage(hwndRichEdit
, WM_UNDO
, 0, 0);
3225 ok(SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0),
3226 "EM_SETUNDOLIMIT didn't allow a second undo with UNDOLIMIT set to 2\n");
3227 SendMessage(hwndRichEdit
, WM_UNDO
, 0, 0);
3228 ok(!SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0),
3229 "EM_SETUNDOLIMIT allowed a third undo with UNDOLIMIT set to 2\n");
3231 /* fourth case - setting negative numbers should default to 100 undos */
3232 SendMessage(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
3233 result
= SendMessage(hwndRichEdit
, EM_SETUNDOLIMIT
, -1, 0);
3235 "EM_SETUNDOLIMIT returned %d when set to -1, instead of 100\n",result
);
3237 DestroyWindow(hwndRichEdit
);
3240 static void test_ES_PASSWORD(void)
3242 /* This isn't hugely testable, so we're just going to run it through its paces */
3244 HWND hwndRichEdit
= new_richedit(NULL
);
3247 /* First, check the default of a regular control */
3248 result
= SendMessage(hwndRichEdit
, EM_GETPASSWORDCHAR
, 0, 0);
3250 "EM_GETPASSWORDCHAR returned %c by default, instead of NULL\n",result
);
3252 /* Now, set it to something normal */
3253 SendMessage(hwndRichEdit
, EM_SETPASSWORDCHAR
, 'x', 0);
3254 result
= SendMessage(hwndRichEdit
, EM_GETPASSWORDCHAR
, 0, 0);
3256 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result
,result
);
3258 /* Now, set it to something odd */
3259 SendMessage(hwndRichEdit
, EM_SETPASSWORDCHAR
, (WCHAR
)1234, 0);
3260 result
= SendMessage(hwndRichEdit
, EM_GETPASSWORDCHAR
, 0, 0);
3262 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result
,result
);
3263 DestroyWindow(hwndRichEdit
);
3266 static DWORD CALLBACK
test_WM_SETTEXT_esCallback(DWORD_PTR dwCookie
,
3271 char** str
= (char**)dwCookie
;
3274 memcpy(*str
, pbBuff
, *pcb
);
3280 static void test_WM_SETTEXT(void)
3282 HWND hwndRichEdit
= new_richedit(NULL
);
3283 const char * TestItem1
= "TestSomeText";
3284 const char * TestItem2
= "TestSomeText\r";
3285 const char * TestItem2_after
= "TestSomeText\r\n";
3286 const char * TestItem3
= "TestSomeText\rSomeMoreText\r";
3287 const char * TestItem3_after
= "TestSomeText\r\nSomeMoreText\r\n";
3288 const char * TestItem4
= "TestSomeText\n\nTestSomeText";
3289 const char * TestItem4_after
= "TestSomeText\r\n\r\nTestSomeText";
3290 const char * TestItem5
= "TestSomeText\r\r\nTestSomeText";
3291 const char * TestItem5_after
= "TestSomeText TestSomeText";
3292 const char * TestItem6
= "TestSomeText\r\r\n\rTestSomeText";
3293 const char * TestItem6_after
= "TestSomeText \r\nTestSomeText";
3294 const char * TestItem7
= "TestSomeText\r\n\r\r\n\rTestSomeText";
3295 const char * TestItem7_after
= "TestSomeText\r\n \r\nTestSomeText";
3297 const char rtftextA
[] = "{\\rtf sometext}";
3298 const char urtftextA
[] = "{\\urtf sometext}";
3299 const WCHAR rtftextW
[] = {'{','\\','r','t','f',' ','s','o','m','e','t','e','x','t','}',0};
3300 const WCHAR urtftextW
[] = {'{','\\','u','r','t','f',' ','s','o','m','e','t','e','x','t','}',0};
3301 const WCHAR sometextW
[] = {'s','o','m','e','t','e','x','t',0};
3303 char buf
[1024] = {0};
3304 WCHAR bufW
[1024] = {0};
3307 /* This test attempts to show that WM_SETTEXT on a riched20 control causes
3308 any solitary \r to be converted to \r\n on return. Properly paired
3309 \r\n are not affected. It also shows that the special sequence \r\r\n
3310 gets converted to a single space.
3313 #define TEST_SETTEXT(a, b) \
3314 result = SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) a); \
3315 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \
3316 result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buf); \
3317 ok (result == lstrlen(buf), \
3318 "WM_GETTEXT returned %ld instead of expected %u\n", \
3319 result, lstrlen(buf)); \
3320 result = strcmp(b, buf); \
3322 "WM_SETTEXT round trip: strcmp = %ld, text=\"%s\"\n", result, buf);
3324 TEST_SETTEXT(TestItem1
, TestItem1
)
3325 TEST_SETTEXT(TestItem2
, TestItem2_after
)
3326 TEST_SETTEXT(TestItem3
, TestItem3_after
)
3327 TEST_SETTEXT(TestItem3_after
, TestItem3_after
)
3328 TEST_SETTEXT(TestItem4
, TestItem4_after
)
3329 TEST_SETTEXT(TestItem5
, TestItem5_after
)
3330 TEST_SETTEXT(TestItem6
, TestItem6_after
)
3331 TEST_SETTEXT(TestItem7
, TestItem7_after
)
3333 /* The following tests demonstrate that WM_SETTEXT supports RTF strings */
3334 TEST_SETTEXT(rtftextA
, "sometext") /* interpreted as ascii rtf */
3335 TEST_SETTEXT(urtftextA
, "sometext") /* interpreted as ascii rtf */
3336 TEST_SETTEXT(rtftextW
, "{") /* interpreted as ascii text */
3337 TEST_SETTEXT(urtftextW
, "{") /* interpreted as ascii text */
3338 DestroyWindow(hwndRichEdit
);
3341 #define TEST_SETTEXTW(a, b) \
3342 result = SendMessageW(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) a); \
3343 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \
3344 result = SendMessageW(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) bufW); \
3345 ok (result == lstrlenW(bufW), \
3346 "WM_GETTEXT returned %ld instead of expected %u\n", \
3347 result, lstrlenW(bufW)); \
3348 result = lstrcmpW(b, bufW); \
3349 ok(result == 0, "WM_SETTEXT round trip: strcmp = %ld\n", result);
3351 hwndRichEdit
= CreateWindowW(RICHEDIT_CLASS20W
, NULL
,
3352 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
3353 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
3354 ok(hwndRichEdit
!= NULL
, "class: RichEdit20W, error: %d\n", (int) GetLastError());
3355 TEST_SETTEXTW(rtftextA
, sometextW
) /* interpreted as ascii rtf */
3356 TEST_SETTEXTW(urtftextA
, sometextW
) /* interpreted as ascii rtf */
3357 TEST_SETTEXTW(rtftextW
, rtftextW
) /* interpreted as ascii text */
3358 TEST_SETTEXTW(urtftextW
, urtftextW
) /* interpreted as ascii text */
3359 DestroyWindow(hwndRichEdit
);
3360 #undef TEST_SETTEXTW
3363 static void test_EM_STREAMOUT(void)
3365 HWND hwndRichEdit
= new_richedit(NULL
);
3368 char buf
[1024] = {0};
3371 const char * TestItem1
= "TestSomeText";
3372 const char * TestItem2
= "TestSomeText\r";
3373 const char * TestItem3
= "TestSomeText\r\n";
3375 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) TestItem1
);
3377 es
.dwCookie
= (DWORD_PTR
)&p
;
3379 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3380 memset(buf
, 0, sizeof(buf
));
3381 SendMessage(hwndRichEdit
, EM_STREAMOUT
, SF_TEXT
, (LPARAM
)&es
);
3383 ok(r
== 12, "streamed text length is %d, expecting 12\n", r
);
3384 ok(strcmp(buf
, TestItem1
) == 0,
3385 "streamed text different, got %s\n", buf
);
3387 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) TestItem2
);
3389 es
.dwCookie
= (DWORD_PTR
)&p
;
3391 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3392 memset(buf
, 0, sizeof(buf
));
3393 SendMessage(hwndRichEdit
, EM_STREAMOUT
, SF_TEXT
, (LPARAM
)&es
);
3395 /* Here again, \r gets converted to \r\n, like WM_GETTEXT */
3396 ok(r
== 14, "streamed text length is %d, expecting 14\n", r
);
3397 ok(strcmp(buf
, TestItem3
) == 0,
3398 "streamed text different from, got %s\n", buf
);
3399 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) TestItem3
);
3401 es
.dwCookie
= (DWORD_PTR
)&p
;
3403 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3404 memset(buf
, 0, sizeof(buf
));
3405 SendMessage(hwndRichEdit
, EM_STREAMOUT
, SF_TEXT
, (LPARAM
)&es
);
3407 ok(r
== 14, "streamed text length is %d, expecting 14\n", r
);
3408 ok(strcmp(buf
, TestItem3
) == 0,
3409 "streamed text different, got %s\n", buf
);
3411 DestroyWindow(hwndRichEdit
);
3414 static void test_EM_STREAMOUT_FONTTBL(void)
3416 HWND hwndRichEdit
= new_richedit(NULL
);
3418 char buf
[1024] = {0};
3423 const char * TestItem
= "TestSomeText";
3425 /* fills in the richedit control with some text */
3426 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) TestItem
);
3428 /* streams out the text in rtf format */
3430 es
.dwCookie
= (DWORD_PTR
)&p
;
3432 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3433 memset(buf
, 0, sizeof(buf
));
3434 SendMessage(hwndRichEdit
, EM_STREAMOUT
, SF_RTF
, (LPARAM
)&es
);
3436 /* scans for \fonttbl, error if not found */
3437 fontTbl
= strstr(buf
, "\\fonttbl");
3438 ok(fontTbl
!= NULL
, "missing \\fonttbl section\n");
3441 /* scans for terminating closing bracket */
3443 while(*fontTbl
&& brackCount
)
3447 else if(*fontTbl
== '}')
3451 /* checks whether closing bracket is ok */
3452 ok(brackCount
== 0, "missing closing bracket in \\fonttbl block\n");
3455 /* char before closing fonttbl block should be a closed bracket */
3457 ok(*fontTbl
== '}', "spurious character '%02x' before \\fonttbl closing bracket\n", *fontTbl
);
3459 /* char after fonttbl block should be a crlf */
3461 ok(*fontTbl
== 0x0d && *(fontTbl
+1) == 0x0a, "missing crlf after \\fonttbl block\n");
3464 DestroyWindow(hwndRichEdit
);
3468 static void test_EM_SETTEXTEX(void)
3470 HWND hwndRichEdit
, parent
;
3472 int sel_start
, sel_end
;
3475 WCHAR TestItem1
[] = {'T', 'e', 's', 't',
3477 'T', 'e', 'x', 't', 0};
3478 WCHAR TestItem1alt
[] = {'T', 'T', 'e', 's',
3484 WCHAR TestItem1altn
[] = {'T','T','e','s','t','S','o','m','e','T','e','x','t',
3485 '\r','t','S','o','m','e','T','e','x','t',0};
3486 WCHAR TestItem2
[] = {'T', 'e', 's', 't',
3490 const char * TestItem2_after
= "TestSomeText\r\n";
3491 WCHAR TestItem3
[] = {'T', 'e', 's', 't',
3494 '\r','\n','\r','\n', 0};
3495 WCHAR TestItem3alt
[] = {'T', 'e', 's', 't',
3499 WCHAR TestItem3_after
[] = {'T', 'e', 's', 't',
3503 WCHAR TestItem4
[] = {'T', 'e', 's', 't',
3506 '\r','\r','\n','\r',
3508 WCHAR TestItem4_after
[] = {'T', 'e', 's', 't',
3512 #define MAX_BUF_LEN 1024
3513 WCHAR buf
[MAX_BUF_LEN
];
3514 char bufACP
[MAX_BUF_LEN
];
3521 /* Test the scroll position with and without a parent window.
3523 * For some reason the scroll position is 0 after EM_SETTEXTEX
3524 * with the ST_SELECTION flag only when the control has a parent
3525 * window, even though the selection is at the end. */
3527 cls
.lpfnWndProc
= DefWindowProcA
;
3530 cls
.hInstance
= GetModuleHandleA(0);
3532 cls
.hCursor
= LoadCursorA(0, IDC_ARROW
);
3533 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
3534 cls
.lpszMenuName
= NULL
;
3535 cls
.lpszClassName
= "ParentTestClass";
3536 if(!RegisterClassA(&cls
)) assert(0);
3538 parent
= CreateWindow(cls
.lpszClassName
, NULL
, WS_POPUP
|WS_VISIBLE
,
3539 0, 0, 200, 60, NULL
, NULL
, NULL
, NULL
);
3540 ok (parent
!= 0, "Failed to create parent window\n");
3542 hwndRichEdit
= CreateWindowEx(0,
3543 RICHEDIT_CLASS
, NULL
,
3544 ES_MULTILINE
|WS_VSCROLL
|WS_VISIBLE
|WS_CHILD
,
3545 0, 0, 200, 60, parent
, NULL
,
3546 hmoduleRichEdit
, NULL
);
3548 setText
.codepage
= CP_ACP
;
3549 setText
.flags
= ST_SELECTION
;
3550 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
,
3551 (LPARAM
)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
3552 si
.cbSize
= sizeof(si
);
3554 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3555 todo_wine
ok(si
.nPos
== 0, "Position is incorrectly at %d\n", si
.nPos
);
3556 SendMessage(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
3557 ok(sel_start
== 18, "Selection start incorrectly at %d\n", sel_start
);
3558 ok(sel_end
== 18, "Selection end incorrectly at %d\n", sel_end
);
3560 DestroyWindow(parent
);
3562 /* Test without a parent window */
3563 hwndRichEdit
= new_richedit(NULL
);
3564 setText
.codepage
= CP_ACP
;
3565 setText
.flags
= ST_SELECTION
;
3566 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
,
3567 (LPARAM
)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
3568 si
.cbSize
= sizeof(si
);
3570 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3571 ok(si
.nPos
!= 0, "Position is incorrectly at %d\n", si
.nPos
);
3572 SendMessage(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
3573 ok(sel_start
== 18, "Selection start incorrectly at %d\n", sel_start
);
3574 ok(sel_end
== 18, "Selection end incorrectly at %d\n", sel_end
);
3576 /* The scroll position should also be 0 after EM_SETTEXTEX with ST_DEFAULT,
3577 * but this time it is because the selection is at the beginning. */
3578 setText
.codepage
= CP_ACP
;
3579 setText
.flags
= ST_DEFAULT
;
3580 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
,
3581 (LPARAM
)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
3582 si
.cbSize
= sizeof(si
);
3584 GetScrollInfo(hwndRichEdit
, SB_VERT
, &si
);
3585 ok(si
.nPos
== 0, "Position is incorrectly at %d\n", si
.nPos
);
3586 SendMessage(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
3587 ok(sel_start
== 0, "Selection start incorrectly at %d\n", sel_start
);
3588 ok(sel_end
== 0, "Selection end incorrectly at %d\n", sel_end
);
3590 setText
.codepage
= 1200; /* no constant for unicode */
3591 getText
.codepage
= 1200; /* no constant for unicode */
3592 getText
.cb
= MAX_BUF_LEN
;
3593 getText
.flags
= GT_DEFAULT
;
3594 getText
.lpDefaultChar
= NULL
;
3595 getText
.lpUsedDefChar
= NULL
;
3598 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
) TestItem1
);
3599 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buf
);
3600 ok(lstrcmpW(buf
, TestItem1
) == 0,
3601 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
3603 /* Unlike WM_SETTEXT/WM_GETTEXT pair, EM_SETTEXTEX/EM_GETTEXTEX does not
3604 convert \r to \r\n on return: !ST_SELECTION && Unicode && !\rtf
3606 setText
.codepage
= 1200; /* no constant for unicode */
3607 getText
.codepage
= 1200; /* no constant for unicode */
3608 getText
.cb
= MAX_BUF_LEN
;
3609 getText
.flags
= GT_DEFAULT
;
3610 getText
.lpDefaultChar
= NULL
;
3611 getText
.lpUsedDefChar
= NULL
;
3613 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
) TestItem2
);
3614 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buf
);
3615 ok(lstrcmpW(buf
, TestItem2
) == 0,
3616 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
3618 /* However, WM_GETTEXT *does* see \r\n where EM_GETTEXTEX would see \r */
3619 SendMessage(hwndRichEdit
, WM_GETTEXT
, MAX_BUF_LEN
, (LPARAM
)buf
);
3620 ok(strcmp((const char *)buf
, TestItem2_after
) == 0,
3621 "WM_GETTEXT did *not* see \\r converted to \\r\\n pairs.\n");
3623 /* Baseline test for just-enough buffer space for string */
3624 getText
.cb
= (lstrlenW(TestItem2
) + 1) * sizeof(WCHAR
);
3625 getText
.codepage
= 1200; /* no constant for unicode */
3626 getText
.flags
= GT_DEFAULT
;
3627 getText
.lpDefaultChar
= NULL
;
3628 getText
.lpUsedDefChar
= NULL
;
3629 memset(buf
, 0, MAX_BUF_LEN
);
3630 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buf
);
3631 ok(lstrcmpW(buf
, TestItem2
) == 0,
3632 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
3634 /* When there is enough space for one character, but not both, of the CRLF
3635 pair at the end of the string, the CR is not copied at all. That is,
3636 the caller must not see CRLF pairs truncated to CR at the end of the
3639 getText
.cb
= (lstrlenW(TestItem2
) + 1) * sizeof(WCHAR
);
3640 getText
.codepage
= 1200; /* no constant for unicode */
3641 getText
.flags
= GT_USECRLF
; /* <-- asking for CR -> CRLF conversion */
3642 getText
.lpDefaultChar
= NULL
;
3643 getText
.lpUsedDefChar
= NULL
;
3644 memset(buf
, 0, MAX_BUF_LEN
);
3645 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buf
);
3646 ok(lstrcmpW(buf
, TestItem1
) == 0,
3647 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
3650 /* \r\n pairs get changed into \r: !ST_SELECTION && Unicode && !\rtf */
3651 setText
.codepage
= 1200; /* no constant for unicode */
3652 getText
.codepage
= 1200; /* no constant for unicode */
3653 getText
.cb
= MAX_BUF_LEN
;
3654 getText
.flags
= GT_DEFAULT
;
3655 getText
.lpDefaultChar
= NULL
;
3656 getText
.lpUsedDefChar
= NULL
;
3658 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
) TestItem3
);
3659 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buf
);
3660 ok(lstrcmpW(buf
, TestItem3_after
) == 0,
3661 "EM_SETTEXTEX did not convert properly\n");
3663 /* \n also gets changed to \r: !ST_SELECTION && Unicode && !\rtf */
3664 setText
.codepage
= 1200; /* no constant for unicode */
3665 getText
.codepage
= 1200; /* no constant for unicode */
3666 getText
.cb
= MAX_BUF_LEN
;
3667 getText
.flags
= GT_DEFAULT
;
3668 getText
.lpDefaultChar
= NULL
;
3669 getText
.lpUsedDefChar
= NULL
;
3671 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
) TestItem3alt
);
3672 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buf
);
3673 ok(lstrcmpW(buf
, TestItem3_after
) == 0,
3674 "EM_SETTEXTEX did not convert properly\n");
3676 /* \r\r\n gets changed into single space: !ST_SELECTION && Unicode && !\rtf */
3677 setText
.codepage
= 1200; /* no constant for unicode */
3678 getText
.codepage
= 1200; /* no constant for unicode */
3679 getText
.cb
= MAX_BUF_LEN
;
3680 getText
.flags
= GT_DEFAULT
;
3681 getText
.lpDefaultChar
= NULL
;
3682 getText
.lpUsedDefChar
= NULL
;
3684 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
) TestItem4
);
3685 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buf
);
3686 ok(lstrcmpW(buf
, TestItem4_after
) == 0,
3687 "EM_SETTEXTEX did not convert properly\n");
3689 /* !ST_SELECTION && Unicode && !\rtf */
3690 result
= SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, 0);
3691 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buf
);
3694 "EM_SETTEXTEX returned %d, instead of 1\n",result
);
3695 ok(lstrlenW(buf
) == 0,
3696 "EM_SETTEXTEX with NULL lParam should clear rich edit.\n");
3698 /* put some text back: !ST_SELECTION && Unicode && !\rtf */
3700 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
) TestItem1
);
3701 /* select some text */
3704 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
3705 /* replace current selection: ST_SELECTION && Unicode && !\rtf */
3706 setText
.flags
= ST_SELECTION
;
3707 result
= SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, 0);
3709 "EM_SETTEXTEX with NULL lParam to replace selection"
3710 " with no text should return 0. Got %i\n",
3713 /* put some text back: !ST_SELECTION && Unicode && !\rtf */
3715 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
) TestItem1
);
3716 /* select some text */
3719 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
3720 /* replace current selection: ST_SELECTION && Unicode && !\rtf */
3721 setText
.flags
= ST_SELECTION
;
3722 result
= SendMessage(hwndRichEdit
, EM_SETTEXTEX
,
3723 (WPARAM
)&setText
, (LPARAM
) TestItem1
);
3725 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buf
);
3726 ok(result
== lstrlenW(TestItem1
),
3727 "EM_SETTEXTEX with NULL lParam to replace selection"
3728 " with no text should return 0. Got %i\n",
3730 ok(lstrlenW(buf
) == 22,
3731 "EM_SETTEXTEX to replace selection with more text failed: %i.\n",
3734 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings */
3735 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "TestSomeText"); /* TestItem1 */
3737 es
.dwCookie
= (DWORD_PTR
)&p
;
3739 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3740 memset(buf
, 0, sizeof(buf
));
3741 SendMessage(hwndRichEdit
, EM_STREAMOUT
,
3742 (WPARAM
)(SF_RTF
), (LPARAM
)&es
);
3743 trace("EM_STREAMOUT produced:\n%s\n", (char *)buf
);
3745 /* !ST_SELECTION && !Unicode && \rtf */
3746 setText
.codepage
= CP_ACP
;/* EM_STREAMOUT saved as ANSI string */
3747 getText
.codepage
= 1200; /* no constant for unicode */
3748 getText
.cb
= MAX_BUF_LEN
;
3749 getText
.flags
= GT_DEFAULT
;
3750 getText
.lpDefaultChar
= NULL
;
3751 getText
.lpUsedDefChar
= NULL
;
3754 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
) buf
);
3755 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buf
);
3756 ok(lstrcmpW(buf
, TestItem1
) == 0,
3757 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
3759 /* The following test demonstrates that EM_SETTEXTEX treats text as ASCII if it
3760 * starts with ASCII characters "{\rtf" even when the codepage is unicode. */
3761 setText
.codepage
= 1200; /* Lie about code page (actual ASCII) */
3762 getText
.codepage
= CP_ACP
;
3763 getText
.cb
= MAX_BUF_LEN
;
3764 getText
.flags
= GT_DEFAULT
;
3765 getText
.lpDefaultChar
= NULL
;
3766 getText
.lpUsedDefChar
= NULL
;
3768 setText
.flags
= ST_SELECTION
;
3769 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, -1);
3770 result
= SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
) "{\\rtf not unicode}");
3771 todo_wine
ok(result
== 11, "EM_SETTEXTEX incorrectly returned %d\n", result
);
3772 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) bufACP
);
3773 ok(lstrcmpA(bufACP
, "not unicode") == 0, "'%s' != 'not unicode'\n", bufACP
);
3775 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings with a selection */
3776 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "TestSomeText"); /* TestItem1 */
3778 es
.dwCookie
= (DWORD_PTR
)&p
;
3780 es
.pfnCallback
= test_WM_SETTEXT_esCallback
;
3781 memset(buf
, 0, sizeof(buf
));
3782 SendMessage(hwndRichEdit
, EM_STREAMOUT
,
3783 (WPARAM
)(SF_RTF
), (LPARAM
)&es
);
3784 trace("EM_STREAMOUT produced:\n%s\n", (char *)buf
);
3786 /* select some text */
3789 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
3791 /* ST_SELECTION && !Unicode && \rtf */
3792 setText
.codepage
= CP_ACP
;/* EM_STREAMOUT saved as ANSI string */
3793 getText
.codepage
= 1200; /* no constant for unicode */
3794 getText
.cb
= MAX_BUF_LEN
;
3795 getText
.flags
= GT_DEFAULT
;
3796 getText
.lpDefaultChar
= NULL
;
3797 getText
.lpUsedDefChar
= NULL
;
3799 setText
.flags
= ST_SELECTION
;
3800 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
) buf
);
3801 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buf
);
3802 ok_w3("Expected \"%s\" or \"%s\", got \"%s\"\n", TestItem1alt
, TestItem1altn
, buf
);
3804 /* The following test demonstrates that EM_SETTEXTEX replacing a selection */
3805 setText
.codepage
= 1200; /* no constant for unicode */
3806 getText
.codepage
= CP_ACP
;
3807 getText
.cb
= MAX_BUF_LEN
;
3810 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
) TestItem1
); /* TestItem1 */
3811 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) bufACP
);
3813 /* select some text */
3816 SendMessage(hwndRichEdit
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
3818 /* ST_SELECTION && !Unicode && !\rtf */
3819 setText
.codepage
= CP_ACP
;
3820 getText
.codepage
= 1200; /* no constant for unicode */
3821 getText
.cb
= MAX_BUF_LEN
;
3822 getText
.flags
= GT_DEFAULT
;
3823 getText
.lpDefaultChar
= NULL
;
3824 getText
.lpUsedDefChar
= NULL
;
3826 setText
.flags
= ST_SELECTION
;
3827 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
) bufACP
);
3828 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buf
);
3829 ok(lstrcmpW(buf
, TestItem1alt
) == 0,
3830 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX when"
3831 " using ST_SELECTION and non-Unicode\n");
3833 /* Test setting text using rich text format */
3835 setText
.codepage
= CP_ACP
;
3836 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"{\\rtf richtext}");
3837 getText
.codepage
= CP_ACP
;
3838 getText
.cb
= MAX_BUF_LEN
;
3839 getText
.flags
= GT_DEFAULT
;
3840 getText
.lpDefaultChar
= NULL
;
3841 getText
.lpUsedDefChar
= NULL
;
3842 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) bufACP
);
3843 ok(!strcmp(bufACP
, "richtext"), "expected 'richtext' but got '%s'\n", bufACP
);
3846 setText
.codepage
= CP_ACP
;
3847 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)"{\\urtf morerichtext}");
3848 getText
.codepage
= CP_ACP
;
3849 getText
.cb
= MAX_BUF_LEN
;
3850 getText
.flags
= GT_DEFAULT
;
3851 getText
.lpDefaultChar
= NULL
;
3852 getText
.lpUsedDefChar
= NULL
;
3853 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) bufACP
);
3854 ok(!strcmp(bufACP
, "morerichtext"), "expected 'morerichtext' but got '%s'\n", bufACP
);
3856 DestroyWindow(hwndRichEdit
);
3859 static void test_EM_LIMITTEXT(void)
3863 HWND hwndRichEdit
= new_richedit(NULL
);
3865 /* The main purpose of this test is to demonstrate that the nonsense in MSDN
3866 * about setting the length to -1 for multiline edit controls doesn't happen.
3869 /* Don't check default gettextlimit case. That's done in other tests */
3871 /* Set textlimit to 100 */
3872 SendMessage (hwndRichEdit
, EM_LIMITTEXT
, 100, 0);
3873 ret
= SendMessage (hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3875 "EM_LIMITTEXT: set to 100, returned: %d, expected: 100\n", ret
);
3877 /* Set textlimit to 0 */
3878 SendMessage (hwndRichEdit
, EM_LIMITTEXT
, 0, 0);
3879 ret
= SendMessage (hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3881 "EM_LIMITTEXT: set to 0, returned: %d, expected: 65536\n", ret
);
3883 /* Set textlimit to -1 */
3884 SendMessage (hwndRichEdit
, EM_LIMITTEXT
, -1, 0);
3885 ret
= SendMessage (hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3887 "EM_LIMITTEXT: set to -1, returned: %d, expected: -1\n", ret
);
3889 /* Set textlimit to -2 */
3890 SendMessage (hwndRichEdit
, EM_LIMITTEXT
, -2, 0);
3891 ret
= SendMessage (hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3893 "EM_LIMITTEXT: set to -2, returned: %d, expected: -2\n", ret
);
3895 DestroyWindow (hwndRichEdit
);
3899 static void test_EM_EXLIMITTEXT(void)
3901 int i
, selBegin
, selEnd
, len1
, len2
;
3903 char text
[1024 + 1];
3904 char buffer
[1024 + 1];
3905 int textlimit
= 0; /* multiple of 100 */
3906 HWND hwndRichEdit
= new_richedit(NULL
);
3908 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3909 ok(32767 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 32767, i
); /* default */
3912 SendMessage(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
3913 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3915 ok(textlimit
== i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit
, i
);
3918 SendMessage(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
3919 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3921 ok(textlimit
== i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit
, i
);
3923 SendMessage(hwndRichEdit
, EM_EXLIMITTEXT
, 0, 0);
3924 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3925 /* default for WParam = 0 */
3926 ok(65536 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 65536, i
);
3928 textlimit
= sizeof(text
)-1;
3929 memset(text
, 'W', textlimit
);
3930 text
[sizeof(text
)-1] = 0;
3931 SendMessage(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
3932 /* maxed out text */
3933 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
3935 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, -1); /* select everything */
3936 SendMessage(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
3937 len1
= selEnd
- selBegin
;
3939 SendMessage(hwndRichEdit
, WM_KEYDOWN
, VK_BACK
, 1);
3940 SendMessage(hwndRichEdit
, WM_CHAR
, VK_BACK
, 1);
3941 SendMessage(hwndRichEdit
, WM_KEYUP
, VK_BACK
, 1);
3942 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, -1);
3943 SendMessage(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
3944 len2
= selEnd
- selBegin
;
3947 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
3950 SendMessage(hwndRichEdit
, WM_KEYDOWN
, 'A', 1);
3951 SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 1);
3952 SendMessage(hwndRichEdit
, WM_KEYUP
, 'A', 1);
3953 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, -1);
3954 SendMessage(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
3955 len1
= selEnd
- selBegin
;
3958 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
3961 SendMessage(hwndRichEdit
, WM_KEYDOWN
, 'A', 1);
3962 SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 1);
3963 SendMessage(hwndRichEdit
, WM_KEYUP
, 'A', 1); /* full; should be no effect */
3964 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, -1);
3965 SendMessage(hwndRichEdit
, EM_GETSEL
, (WPARAM
)&selBegin
, (LPARAM
)&selEnd
);
3966 len2
= selEnd
- selBegin
;
3969 "EM_EXLIMITTEXT: No Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
3972 /* set text up to the limit, select all the text, then add a char */
3974 memset(text
, 'W', textlimit
);
3975 text
[textlimit
] = 0;
3976 SendMessage(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
3977 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
3978 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, -1);
3979 SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 1);
3980 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
3981 result
= strcmp(buffer
, "A");
3982 ok(0 == result
, "got string = \"%s\"\n", buffer
);
3984 /* WM_SETTEXT not limited */
3986 memset(text
, 'W', textlimit
);
3987 text
[textlimit
] = 0;
3988 SendMessage(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
-5);
3989 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text
);
3990 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
3992 ok(10 == i
, "expected 10 chars\n");
3993 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
3994 ok(10 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i
);
3996 /* try inserting more text at end */
3997 i
= SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 0);
3998 ok(0 == i
, "WM_CHAR wasn't processed\n");
3999 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
4001 ok(10 == i
, "expected 10 chars, got %i\n", i
);
4002 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4003 ok(10 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i
);
4005 /* try inserting text at beginning */
4006 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 0);
4007 i
= SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 0);
4008 ok(0 == i
, "WM_CHAR wasn't processed\n");
4009 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
4011 ok(10 == i
, "expected 10 chars, got %i\n", i
);
4012 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4013 ok(10 == i
, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i
);
4015 /* WM_CHAR is limited */
4017 SendMessage(hwndRichEdit
, EM_EXLIMITTEXT
, 0, textlimit
);
4018 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, -1); /* select everything */
4019 i
= SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 0);
4020 ok(0 == i
, "WM_CHAR wasn't processed\n");
4021 i
= SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 0);
4022 ok(0 == i
, "WM_CHAR wasn't processed\n");
4023 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
4025 ok(1 == i
, "expected 1 chars, got %i instead\n", i
);
4027 DestroyWindow(hwndRichEdit
);
4030 static void test_EM_GETLIMITTEXT(void)
4033 HWND hwndRichEdit
= new_richedit(NULL
);
4035 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4036 ok(32767 == i
, "expected: %d, actual: %d\n", 32767, i
); /* default value */
4038 SendMessage(hwndRichEdit
, EM_EXLIMITTEXT
, 0, 50000);
4039 i
= SendMessage(hwndRichEdit
, EM_GETLIMITTEXT
, 0, 0);
4040 ok(50000 == i
, "expected: %d, actual: %d\n", 50000, i
);
4042 DestroyWindow(hwndRichEdit
);
4045 static void test_WM_SETFONT(void)
4047 /* There is no invalid input or error conditions for this function.
4048 * NULL wParam and lParam just fall back to their default values
4049 * It should be noted that even if you use a gibberish name for your fonts
4050 * here, it will still work because the name is stored. They will display as
4051 * System, but will report their name to be whatever they were created as */
4053 HWND hwndRichEdit
= new_richedit(NULL
);
4054 HFONT testFont1
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4055 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4056 FF_DONTCARE
, "Marlett");
4057 HFONT testFont2
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4058 OUT_TT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4059 FF_DONTCARE
, "MS Sans Serif");
4060 HFONT testFont3
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4061 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4062 FF_DONTCARE
, "Courier");
4063 LOGFONTA sentLogFont
;
4064 CHARFORMAT2A returnedCF2A
;
4066 returnedCF2A
.cbSize
= sizeof(returnedCF2A
);
4068 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "x");
4069 SendMessage(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont1
, MAKELPARAM(TRUE
, 0));
4070 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
) &returnedCF2A
);
4072 GetObjectA(testFont1
, sizeof(LOGFONTA
), &sentLogFont
);
4073 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
4074 "EM_GETCHARFORMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n",
4075 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
4077 SendMessage(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont2
, MAKELPARAM(TRUE
, 0));
4078 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
) &returnedCF2A
);
4079 GetObjectA(testFont2
, sizeof(LOGFONTA
), &sentLogFont
);
4080 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
4081 "EM_GETCHARFORMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n",
4082 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
4084 SendMessage(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont3
, MAKELPARAM(TRUE
, 0));
4085 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
) &returnedCF2A
);
4086 GetObjectA(testFont3
, sizeof(LOGFONTA
), &sentLogFont
);
4087 ok (!strcmp(sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
),
4088 "EM_GETCHARFORMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n",
4089 sentLogFont
.lfFaceName
,returnedCF2A
.szFaceName
);
4091 /* This last test is special since we send in NULL. We clear the variables
4092 * and just compare to "System" instead of the sent in font name. */
4093 ZeroMemory(&returnedCF2A
,sizeof(returnedCF2A
));
4094 ZeroMemory(&sentLogFont
,sizeof(sentLogFont
));
4095 returnedCF2A
.cbSize
= sizeof(returnedCF2A
);
4097 SendMessage(hwndRichEdit
, WM_SETFONT
, 0, MAKELPARAM((WORD
) TRUE
, 0));
4098 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
) &returnedCF2A
);
4099 GetObjectA(NULL
, sizeof(LOGFONTA
), &sentLogFont
);
4100 ok (!strcmp("System",returnedCF2A
.szFaceName
),
4101 "EM_GETCHARFORMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A
.szFaceName
);
4103 DestroyWindow(hwndRichEdit
);
4107 static DWORD CALLBACK
test_EM_GETMODIFY_esCallback(DWORD_PTR dwCookie
,
4112 const char** str
= (const char**)dwCookie
;
4113 int size
= strlen(*str
);
4114 if(size
> 3) /* let's make it piecemeal for fun */
4121 memcpy(pbBuff
, *str
, *pcb
);
4127 static void test_EM_GETMODIFY(void)
4129 HWND hwndRichEdit
= new_richedit(NULL
);
4132 WCHAR TestItem1
[] = {'T', 'e', 's', 't',
4134 'T', 'e', 'x', 't', 0};
4135 WCHAR TestItem2
[] = {'T', 'e', 's', 't',
4137 'O', 't', 'h', 'e', 'r',
4138 'T', 'e', 'x', 't', 0};
4139 const char* streamText
= "hello world";
4144 HFONT testFont
= CreateFontA (0,0,0,0,FW_LIGHT
, 0, 0, 0, ANSI_CHARSET
,
4145 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
|
4146 FF_DONTCARE
, "Courier");
4148 setText
.codepage
= 1200; /* no constant for unicode */
4149 setText
.flags
= ST_KEEPUNDO
;
4152 /* modify flag shouldn't be set when richedit is first created */
4153 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4155 "EM_GETMODIFY returned non-zero, instead of zero on create\n");
4157 /* setting modify flag should actually set it */
4158 SendMessage(hwndRichEdit
, EM_SETMODIFY
, TRUE
, 0);
4159 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4161 "EM_GETMODIFY returned zero, instead of non-zero on EM_SETMODIFY\n");
4163 /* clearing modify flag should actually clear it */
4164 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4165 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4167 "EM_GETMODIFY returned non-zero, instead of zero on EM_SETMODIFY\n");
4169 /* setting font doesn't change modify flag */
4170 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4171 SendMessage(hwndRichEdit
, WM_SETFONT
, (WPARAM
)testFont
, MAKELPARAM(TRUE
, 0));
4172 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4174 "EM_GETMODIFY returned non-zero, instead of zero on setting font\n");
4176 /* setting text should set modify flag */
4177 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4178 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
4179 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4181 "EM_GETMODIFY returned zero, instead of non-zero on setting text\n");
4183 /* undo previous text doesn't reset modify flag */
4184 SendMessage(hwndRichEdit
, WM_UNDO
, 0, 0);
4185 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4187 "EM_GETMODIFY returned zero, instead of non-zero on undo after setting text\n");
4189 /* set text with no flag to keep undo stack should not set modify flag */
4190 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4192 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
4193 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4195 "EM_GETMODIFY returned non-zero, instead of zero when setting text while not keeping undo stack\n");
4197 /* WM_SETTEXT doesn't modify */
4198 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4199 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)TestItem2
);
4200 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4202 "EM_GETMODIFY returned non-zero for WM_SETTEXT\n");
4204 /* clear the text */
4205 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4206 SendMessage(hwndRichEdit
, WM_CLEAR
, 0, 0);
4207 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4209 "EM_GETMODIFY returned non-zero, instead of zero for WM_CLEAR\n");
4212 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4213 SendMessage(hwndRichEdit
, EM_SETTEXTEX
, (WPARAM
)&setText
, (LPARAM
)TestItem1
);
4214 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 2);
4215 SendMessage(hwndRichEdit
, EM_REPLACESEL
, TRUE
, (LPARAM
)TestItem2
);
4216 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4218 "EM_GETMODIFY returned zero, instead of non-zero when replacing text\n");
4220 /* copy/paste text 1 */
4221 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4222 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 2);
4223 SendMessage(hwndRichEdit
, WM_COPY
, 0, 0);
4224 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
4225 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4227 "EM_GETMODIFY returned zero, instead of non-zero when pasting identical text\n");
4229 /* copy/paste text 2 */
4230 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4231 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 2);
4232 SendMessage(hwndRichEdit
, WM_COPY
, 0, 0);
4233 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 3);
4234 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
4235 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4237 "EM_GETMODIFY returned zero, instead of non-zero when pasting different text\n");
4240 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4241 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 1);
4242 SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 0);
4243 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4245 "EM_GETMODIFY returned zero, instead of non-zero for WM_CHAR\n");
4248 SendMessage(hwndRichEdit
, WM_CHAR
, 'A', 0);
4249 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4250 SendMessage(hwndRichEdit
, WM_KEYDOWN
, VK_BACK
, 0);
4251 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4253 "EM_GETMODIFY returned zero, instead of non-zero for backspace\n");
4255 /* set char format */
4256 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4257 cf2
.cbSize
= sizeof(CHARFORMAT2
);
4258 SendMessage(hwndRichEdit
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
4259 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
4260 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
4261 SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
4262 result
= SendMessage(hwndRichEdit
, EM_SETCHARFORMAT
, SCF_ALL
, (LPARAM
)&cf2
);
4263 ok(result
== 1, "EM_SETCHARFORMAT returned %ld instead of 1\n", result
);
4264 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4266 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETCHARFORMAT\n");
4268 /* set para format */
4269 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4270 pf2
.cbSize
= sizeof(PARAFORMAT2
);
4271 SendMessage(hwndRichEdit
, EM_GETPARAFORMAT
, 0,
4273 pf2
.dwMask
= PFM_ALIGNMENT
| pf2
.dwMask
;
4274 pf2
.wAlignment
= PFA_RIGHT
;
4275 SendMessage(hwndRichEdit
, EM_SETPARAFORMAT
, 0, (LPARAM
) &pf2
);
4276 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4278 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETPARAFORMAT\n");
4281 SendMessage(hwndRichEdit
, EM_SETMODIFY
, FALSE
, 0);
4282 es
.dwCookie
= (DWORD_PTR
)&streamText
;
4284 es
.pfnCallback
= test_EM_GETMODIFY_esCallback
;
4285 SendMessage(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
4286 result
= SendMessage(hwndRichEdit
, EM_GETMODIFY
, 0, 0);
4288 "EM_GETMODIFY returned zero, instead of non-zero for EM_STREAM\n");
4290 DestroyWindow(hwndRichEdit
);
4296 LRESULT expected_retval
;
4297 int expected_getsel_start
;
4298 int expected_getsel_end
;
4299 int _getsel_todo_wine
;
4302 const struct exsetsel_s exsetsel_tests
[] = {
4304 {5, 10, 10, 5, 10, 0},
4305 {15, 17, 17, 15, 17, 0},
4306 /* test cpMax > strlen() */
4307 {0, 100, 18, 0, 18, 1},
4308 /* test cpMin == cpMax */
4310 /* test cpMin < 0 && cpMax >= 0 (bug 4462) */
4311 {-1, 0, 5, 5, 5, 0},
4312 {-1, 17, 5, 5, 5, 0},
4313 {-1, 18, 5, 5, 5, 0},
4314 /* test cpMin < 0 && cpMax < 0 */
4315 {-1, -1, 17, 17, 17, 0},
4316 {-4, -5, 17, 17, 17, 0},
4317 /* test cMin >=0 && cpMax < 0 (bug 6814) */
4318 {0, -1, 18, 0, 18, 1},
4319 {17, -5, 18, 17, 18, 1},
4320 {18, -3, 17, 17, 17, 0},
4321 /* test if cpMin > cpMax */
4322 {15, 19, 18, 15, 18, 1},
4323 {19, 15, 18, 15, 18, 1}
4326 static void check_EM_EXSETSEL(HWND hwnd
, const struct exsetsel_s
*setsel
, int id
) {
4331 cr
.cpMin
= setsel
->min
;
4332 cr
.cpMax
= setsel
->max
;
4333 result
= SendMessage(hwnd
, EM_EXSETSEL
, 0, (LPARAM
) &cr
);
4335 ok(result
== setsel
->expected_retval
, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id
, setsel
->expected_retval
, result
);
4337 SendMessage(hwnd
, EM_GETSEL
, (WPARAM
) &start
, (LPARAM
) &end
);
4339 if (setsel
->_getsel_todo_wine
) {
4341 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
);
4344 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
);
4348 static void test_EM_EXSETSEL(void)
4350 HWND hwndRichEdit
= new_richedit(NULL
);
4352 const int num_tests
= sizeof(exsetsel_tests
)/sizeof(struct exsetsel_s
);
4354 /* sending some text to the window */
4355 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "testing selection");
4356 /* 01234567890123456*/
4359 for (i
= 0; i
< num_tests
; i
++) {
4360 check_EM_EXSETSEL(hwndRichEdit
, &exsetsel_tests
[i
], i
);
4363 DestroyWindow(hwndRichEdit
);
4366 static void test_EM_REPLACESEL(int redraw
)
4368 HWND hwndRichEdit
= new_richedit(NULL
);
4369 char buffer
[1024] = {0};
4374 /* sending some text to the window */
4375 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "testing selection");
4376 /* 01234567890123456*/
4379 /* FIXME add more tests */
4380 SendMessage(hwndRichEdit
, EM_SETSEL
, 7, 17);
4381 r
= SendMessage(hwndRichEdit
, EM_REPLACESEL
, 0, 0);
4382 ok(0 == r
, "EM_REPLACESEL returned %d, expected 0\n", r
);
4383 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
4384 r
= strcmp(buffer
, "testing");
4385 ok(0 == r
, "expected %d, got %d\n", 0, r
);
4387 DestroyWindow(hwndRichEdit
);
4389 hwndRichEdit
= new_richedit(NULL
);
4391 trace("Testing EM_REPLACESEL behavior with redraw=%d\n", redraw
);
4392 SendMessage(hwndRichEdit
, WM_SETREDRAW
, redraw
, 0);
4394 /* Test behavior with carriage returns and newlines */
4395 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4396 r
= SendMessage(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
) "RichEdit1");
4397 ok(9 == r
, "EM_REPLACESEL returned %d, expected 9\n", r
);
4398 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
4399 r
= strcmp(buffer
, "RichEdit1");
4400 ok(0 == r
, "expected %d, got %d\n", 0, r
);
4402 getText
.codepage
= CP_ACP
;
4403 getText
.flags
= GT_DEFAULT
;
4404 getText
.lpDefaultChar
= NULL
;
4405 getText
.lpUsedDefChar
= NULL
;
4406 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buffer
);
4407 ok(strcmp(buffer
, "RichEdit1") == 0,
4408 "EM_GETTEXTEX results not what was set by EM_REPLACESEL\n");
4410 /* Test number of lines reported after EM_REPLACESEL */
4411 r
= SendMessage(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4412 ok(r
== 1, "EM_GETLINECOUNT returned %d, expected 1\n", r
);
4414 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4415 r
= SendMessage(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
) "RichEdit1\r");
4416 ok(10 == r
, "EM_REPLACESEL returned %d, expected 10\n", r
);
4417 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
4418 r
= strcmp(buffer
, "RichEdit1\r\n");
4419 ok(0 == r
, "expected %d, got %d\n", 0, r
);
4421 getText
.codepage
= CP_ACP
;
4422 getText
.flags
= GT_DEFAULT
;
4423 getText
.lpDefaultChar
= NULL
;
4424 getText
.lpUsedDefChar
= NULL
;
4425 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buffer
);
4426 ok(strcmp(buffer
, "RichEdit1\r") == 0,
4427 "EM_GETTEXTEX returned incorrect string\n");
4429 /* Test number of lines reported after EM_REPLACESEL */
4430 r
= SendMessage(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4431 ok(r
== 2, "EM_GETLINECOUNT returned %d, expected 2\n", r
);
4433 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4434 r
= SendMessage(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
) "RichEdit1\r\n");
4435 ok(r
== 11, "EM_REPLACESEL returned %d, expected 11\n", r
);
4437 /* Test number of lines reported after EM_REPLACESEL */
4438 r
= SendMessage(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4439 ok(r
== 2, "EM_GETLINECOUNT returned %d, expected 2\n", r
);
4441 r
= SendMessage(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4442 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4443 ok(cr
.cpMin
== 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr
.cpMin
);
4444 ok(cr
.cpMax
== 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr
.cpMax
);
4446 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
4447 r
= strcmp(buffer
, "RichEdit1\r\n");
4448 ok(0 == r
, "expected %d, got %d\n", 0, r
);
4450 getText
.codepage
= CP_ACP
;
4451 getText
.flags
= GT_DEFAULT
;
4452 getText
.lpDefaultChar
= NULL
;
4453 getText
.lpUsedDefChar
= NULL
;
4454 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buffer
);
4455 ok(strcmp(buffer
, "RichEdit1\r") == 0,
4456 "EM_GETTEXTEX returned incorrect string\n");
4458 r
= SendMessage(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4459 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4460 ok(cr
.cpMin
== 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr
.cpMin
);
4461 ok(cr
.cpMax
== 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr
.cpMax
);
4463 /* The following tests show that richedit should handle the special \r\r\n
4464 sequence by turning it into a single space on insertion. However,
4465 EM_REPLACESEL on WinXP returns the number of characters in the original
4469 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4470 r
= SendMessage(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
) "\r\r");
4471 ok(2 == r
, "EM_REPLACESEL returned %d, expected 4\n", r
);
4472 r
= SendMessage(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4473 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4474 ok(cr
.cpMin
== 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr
.cpMin
);
4475 ok(cr
.cpMax
== 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr
.cpMax
);
4477 /* Test the actual string */
4479 getText
.codepage
= CP_ACP
;
4480 getText
.flags
= GT_DEFAULT
;
4481 getText
.lpDefaultChar
= NULL
;
4482 getText
.lpUsedDefChar
= NULL
;
4483 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buffer
);
4484 ok(strcmp(buffer
, "\r\r") == 0,
4485 "EM_GETTEXTEX returned incorrect string\n");
4487 /* Test number of lines reported after EM_REPLACESEL */
4488 r
= SendMessage(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4489 ok(r
== 3, "EM_GETLINECOUNT returned %d, expected 3\n", r
);
4491 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4492 r
= SendMessage(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
) "\r\r\n");
4493 ok(r
== 3, "EM_REPLACESEL returned %d, expected 3\n", r
);
4494 r
= SendMessage(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4495 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4496 ok(cr
.cpMin
== 1, "EM_EXGETSEL returned cpMin=%d, expected 1\n", cr
.cpMin
);
4497 ok(cr
.cpMax
== 1, "EM_EXGETSEL returned cpMax=%d, expected 1\n", cr
.cpMax
);
4499 /* Test the actual string */
4501 getText
.codepage
= CP_ACP
;
4502 getText
.flags
= GT_DEFAULT
;
4503 getText
.lpDefaultChar
= NULL
;
4504 getText
.lpUsedDefChar
= NULL
;
4505 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buffer
);
4506 ok(strcmp(buffer
, " ") == 0,
4507 "EM_GETTEXTEX returned incorrect string\n");
4509 /* Test number of lines reported after EM_REPLACESEL */
4510 r
= SendMessage(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4511 ok(r
== 1, "EM_GETLINECOUNT returned %d, expected 1\n", r
);
4513 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4514 r
= SendMessage(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
) "\r\r\r\r\r\n\r\r\r");
4515 ok(r
== 9, "EM_REPLACESEL returned %d, expected 9\n", r
);
4516 r
= SendMessage(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4517 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4518 ok(cr
.cpMin
== 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr
.cpMin
);
4519 ok(cr
.cpMax
== 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr
.cpMax
);
4521 /* Test the actual string */
4523 getText
.codepage
= CP_ACP
;
4524 getText
.flags
= GT_DEFAULT
;
4525 getText
.lpDefaultChar
= NULL
;
4526 getText
.lpUsedDefChar
= NULL
;
4527 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buffer
);
4528 ok(strcmp(buffer
, "\r\r\r \r\r\r") == 0,
4529 "EM_GETTEXTEX returned incorrect string\n");
4531 /* Test number of lines reported after EM_REPLACESEL */
4532 r
= SendMessage(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4533 ok(r
== 7, "EM_GETLINECOUNT returned %d, expected 7\n", r
);
4535 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4536 r
= SendMessage(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
) "\r\r\n\r\n");
4537 ok(r
== 5, "EM_REPLACESEL returned %d, expected 5\n", r
);
4538 r
= SendMessage(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4539 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4540 ok(cr
.cpMin
== 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr
.cpMin
);
4541 ok(cr
.cpMax
== 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr
.cpMax
);
4543 /* Test the actual string */
4545 getText
.codepage
= CP_ACP
;
4546 getText
.flags
= GT_DEFAULT
;
4547 getText
.lpDefaultChar
= NULL
;
4548 getText
.lpUsedDefChar
= NULL
;
4549 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buffer
);
4550 ok(strcmp(buffer
, " \r") == 0,
4551 "EM_GETTEXTEX returned incorrect string\n");
4553 /* Test number of lines reported after EM_REPLACESEL */
4554 r
= SendMessage(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4555 ok(r
== 2, "EM_GETLINECOUNT returned %d, expected 2\n", r
);
4557 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4558 r
= SendMessage(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
) "\r\r\n\r\r");
4559 ok(r
== 5, "EM_REPLACESEL returned %d, expected 5\n", r
);
4560 r
= SendMessage(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4561 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4562 ok(cr
.cpMin
== 3, "EM_EXGETSEL returned cpMin=%d, expected 3\n", cr
.cpMin
);
4563 ok(cr
.cpMax
== 3, "EM_EXGETSEL returned cpMax=%d, expected 3\n", cr
.cpMax
);
4565 /* Test the actual string */
4567 getText
.codepage
= CP_ACP
;
4568 getText
.flags
= GT_DEFAULT
;
4569 getText
.lpDefaultChar
= NULL
;
4570 getText
.lpUsedDefChar
= NULL
;
4571 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buffer
);
4572 ok(strcmp(buffer
, " \r\r") == 0,
4573 "EM_GETTEXTEX returned incorrect string\n");
4575 /* Test number of lines reported after EM_REPLACESEL */
4576 r
= SendMessage(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4577 ok(r
== 3, "EM_GETLINECOUNT returned %d, expected 3\n", r
);
4579 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4580 r
= SendMessage(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
) "\rX\r\n\r\r");
4581 ok(r
== 6, "EM_REPLACESEL returned %d, expected 6\n", r
);
4582 r
= SendMessage(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4583 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4584 ok(cr
.cpMin
== 5, "EM_EXGETSEL returned cpMin=%d, expected 5\n", cr
.cpMin
);
4585 ok(cr
.cpMax
== 5, "EM_EXGETSEL returned cpMax=%d, expected 5\n", cr
.cpMax
);
4587 /* Test the actual string */
4589 getText
.codepage
= CP_ACP
;
4590 getText
.flags
= GT_DEFAULT
;
4591 getText
.lpDefaultChar
= NULL
;
4592 getText
.lpUsedDefChar
= NULL
;
4593 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buffer
);
4594 ok(strcmp(buffer
, "\rX\r\r\r") == 0,
4595 "EM_GETTEXTEX returned incorrect string\n");
4597 /* Test number of lines reported after EM_REPLACESEL */
4598 r
= SendMessage(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4599 ok(r
== 5, "EM_GETLINECOUNT returned %d, expected 5\n", r
);
4601 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4602 r
= SendMessage(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
) "\n\n");
4603 ok(2 == r
, "EM_REPLACESEL returned %d, expected 2\n", r
);
4604 r
= SendMessage(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4605 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4606 ok(cr
.cpMin
== 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr
.cpMin
);
4607 ok(cr
.cpMax
== 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr
.cpMax
);
4609 /* Test the actual string */
4611 getText
.codepage
= CP_ACP
;
4612 getText
.flags
= GT_DEFAULT
;
4613 getText
.lpDefaultChar
= NULL
;
4614 getText
.lpUsedDefChar
= NULL
;
4615 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buffer
);
4616 ok(strcmp(buffer
, "\r\r") == 0,
4617 "EM_GETTEXTEX returned incorrect string\n");
4619 /* Test number of lines reported after EM_REPLACESEL */
4620 r
= SendMessage(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4621 ok(r
== 3, "EM_GETLINECOUNT returned %d, expected 3\n", r
);
4623 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4624 r
= SendMessage(hwndRichEdit
, EM_REPLACESEL
, 0, (LPARAM
) "\n\n\n\n\r\r\r\r\n");
4625 ok(r
== 9, "EM_REPLACESEL returned %d, expected 9\n", r
);
4626 r
= SendMessage(hwndRichEdit
, EM_EXGETSEL
, 0, (LPARAM
)&cr
);
4627 ok(0 == r
, "EM_EXGETSEL returned %d, expected 0\n", r
);
4628 ok(cr
.cpMin
== 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr
.cpMin
);
4629 ok(cr
.cpMax
== 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr
.cpMax
);
4631 /* Test the actual string */
4633 getText
.codepage
= CP_ACP
;
4634 getText
.flags
= GT_DEFAULT
;
4635 getText
.lpDefaultChar
= NULL
;
4636 getText
.lpUsedDefChar
= NULL
;
4637 SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buffer
);
4638 ok(strcmp(buffer
, "\r\r\r\r\r\r ") == 0,
4639 "EM_GETTEXTEX returned incorrect string\n");
4641 /* Test number of lines reported after EM_REPLACESEL */
4642 r
= SendMessage(hwndRichEdit
, EM_GETLINECOUNT
, 0, 0);
4643 ok(r
== 7, "EM_GETLINECOUNT returned %d, expected 7\n", r
);
4646 /* This is needed to avoid interferring with keybd_event calls
4647 * on other tests that simulate keyboard events. */
4648 SendMessage(hwndRichEdit
, WM_SETREDRAW
, TRUE
, 0);
4650 DestroyWindow(hwndRichEdit
);
4653 /* Native riched20 inspects the keyboard state (e.g. GetKeyState)
4654 * to test the state of the modifiers (Ctrl/Alt/Shift).
4656 * Therefore Ctrl-<key> keystrokes need to be simulated with
4657 * keybd_event or by using SetKeyboardState to set the modifiers
4658 * and SendMessage to simulate the keystrokes.
4660 static LRESULT
send_ctrl_key(HWND hwnd
, UINT key
)
4663 hold_key(VK_CONTROL
);
4664 result
= SendMessage(hwnd
, WM_KEYDOWN
, key
, 1);
4665 release_key(VK_CONTROL
);
4669 static void test_WM_PASTE(void)
4672 char buffer
[1024] = {0};
4673 const char* text1
= "testing paste\r";
4674 const char* text1_step1
= "testing paste\r\ntesting paste\r\n";
4675 const char* text1_after
= "testing paste\r\n";
4676 const char* text2
= "testing paste\r\rtesting paste";
4677 const char* text2_after
= "testing paste\r\n\r\ntesting paste";
4678 const char* text3
= "testing paste\r\npaste\r\ntesting paste";
4679 HWND hwndRichEdit
= new_richedit(NULL
);
4681 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text1
);
4682 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 14);
4684 send_ctrl_key(hwndRichEdit
, 'C'); /* Copy */
4685 SendMessage(hwndRichEdit
, EM_SETSEL
, 14, 14);
4686 send_ctrl_key(hwndRichEdit
, 'V'); /* Paste */
4687 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
4688 /* Pasted text should be visible at this step */
4689 result
= strcmp(text1_step1
, buffer
);
4691 "test paste: strcmp = %i, text='%s'\n", result
, buffer
);
4693 send_ctrl_key(hwndRichEdit
, 'Z'); /* Undo */
4694 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
4695 /* Text should be the same as before (except for \r -> \r\n conversion) */
4696 result
= strcmp(text1_after
, buffer
);
4698 "test paste: strcmp = %i, text='%s'\n", result
, buffer
);
4700 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text2
);
4701 SendMessage(hwndRichEdit
, EM_SETSEL
, 8, 13);
4702 send_ctrl_key(hwndRichEdit
, 'C'); /* Copy */
4703 SendMessage(hwndRichEdit
, EM_SETSEL
, 14, 14);
4704 send_ctrl_key(hwndRichEdit
, 'V'); /* Paste */
4705 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
4706 /* Pasted text should be visible at this step */
4707 result
= strcmp(text3
, buffer
);
4709 "test paste: strcmp = %i\n", result
);
4710 send_ctrl_key(hwndRichEdit
, 'Z'); /* Undo */
4711 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
4712 /* Text should be the same as before (except for \r -> \r\n conversion) */
4713 result
= strcmp(text2_after
, buffer
);
4715 "test paste: strcmp = %i\n", result
);
4716 send_ctrl_key(hwndRichEdit
, 'Y'); /* Redo */
4717 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
4718 /* Text should revert to post-paste state */
4719 result
= strcmp(buffer
,text3
);
4721 "test paste: strcmp = %i\n", result
);
4723 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4724 /* Send WM_CHAR to simulates Ctrl-V */
4725 SendMessage(hwndRichEdit
, WM_CHAR
, 22,
4726 (MapVirtualKey('V', MAPVK_VK_TO_VSC
) << 16) | 1);
4727 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
4728 /* Shouldn't paste because pasting is handled by WM_KEYDOWN */
4729 result
= strcmp(buffer
,"");
4731 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4733 /* Send keystrokes with WM_KEYDOWN after setting the modifiers
4734 * with SetKeyboard state. */
4736 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4737 /* Simulates paste (Ctrl-V) */
4738 hold_key(VK_CONTROL
);
4739 SendMessage(hwndRichEdit
, WM_KEYDOWN
, 'V',
4740 (MapVirtualKey('V', MAPVK_VK_TO_VSC
) << 16) | 1);
4741 release_key(VK_CONTROL
);
4742 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
4743 result
= strcmp(buffer
,"paste");
4745 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4747 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) text1
);
4748 SendMessage(hwndRichEdit
, EM_SETSEL
, 0, 7);
4749 /* Simulates copy (Ctrl-C) */
4750 hold_key(VK_CONTROL
);
4751 SendMessage(hwndRichEdit
, WM_KEYDOWN
, 'C',
4752 (MapVirtualKey('C', MAPVK_VK_TO_VSC
) << 16) | 1);
4753 release_key(VK_CONTROL
);
4754 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4755 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
4756 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
4757 result
= strcmp(buffer
,"testing");
4759 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4761 /* Cut with WM_KEYDOWN to simulate Ctrl-X */
4762 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) "cut");
4763 /* Simulates select all (Ctrl-A) */
4764 hold_key(VK_CONTROL
);
4765 SendMessage(hwndRichEdit
, WM_KEYDOWN
, 'A',
4766 (MapVirtualKey('A', MAPVK_VK_TO_VSC
) << 16) | 1);
4767 /* Simulates select cut (Ctrl-X) */
4768 SendMessage(hwndRichEdit
, WM_KEYDOWN
, 'X',
4769 (MapVirtualKey('X', MAPVK_VK_TO_VSC
) << 16) | 1);
4770 release_key(VK_CONTROL
);
4771 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
4772 result
= strcmp(buffer
,"");
4774 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4775 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, 0);
4776 SendMessage(hwndRichEdit
, WM_PASTE
, 0, 0);
4777 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
4778 result
= strcmp(buffer
,"cut\r\n");
4779 todo_wine
ok(result
== 0,
4780 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4781 /* Simulates undo (Ctrl-Z) */
4782 hold_key(VK_CONTROL
);
4783 SendMessage(hwndRichEdit
, WM_KEYDOWN
, 'Z',
4784 (MapVirtualKey('Z', MAPVK_VK_TO_VSC
) << 16) | 1);
4785 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
4786 result
= strcmp(buffer
,"");
4788 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4789 /* Simulates redo (Ctrl-Y) */
4790 SendMessage(hwndRichEdit
, WM_KEYDOWN
, 'Y',
4791 (MapVirtualKey('Y', MAPVK_VK_TO_VSC
) << 16) | 1);
4792 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
4793 result
= strcmp(buffer
,"cut\r\n");
4794 todo_wine
ok(result
== 0,
4795 "test paste: strcmp = %i, actual = '%s'\n", result
, buffer
);
4796 release_key(VK_CONTROL
);
4798 DestroyWindow(hwndRichEdit
);
4801 static void test_EM_FORMATRANGE(void)
4803 int r
, i
, tpp_x
, tpp_y
;
4805 HWND hwndRichEdit
= new_richedit(NULL
);
4807 BOOL skip_non_english
;
4808 static const struct {
4809 const char *string
; /* The string */
4810 int first
; /* First 'pagebreak', 0 for don't care */
4811 int second
; /* Second 'pagebreak', 0 for don't care */
4813 {"WINE wine", 0, 0},
4814 {"WINE wineWine", 0, 0},
4815 {"WINE\r\nwine\r\nwine", 5, 10},
4816 {"WINE\r\nWINEwine\r\nWINEwine", 5, 14},
4817 {"WINE\r\n\r\nwine\r\nwine", 5, 6}
4820 skip_non_english
= (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH
);
4821 if (skip_non_english
)
4822 skip("Skipping some tests on non-English platform\n");
4824 hdc
= GetDC(hwndRichEdit
);
4825 ok(hdc
!= NULL
, "Could not get HDC\n");
4827 /* Calculate the twips per pixel */
4828 tpp_x
= 1440 / GetDeviceCaps(hdc
, LOGPIXELSX
);
4829 tpp_y
= 1440 / GetDeviceCaps(hdc
, LOGPIXELSY
);
4831 /* Test the simple case where all the text fits in the page rect. */
4832 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"a");
4833 fr
.hdc
= fr
.hdcTarget
= hdc
;
4834 fr
.rc
.top
= fr
.rcPage
.top
= fr
.rc
.left
= fr
.rcPage
.left
= 0;
4835 fr
.rc
.right
= fr
.rcPage
.right
= 500 * tpp_x
;
4836 fr
.rc
.bottom
= fr
.rcPage
.bottom
= 500 * tpp_y
;
4839 r
= SendMessage(hwndRichEdit
, EM_FORMATRANGE
, FALSE
, (LPARAM
)&fr
);
4840 todo_wine
ok(r
== 2, "r=%d expected r=2\n", r
);
4842 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)"ab");
4843 fr
.rc
.bottom
= fr
.rcPage
.bottom
;
4844 r
= SendMessage(hwndRichEdit
, EM_FORMATRANGE
, FALSE
, (LPARAM
)&fr
);
4845 todo_wine
ok(r
== 3, "r=%d expected r=3\n", r
);
4847 SendMessage(hwndRichEdit
, EM_FORMATRANGE
, FALSE
, 0);
4849 for (i
= 0; i
< sizeof(fmtstrings
)/sizeof(fmtstrings
[0]); i
++)
4851 GETTEXTLENGTHEX gtl
;
4855 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) fmtstrings
[i
].string
);
4857 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
4858 gtl
.codepage
= CP_ACP
;
4859 len
= SendMessageA(hwndRichEdit
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
4861 /* Get some size information for the string */
4862 GetTextExtentPoint32(hdc
, fmtstrings
[i
].string
, strlen(fmtstrings
[i
].string
), &stringsize
);
4864 /* Define the box to be half the width needed and a bit larger than the height.
4865 * Changes to the width means we have at least 2 pages. Changes to the height
4866 * is done so we can check the changing of fr.rc.bottom.
4868 fr
.hdc
= fr
.hdcTarget
= hdc
;
4869 fr
.rc
.top
= fr
.rcPage
.top
= fr
.rc
.left
= fr
.rcPage
.left
= 0;
4870 fr
.rc
.right
= fr
.rcPage
.right
= (stringsize
.cx
/ 2) * tpp_x
;
4871 fr
.rc
.bottom
= fr
.rcPage
.bottom
= (stringsize
.cy
+ 10) * tpp_y
;
4873 r
= SendMessage(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, 0);
4875 ok(r
== len
, "Expected %d, got %d\n", len
, r
);
4878 /* We know that the page can't hold the full string. See how many characters
4879 * are on the first one
4883 r
= SendMessage(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, (LPARAM
) &fr
);
4885 if (! skip_non_english
)
4886 ok(fr
.rc
.bottom
== (stringsize
.cy
* tpp_y
), "Expected bottom to be %d, got %d\n", (stringsize
.cy
* tpp_y
), fr
.rc
.bottom
);
4888 if (fmtstrings
[i
].first
)
4890 ok(r
== fmtstrings
[i
].first
, "Expected %d, got %d\n", fmtstrings
[i
].first
, r
);
4893 ok(r
< len
, "Expected < %d, got %d\n", len
, r
);
4895 /* Do another page */
4897 r
= SendMessage(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, (LPARAM
) &fr
);
4898 if (fmtstrings
[i
].second
)
4900 ok(r
== fmtstrings
[i
].second
, "Expected %d, got %d\n", fmtstrings
[i
].second
, r
);
4902 else if (! skip_non_english
)
4903 ok (r
< len
, "Expected < %d, got %d\n", len
, r
);
4905 /* There is at least on more page, but we don't care */
4907 r
= SendMessage(hwndRichEdit
, EM_FORMATRANGE
, TRUE
, 0);
4909 ok(r
== len
, "Expected %d, got %d\n", len
, r
);
4913 ReleaseDC(NULL
, hdc
);
4914 DestroyWindow(hwndRichEdit
);
4917 static int nCallbackCount
= 0;
4919 static DWORD CALLBACK
EditStreamCallback(DWORD_PTR dwCookie
, LPBYTE pbBuff
,
4922 const char text
[] = {'t','e','s','t'};
4924 if (sizeof(text
) <= cb
)
4926 if ((int)dwCookie
!= nCallbackCount
)
4932 memcpy (pbBuff
, text
, sizeof(text
));
4933 *pcb
= sizeof(text
);
4940 return 1; /* indicates callback failed */
4943 static DWORD CALLBACK
test_EM_STREAMIN_esCallback(DWORD_PTR dwCookie
,
4948 const char** str
= (const char**)dwCookie
;
4949 int size
= strlen(*str
);
4955 memcpy(pbBuff
, *str
, *pcb
);
4961 struct StringWithLength
{
4966 /* This callback is used to handled the null characters in a string. */
4967 static DWORD CALLBACK
test_EM_STREAMIN_esCallback2(DWORD_PTR dwCookie
,
4972 struct StringWithLength
* str
= (struct StringWithLength
*)dwCookie
;
4973 int size
= str
->length
;
4979 memcpy(pbBuff
, str
->buffer
, *pcb
);
4980 str
->buffer
+= *pcb
;
4981 str
->length
-= *pcb
;
4986 static void test_EM_STREAMIN(void)
4988 HWND hwndRichEdit
= new_richedit(NULL
);
4991 char buffer
[1024] = {0};
4993 const char * streamText0
= "{\\rtf1 TestSomeText}";
4994 const char * streamText0a
= "{\\rtf1 TestSomeText\\par}";
4995 const char * streamText0b
= "{\\rtf1 TestSomeText\\par\\par}";
4997 const char * streamText1
=
4998 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n"
4999 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n"
5002 /* In richedit 2.0 mode, this should NOT be accepted, unlike 1.0 */
5003 const char * streamText2
=
5004 "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;"
5005 "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255"
5006 "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 "
5007 "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 "
5008 "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 "
5009 "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 "
5010 "\\tx11448 \\tx11872 \\tx12296 \\tx12720 \\tx13144 \\cf2 RichEdit1\\line }";
5012 const char * streamText3
= "RichEdit1";
5014 const char * streamText4
=
5015 "This text just needs to be long enough to cause run to be split onto "
5016 "two separate lines and make sure the null terminating character is "
5017 "handled properly.\0";
5018 int length4
= strlen(streamText4
) + 1;
5019 struct StringWithLength cookieForStream4
= {
5021 (char *)streamText4
,
5024 const WCHAR streamText5
[] = { 'T', 'e', 's', 't', 'S', 'o', 'm', 'e', 'T', 'e', 'x', 't' };
5025 int length5
= sizeof(streamText5
) / sizeof(WCHAR
);
5026 struct StringWithLength cookieForStream5
= {
5027 sizeof(streamText5
),
5028 (char *)streamText5
,
5031 /* Minimal test without \par at the end */
5032 es
.dwCookie
= (DWORD_PTR
)&streamText0
;
5034 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5035 result
= SendMessage(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5036 ok(result
== 12, "got %ld, expected %d\n", result
, 12);
5038 result
= SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
5040 "EM_STREAMIN: Test 0 returned %ld, expected 12\n", result
);
5041 result
= strcmp (buffer
,"TestSomeText");
5043 "EM_STREAMIN: Test 0 set wrong text: Result: %s\n",buffer
);
5044 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es
.dwError
, 0);
5046 /* Native richedit 2.0 ignores last \par */
5047 es
.dwCookie
= (DWORD_PTR
)&streamText0a
;
5049 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5050 result
= SendMessage(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5051 ok(result
== 12, "got %ld, expected %d\n", result
, 12);
5053 result
= SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
5055 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result
);
5056 result
= strcmp (buffer
,"TestSomeText");
5058 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer
);
5059 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0-a set error %d, expected %d\n", es
.dwError
, 0);
5061 /* Native richedit 2.0 ignores last \par, next-to-last \par appears */
5062 es
.dwCookie
= (DWORD_PTR
)&streamText0b
;
5064 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5065 result
= SendMessage(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5066 ok(result
== 13, "got %ld, expected %d\n", result
, 13);
5068 result
= SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
5070 "EM_STREAMIN: Test 0-b returned %ld, expected 14\n", result
);
5071 result
= strcmp (buffer
,"TestSomeText\r\n");
5073 "EM_STREAMIN: Test 0-b set wrong text: Result: %s\n",buffer
);
5074 ok(es
.dwError
== 0, "EM_STREAMIN: Test 0-b set error %d, expected %d\n", es
.dwError
, 0);
5076 es
.dwCookie
= (DWORD_PTR
)&streamText1
;
5078 es
.pfnCallback
= test_EM_STREAMIN_esCallback
;
5079 result
= SendMessage(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5080 ok(result
== 12, "got %ld, expected %d\n", result
, 12);
5082 result
= SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
5084 "EM_STREAMIN: Test 1 returned %ld, expected 12\n", result
);
5085 result
= strcmp (buffer
,"TestSomeText");
5087 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer
);
5088 ok(es
.dwError
== 0, "EM_STREAMIN: Test 1 set error %d, expected %d\n", es
.dwError
, 0);
5090 es
.dwCookie
= (DWORD_PTR
)&streamText2
;
5092 result
= SendMessage(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5093 ok(result
== 0, "got %ld, expected %d\n", result
, 0);
5095 result
= SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
5097 "EM_STREAMIN: Test 2 returned %ld, expected 0\n", result
);
5098 ok (strlen(buffer
) == 0,
5099 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
5100 ok(es
.dwError
== -16, "EM_STREAMIN: Test 2 set error %d, expected %d\n", es
.dwError
, -16);
5102 es
.dwCookie
= (DWORD_PTR
)&streamText3
;
5104 result
= SendMessage(hwndRichEdit
, EM_STREAMIN
, SF_RTF
, (LPARAM
)&es
);
5105 ok(result
== 0, "got %ld, expected %d\n", result
, 0);
5107 result
= SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
5109 "EM_STREAMIN: Test 3 returned %ld, expected 0\n", result
);
5110 ok (strlen(buffer
) == 0,
5111 "EM_STREAMIN: Test 3 set wrong text: Result: %s\n",buffer
);
5112 ok(es
.dwError
== -16, "EM_STREAMIN: Test 3 set error %d, expected %d\n", es
.dwError
, -16);
5114 es
.dwCookie
= (DWORD_PTR
)&cookieForStream4
;
5116 es
.pfnCallback
= test_EM_STREAMIN_esCallback2
;
5117 result
= SendMessage(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
5118 ok(result
== length4
, "got %ld, expected %d\n", result
, length4
);
5120 result
= SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
5121 ok (result
== length4
,
5122 "EM_STREAMIN: Test 4 returned %ld, expected %d\n", result
, length4
);
5123 ok(es
.dwError
== 0, "EM_STREAMIN: Test 4 set error %d, expected %d\n", es
.dwError
, 0);
5125 es
.dwCookie
= (DWORD_PTR
)&cookieForStream5
;
5127 es
.pfnCallback
= test_EM_STREAMIN_esCallback2
;
5128 result
= SendMessage(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
| SF_UNICODE
, (LPARAM
)&es
);
5129 ok(result
== sizeof(streamText5
), "got %ld, expected %u\n", result
, (UINT
)sizeof(streamText5
));
5131 result
= SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
5132 ok (result
== length5
,
5133 "EM_STREAMIN: Test 4 returned %ld, expected %d\n", result
, length5
);
5134 ok(es
.dwError
== 0, "EM_STREAMIN: Test 5 set error %d, expected %d\n", es
.dwError
, 0);
5136 DestroyWindow(hwndRichEdit
);
5139 static void test_EM_StreamIn_Undo(void)
5141 /* The purpose of this test is to determine when a EM_StreamIn should be
5142 * undoable. This is important because WM_PASTE currently uses StreamIn and
5143 * pasting should always be undoable but streaming isn't always.
5146 * StreamIn plain text without SFF_SELECTION.
5147 * StreamIn plain text with SFF_SELECTION set but a zero-length selection
5148 * StreamIn plain text with SFF_SELECTION and a valid, normal selection
5149 * StreamIn plain text with SFF_SELECTION and a backwards-selection (from>to)
5150 * Feel free to add tests for other text modes or StreamIn things.
5154 HWND hwndRichEdit
= new_richedit(NULL
);
5157 char buffer
[1024] = {0};
5158 const char randomtext
[] = "Some text";
5160 es
.pfnCallback
= (EDITSTREAMCALLBACK
) EditStreamCallback
;
5162 /* StreamIn, no SFF_SELECTION */
5163 es
.dwCookie
= nCallbackCount
;
5164 SendMessage(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
5165 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) randomtext
);
5166 SendMessage(hwndRichEdit
, EM_SETSEL
,0,0);
5167 SendMessage(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
, (LPARAM
)&es
);
5168 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
5169 result
= strcmp (buffer
,"test");
5171 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer
);
5173 result
= SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0);
5174 ok (result
== FALSE
,
5175 "EM_STREAMIN without SFF_SELECTION wrongly allows undo\n");
5177 /* StreamIn, SFF_SELECTION, but nothing selected */
5178 es
.dwCookie
= nCallbackCount
;
5179 SendMessage(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
5180 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) randomtext
);
5181 SendMessage(hwndRichEdit
, EM_SETSEL
,0,0);
5182 SendMessage(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
|SFF_SELECTION
, (LPARAM
)&es
);
5183 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
5184 result
= strcmp (buffer
,"testSome text");
5186 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
5188 result
= SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0);
5190 "EM_STREAMIN with SFF_SELECTION but no selection set "
5191 "should create an undo\n");
5193 /* StreamIn, SFF_SELECTION, with a selection */
5194 es
.dwCookie
= nCallbackCount
;
5195 SendMessage(hwndRichEdit
,EM_EMPTYUNDOBUFFER
, 0,0);
5196 SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) randomtext
);
5197 SendMessage(hwndRichEdit
, EM_SETSEL
,4,5);
5198 SendMessage(hwndRichEdit
, EM_STREAMIN
, SF_TEXT
|SFF_SELECTION
, (LPARAM
)&es
);
5199 SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buffer
);
5200 result
= strcmp (buffer
,"Sometesttext");
5202 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer
);
5204 result
= SendMessage(hwndRichEdit
, EM_CANUNDO
, 0, 0);
5206 "EM_STREAMIN with SFF_SELECTION and selection set "
5207 "should create an undo\n");
5209 DestroyWindow(hwndRichEdit
);
5212 static BOOL
is_em_settextex_supported(HWND hwnd
)
5214 SETTEXTEX stex
= { ST_DEFAULT
, CP_ACP
};
5215 return SendMessageA(hwnd
, EM_SETTEXTEX
, (WPARAM
)&stex
, 0) != 0;
5218 static void test_unicode_conversions(void)
5220 static const WCHAR tW
[] = {'t',0};
5221 static const WCHAR teW
[] = {'t','e',0};
5222 static const WCHAR textW
[] = {'t','e','s','t',0};
5223 static const char textA
[] = "test";
5227 int em_settextex_supported
, ret
;
5229 #define set_textA(hwnd, wm_set_text, txt) \
5231 SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; \
5232 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
5233 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
5234 ret = SendMessageA(hwnd, wm_set_text, wparam, (LPARAM)txt); \
5235 ok(ret, "SendMessageA(%02x) error %u\n", wm_set_text, GetLastError()); \
5237 #define expect_textA(hwnd, wm_get_text, txt) \
5239 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
5240 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
5241 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
5242 memset(bufA, 0xAA, sizeof(bufA)); \
5243 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
5244 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
5245 ret = lstrcmpA(bufA, txt); \
5246 ok(!ret, "%02x: strings do not match: expected %s got %s\n", wm_get_text, txt, bufA); \
5249 #define set_textW(hwnd, wm_set_text, txt) \
5251 SETTEXTEX stex = { ST_DEFAULT, 1200 }; \
5252 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
5253 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
5254 ret = SendMessageW(hwnd, wm_set_text, wparam, (LPARAM)txt); \
5255 ok(ret, "SendMessageW(%02x) error %u\n", wm_set_text, GetLastError()); \
5257 #define expect_textW(hwnd, wm_get_text, txt) \
5259 GETTEXTEX gtex = { 64, GT_DEFAULT, 1200, NULL, NULL }; \
5260 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
5261 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
5262 memset(bufW, 0xAA, sizeof(bufW)); \
5263 ret = SendMessageW(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
5264 ok(ret, "SendMessageW(%02x) error %u\n", wm_get_text, GetLastError()); \
5265 ret = lstrcmpW(bufW, txt); \
5266 ok(!ret, "%02x: strings do not match: expected[0] %x got[0] %x\n", wm_get_text, txt[0], bufW[0]); \
5268 #define expect_empty(hwnd, wm_get_text) \
5270 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
5271 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)>ex; \
5272 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
5273 memset(bufA, 0xAA, sizeof(bufA)); \
5274 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
5275 ok(!ret, "empty richedit should return 0, got %d\n", ret); \
5276 ok(!*bufA, "empty richedit should return empty string, got %s\n", bufA); \
5279 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
,
5280 0, 0, 200, 60, 0, 0, 0, 0);
5281 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5283 ret
= IsWindowUnicode(hwnd
);
5284 ok(ret
, "RichEdit20W should be unicode under NT\n");
5286 /* EM_SETTEXTEX is supported starting from version 3.0 */
5287 em_settextex_supported
= is_em_settextex_supported(hwnd
);
5288 trace("EM_SETTEXTEX is %ssupported on this platform\n",
5289 em_settextex_supported
? "" : "NOT ");
5291 expect_empty(hwnd
, WM_GETTEXT
);
5292 expect_empty(hwnd
, EM_GETTEXTEX
);
5294 ret
= SendMessageA(hwnd
, WM_CHAR
, textW
[0], 0);
5295 ok(!ret
, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret
);
5296 expect_textA(hwnd
, WM_GETTEXT
, "t");
5297 expect_textA(hwnd
, EM_GETTEXTEX
, "t");
5298 expect_textW(hwnd
, EM_GETTEXTEX
, tW
);
5300 ret
= SendMessageA(hwnd
, WM_CHAR
, textA
[1], 0);
5301 ok(!ret
, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret
);
5302 expect_textA(hwnd
, WM_GETTEXT
, "te");
5303 expect_textA(hwnd
, EM_GETTEXTEX
, "te");
5304 expect_textW(hwnd
, EM_GETTEXTEX
, teW
);
5306 set_textA(hwnd
, WM_SETTEXT
, NULL
);
5307 expect_empty(hwnd
, WM_GETTEXT
);
5308 expect_empty(hwnd
, EM_GETTEXTEX
);
5310 set_textA(hwnd
, WM_SETTEXT
, textA
);
5311 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5312 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5313 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5315 if (em_settextex_supported
)
5317 set_textA(hwnd
, EM_SETTEXTEX
, textA
);
5318 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5319 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5320 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5323 set_textW(hwnd
, WM_SETTEXT
, textW
);
5324 expect_textW(hwnd
, WM_GETTEXT
, textW
);
5325 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5326 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5327 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5329 if (em_settextex_supported
)
5331 set_textW(hwnd
, EM_SETTEXTEX
, textW
);
5332 expect_textW(hwnd
, WM_GETTEXT
, textW
);
5333 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5334 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5335 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5337 DestroyWindow(hwnd
);
5339 hwnd
= CreateWindowExA(0, "RichEdit20A", NULL
, WS_POPUP
,
5340 0, 0, 200, 60, 0, 0, 0, 0);
5341 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5343 ret
= IsWindowUnicode(hwnd
);
5344 ok(!ret
, "RichEdit20A should NOT be unicode\n");
5346 set_textA(hwnd
, WM_SETTEXT
, textA
);
5347 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5348 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5349 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5351 if (em_settextex_supported
)
5353 set_textA(hwnd
, EM_SETTEXTEX
, textA
);
5354 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5355 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5356 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5359 set_textW(hwnd
, WM_SETTEXT
, textW
);
5360 expect_textW(hwnd
, WM_GETTEXT
, textW
);
5361 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5362 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5363 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5365 if (em_settextex_supported
)
5367 set_textW(hwnd
, EM_SETTEXTEX
, textW
);
5368 expect_textW(hwnd
, WM_GETTEXT
, textW
);
5369 expect_textA(hwnd
, WM_GETTEXT
, textA
);
5370 expect_textW(hwnd
, EM_GETTEXTEX
, textW
);
5371 expect_textA(hwnd
, EM_GETTEXTEX
, textA
);
5373 DestroyWindow(hwnd
);
5376 static void test_WM_CHAR(void)
5380 const char * char_list
= "abc\rabc\r";
5381 const char * expected_content_single
= "abcabc";
5382 const char * expected_content_multi
= "abc\r\nabc\r\n";
5383 char buffer
[64] = {0};
5386 /* single-line control must IGNORE carriage returns */
5387 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
,
5388 0, 0, 200, 60, 0, 0, 0, 0);
5389 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5392 while (*p
!= '\0') {
5393 SendMessageA(hwnd
, WM_KEYDOWN
, *p
, 1);
5394 ret
= SendMessageA(hwnd
, WM_CHAR
, *p
, 1);
5395 ok(ret
== 0, "WM_CHAR('%c') ret=%d\n", *p
, ret
);
5396 SendMessageA(hwnd
, WM_KEYUP
, *p
, 1);
5400 SendMessage(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5401 ret
= strcmp(buffer
, expected_content_single
);
5402 ok(ret
== 0, "WM_GETTEXT recovered incorrect string!\n");
5404 DestroyWindow(hwnd
);
5406 /* multi-line control inserts CR normally */
5407 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
|ES_MULTILINE
,
5408 0, 0, 200, 60, 0, 0, 0, 0);
5409 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5412 while (*p
!= '\0') {
5413 SendMessageA(hwnd
, WM_KEYDOWN
, *p
, 1);
5414 ret
= SendMessageA(hwnd
, WM_CHAR
, *p
, 1);
5415 ok(ret
== 0, "WM_CHAR('%c') ret=%d\n", *p
, ret
);
5416 SendMessageA(hwnd
, WM_KEYUP
, *p
, 1);
5420 SendMessage(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5421 ret
= strcmp(buffer
, expected_content_multi
);
5422 ok(ret
== 0, "WM_GETTEXT recovered incorrect string!\n");
5424 DestroyWindow(hwnd
);
5427 static void test_EM_GETTEXTLENGTHEX(void)
5430 GETTEXTLENGTHEX gtl
;
5432 const char * base_string
= "base string";
5433 const char * test_string
= "a\nb\n\n\r\n";
5434 const char * test_string_after
= "a";
5435 const char * test_string_2
= "a\rtest\rstring";
5436 char buffer
[64] = {0};
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 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5444 gtl
.codepage
= CP_ACP
;
5445 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5446 ok(ret
== 0, "ret %d\n",ret
);
5448 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5449 gtl
.codepage
= CP_ACP
;
5450 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5451 ok(ret
== 0, "ret %d\n",ret
);
5453 SendMessage(hwnd
, WM_SETTEXT
, 0, (LPARAM
) base_string
);
5455 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5456 gtl
.codepage
= CP_ACP
;
5457 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5458 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
5460 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5461 gtl
.codepage
= CP_ACP
;
5462 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5463 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
5465 SendMessage(hwnd
, WM_SETTEXT
, 0, (LPARAM
) test_string
);
5467 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5468 gtl
.codepage
= CP_ACP
;
5469 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5470 ok(ret
== 1, "ret %d\n",ret
);
5472 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5473 gtl
.codepage
= CP_ACP
;
5474 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5475 ok(ret
== 1, "ret %d\n",ret
);
5477 SendMessage(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5478 ret
= strcmp(buffer
, test_string_after
);
5479 ok(ret
== 0, "WM_GETTEXT recovered incorrect string!\n");
5481 DestroyWindow(hwnd
);
5484 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
| ES_MULTILINE
,
5485 0, 0, 200, 60, 0, 0, 0, 0);
5486 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5488 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5489 gtl
.codepage
= CP_ACP
;
5490 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5491 ok(ret
== 0, "ret %d\n",ret
);
5493 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5494 gtl
.codepage
= CP_ACP
;
5495 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5496 ok(ret
== 0, "ret %d\n",ret
);
5498 SendMessage(hwnd
, WM_SETTEXT
, 0, (LPARAM
) base_string
);
5500 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5501 gtl
.codepage
= CP_ACP
;
5502 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5503 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
5505 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5506 gtl
.codepage
= CP_ACP
;
5507 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5508 ok(ret
== strlen(base_string
), "ret %d\n",ret
);
5510 SendMessage(hwnd
, WM_SETTEXT
, 0, (LPARAM
) test_string_2
);
5512 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5513 gtl
.codepage
= CP_ACP
;
5514 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5515 ok(ret
== strlen(test_string_2
) + 2, "ret %d\n",ret
);
5517 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5518 gtl
.codepage
= CP_ACP
;
5519 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5520 ok(ret
== strlen(test_string_2
), "ret %d\n",ret
);
5522 SendMessage(hwnd
, WM_SETTEXT
, 0, (LPARAM
) test_string
);
5524 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
| GTL_USECRLF
;
5525 gtl
.codepage
= CP_ACP
;
5526 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5527 ok(ret
== 10, "ret %d\n",ret
);
5529 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5530 gtl
.codepage
= CP_ACP
;
5531 ret
= SendMessageA(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>l
, 0);
5532 ok(ret
== 6, "ret %d\n",ret
);
5534 /* Unicode/NUMCHARS/NUMBYTES */
5535 SendMessage(hwnd
, WM_SETTEXT
, 0, (LPARAM
) test_string_2
);
5537 gtl
.flags
= GTL_DEFAULT
;
5538 gtl
.codepage
= 1200;
5539 ret
= SendMessage(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
) >l
, 0);
5540 ok(ret
== lstrlen(test_string_2
),
5541 "GTL_DEFAULT gave %i, expected %i\n", ret
, lstrlen(test_string_2
));
5543 gtl
.flags
= GTL_NUMCHARS
;
5544 gtl
.codepage
= 1200;
5545 ret
= SendMessage(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
) >l
, 0);
5546 ok(ret
== lstrlen(test_string_2
),
5547 "GTL_NUMCHARS gave %i, expected %i\n", ret
, lstrlen(test_string_2
));
5549 gtl
.flags
= GTL_NUMBYTES
;
5550 gtl
.codepage
= 1200;
5551 ret
= SendMessage(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
) >l
, 0);
5552 ok(ret
== lstrlen(test_string_2
)*2,
5553 "GTL_NUMBYTES gave %i, expected %i\n", ret
, lstrlen(test_string_2
)*2);
5555 gtl
.flags
= GTL_PRECISE
;
5556 gtl
.codepage
= 1200;
5557 ret
= SendMessage(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
) >l
, 0);
5558 ok(ret
== lstrlen(test_string_2
)*2,
5559 "GTL_PRECISE gave %i, expected %i\n", ret
, lstrlen(test_string_2
)*2);
5561 gtl
.flags
= GTL_NUMCHARS
| GTL_PRECISE
;
5562 gtl
.codepage
= 1200;
5563 ret
= SendMessage(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
) >l
, 0);
5564 ok(ret
== lstrlen(test_string_2
),
5565 "GTL_NUMCHAR | GTL_PRECISE gave %i, expected %i\n", ret
, lstrlen(test_string_2
));
5567 gtl
.flags
= GTL_NUMCHARS
| GTL_NUMBYTES
;
5568 gtl
.codepage
= 1200;
5569 ret
= SendMessage(hwnd
, EM_GETTEXTLENGTHEX
, (WPARAM
) >l
, 0);
5570 ok(ret
== E_INVALIDARG
,
5571 "GTL_NUMCHARS | GTL_NUMBYTES gave %i, expected %i\n", ret
, E_INVALIDARG
);
5573 DestroyWindow(hwnd
);
5577 /* globals that parent and child access when checking event masks & notifications */
5578 static HWND eventMaskEditHwnd
= 0;
5579 static int queriedEventMask
;
5580 static int watchForEventMask
= 0;
5582 /* parent proc that queries the edit's event mask when it gets a WM_COMMAND */
5583 static LRESULT WINAPI
ParentMsgCheckProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
5585 if(message
== WM_COMMAND
&& (watchForEventMask
& (wParam
>> 16)))
5587 queriedEventMask
= SendMessage(eventMaskEditHwnd
, EM_GETEVENTMASK
, 0, 0);
5589 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
5592 /* test event masks in combination with WM_COMMAND */
5593 static void test_eventMask(void)
5598 const char text
[] = "foo bar\n";
5601 /* register class to capture WM_COMMAND */
5603 cls
.lpfnWndProc
= ParentMsgCheckProcA
;
5606 cls
.hInstance
= GetModuleHandleA(0);
5608 cls
.hCursor
= LoadCursorA(0, IDC_ARROW
);
5609 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
5610 cls
.lpszMenuName
= NULL
;
5611 cls
.lpszClassName
= "EventMaskParentClass";
5612 if(!RegisterClassA(&cls
)) assert(0);
5614 parent
= CreateWindow(cls
.lpszClassName
, NULL
, WS_POPUP
|WS_VISIBLE
,
5615 0, 0, 200, 60, NULL
, NULL
, NULL
, NULL
);
5616 ok (parent
!= 0, "Failed to create parent window\n");
5618 eventMaskEditHwnd
= new_richedit(parent
);
5619 ok(eventMaskEditHwnd
!= 0, "Failed to create edit window\n");
5621 eventMask
= ENM_CHANGE
| ENM_UPDATE
;
5622 ret
= SendMessage(eventMaskEditHwnd
, EM_SETEVENTMASK
, 0, eventMask
);
5623 ok(ret
== ENM_NONE
, "wrong event mask\n");
5624 ret
= SendMessage(eventMaskEditHwnd
, EM_GETEVENTMASK
, 0, 0);
5625 ok(ret
== eventMask
, "failed to set event mask\n");
5627 /* check what happens when we ask for EN_CHANGE and send WM_SETTEXT */
5628 queriedEventMask
= 0; /* initialize to something other than we expect */
5629 watchForEventMask
= EN_CHANGE
;
5630 ret
= SendMessage(eventMaskEditHwnd
, WM_SETTEXT
, 0, (LPARAM
) text
);
5631 ok(ret
== TRUE
, "failed to set text\n");
5632 /* richedit should mask off ENM_CHANGE when it sends an EN_CHANGE
5633 notification in response to WM_SETTEXT */
5634 ok(queriedEventMask
== (eventMask
& ~ENM_CHANGE
),
5635 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
5637 /* check to see if EN_CHANGE is sent when redraw is turned off */
5638 SendMessage(eventMaskEditHwnd
, WM_CLEAR
, 0, 0);
5639 ok(IsWindowVisible(eventMaskEditHwnd
), "Window should be visible.\n");
5640 SendMessage(eventMaskEditHwnd
, WM_SETREDRAW
, FALSE
, 0);
5641 /* redraw is disabled by making the window invisible. */
5642 ok(!IsWindowVisible(eventMaskEditHwnd
), "Window shouldn't be visible.\n");
5643 queriedEventMask
= 0; /* initialize to something other than we expect */
5644 SendMessage(eventMaskEditHwnd
, EM_REPLACESEL
, 0, (LPARAM
) text
);
5645 ok(queriedEventMask
== (eventMask
& ~ENM_CHANGE
),
5646 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
5647 SendMessage(eventMaskEditHwnd
, WM_SETREDRAW
, TRUE
, 0);
5648 ok(IsWindowVisible(eventMaskEditHwnd
), "Window should be visible.\n");
5650 /* check to see if EN_UPDATE is sent when the editor isn't visible */
5651 SendMessage(eventMaskEditHwnd
, WM_CLEAR
, 0, 0);
5652 style
= GetWindowLong(eventMaskEditHwnd
, GWL_STYLE
);
5653 SetWindowLong(eventMaskEditHwnd
, GWL_STYLE
, style
& ~WS_VISIBLE
);
5654 ok(!IsWindowVisible(eventMaskEditHwnd
), "Window shouldn't be visible.\n");
5655 watchForEventMask
= EN_UPDATE
;
5656 queriedEventMask
= 0; /* initialize to something other than we expect */
5657 SendMessage(eventMaskEditHwnd
, EM_REPLACESEL
, 0, (LPARAM
) text
);
5658 ok(queriedEventMask
== 0,
5659 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
5660 SetWindowLong(eventMaskEditHwnd
, GWL_STYLE
, style
);
5661 ok(IsWindowVisible(eventMaskEditHwnd
), "Window should be visible.\n");
5662 queriedEventMask
= 0; /* initialize to something other than we expect */
5663 SendMessage(eventMaskEditHwnd
, EM_REPLACESEL
, 0, (LPARAM
) text
);
5664 ok(queriedEventMask
== eventMask
,
5665 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask
);
5668 DestroyWindow(parent
);
5671 static int received_WM_NOTIFY
= 0;
5672 static int modify_at_WM_NOTIFY
= 0;
5673 static BOOL filter_on_WM_NOTIFY
= FALSE
;
5674 static HWND hwndRichedit_WM_NOTIFY
;
5676 static LRESULT WINAPI
WM_NOTIFY_ParentMsgCheckProcA(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
5678 if(message
== WM_NOTIFY
)
5680 received_WM_NOTIFY
= 1;
5681 modify_at_WM_NOTIFY
= SendMessage(hwndRichedit_WM_NOTIFY
, EM_GETMODIFY
, 0, 0);
5682 if (filter_on_WM_NOTIFY
) return TRUE
;
5684 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
5687 static void test_WM_NOTIFY(void)
5692 int sel_start
, sel_end
;
5694 /* register class to capture WM_NOTIFY */
5696 cls
.lpfnWndProc
= WM_NOTIFY_ParentMsgCheckProcA
;
5699 cls
.hInstance
= GetModuleHandleA(0);
5701 cls
.hCursor
= LoadCursorA(0, IDC_ARROW
);
5702 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
5703 cls
.lpszMenuName
= NULL
;
5704 cls
.lpszClassName
= "WM_NOTIFY_ParentClass";
5705 if(!RegisterClassA(&cls
)) assert(0);
5707 parent
= CreateWindow(cls
.lpszClassName
, NULL
, WS_POPUP
|WS_VISIBLE
,
5708 0, 0, 200, 60, NULL
, NULL
, NULL
, NULL
);
5709 ok (parent
!= 0, "Failed to create parent window\n");
5711 hwndRichedit_WM_NOTIFY
= new_richedit(parent
);
5712 ok(hwndRichedit_WM_NOTIFY
!= 0, "Failed to create edit window\n");
5714 SendMessage(hwndRichedit_WM_NOTIFY
, EM_SETEVENTMASK
, 0, ENM_SELCHANGE
);
5716 /* Notifications for selection change should only be sent when selection
5717 actually changes. EM_SETCHARFORMAT is one message that calls
5718 ME_CommitUndo, which should check whether message should be sent */
5719 received_WM_NOTIFY
= 0;
5720 cf2
.cbSize
= sizeof(CHARFORMAT2
);
5721 SendMessage(hwndRichedit_WM_NOTIFY
, EM_GETCHARFORMAT
, SCF_DEFAULT
, (LPARAM
)&cf2
);
5722 cf2
.dwMask
= CFM_ITALIC
| cf2
.dwMask
;
5723 cf2
.dwEffects
= CFE_ITALIC
^ cf2
.dwEffects
;
5724 SendMessage(hwndRichedit_WM_NOTIFY
, EM_SETCHARFORMAT
, 0, (LPARAM
) &cf2
);
5725 ok(received_WM_NOTIFY
== 0, "Unexpected WM_NOTIFY was sent!\n");
5727 /* WM_SETTEXT should NOT cause a WM_NOTIFY to be sent when selection is
5729 received_WM_NOTIFY
= 0;
5730 modify_at_WM_NOTIFY
= 0;
5731 SendMessage(hwndRichedit_WM_NOTIFY
, WM_SETTEXT
, 0, (LPARAM
)"sometext");
5732 ok(received_WM_NOTIFY
== 0, "Unexpected WM_NOTIFY was sent!\n");
5733 ok(modify_at_WM_NOTIFY
== 0, "WM_NOTIFY callback saw text flagged as modified!\n");
5735 received_WM_NOTIFY
= 0;
5736 modify_at_WM_NOTIFY
= 0;
5737 SendMessage(hwndRichedit_WM_NOTIFY
, EM_SETSEL
, 4, 4);
5738 ok(received_WM_NOTIFY
== 1, "Expected WM_NOTIFY was NOT sent!\n");
5740 received_WM_NOTIFY
= 0;
5741 modify_at_WM_NOTIFY
= 0;
5742 SendMessage(hwndRichedit_WM_NOTIFY
, WM_SETTEXT
, 0, (LPARAM
)"sometext");
5743 ok(received_WM_NOTIFY
== 1, "Expected WM_NOTIFY was NOT sent!\n");
5744 ok(modify_at_WM_NOTIFY
== 0, "WM_NOTIFY callback saw text flagged as modified!\n");
5746 /* Test for WM_NOTIFY messages with redraw disabled. */
5747 SendMessage(hwndRichedit_WM_NOTIFY
, EM_SETSEL
, 0, 0);
5748 SendMessage(hwndRichedit_WM_NOTIFY
, WM_SETREDRAW
, FALSE
, 0);
5749 received_WM_NOTIFY
= 0;
5750 SendMessage(hwndRichedit_WM_NOTIFY
, EM_REPLACESEL
, FALSE
, (LPARAM
)"inserted");
5751 ok(received_WM_NOTIFY
== 1, "Expected WM_NOTIFY was NOT sent!\n");
5752 SendMessage(hwndRichedit_WM_NOTIFY
, WM_SETREDRAW
, TRUE
, 0);
5754 /* Test filtering key events. */
5755 SendMessage(hwndRichedit_WM_NOTIFY
, EM_SETSEL
, 0, 0);
5756 SendMessage(hwndRichedit_WM_NOTIFY
, EM_SETEVENTMASK
, 0, ENM_KEYEVENTS
);
5757 SendMessage(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5758 received_WM_NOTIFY
= 0;
5759 SendMessage(hwndRichedit_WM_NOTIFY
, WM_KEYDOWN
, VK_RIGHT
, 0);
5760 SendMessage(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5761 ok(sel_start
== 1 && sel_end
== 1,
5762 "selections is incorrectly at (%d,%d)\n", sel_start
, sel_end
);
5763 filter_on_WM_NOTIFY
= TRUE
;
5764 received_WM_NOTIFY
= 0;
5765 SendMessage(hwndRichedit_WM_NOTIFY
, WM_KEYDOWN
, VK_RIGHT
, 0);
5766 SendMessage(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5767 ok(sel_start
== 1 && sel_end
== 1,
5768 "selections is incorrectly at (%d,%d)\n", sel_start
, sel_end
);
5770 /* test with owner set to NULL */
5771 SetWindowLongPtr(hwndRichedit_WM_NOTIFY
, GWLP_HWNDPARENT
, 0);
5772 SendMessage(hwndRichedit_WM_NOTIFY
, WM_KEYDOWN
, VK_RIGHT
, 0);
5773 SendMessage(hwndRichedit_WM_NOTIFY
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5774 ok(sel_start
== 1 && sel_end
== 1,
5775 "selections is incorrectly at (%d,%d)\n", sel_start
, sel_end
);
5777 DestroyWindow(hwndRichedit_WM_NOTIFY
);
5778 DestroyWindow(parent
);
5781 static void test_undo_coalescing(void)
5785 char buffer
[64] = {0};
5787 /* multi-line control inserts CR normally */
5788 hwnd
= CreateWindowExA(0, "RichEdit20W", NULL
, WS_POPUP
|ES_MULTILINE
,
5789 0, 0, 200, 60, 0, 0, 0, 0);
5790 ok(hwnd
!= 0, "CreateWindowExA error %u\n", GetLastError());
5792 result
= SendMessage(hwnd
, EM_CANUNDO
, 0, 0);
5793 ok (result
== FALSE
, "Can undo after window creation.\n");
5794 result
= SendMessage(hwnd
, EM_UNDO
, 0, 0);
5795 ok (result
== FALSE
, "Undo operation successful with nothing to undo.\n");
5796 result
= SendMessage(hwnd
, EM_CANREDO
, 0, 0);
5797 ok (result
== FALSE
, "Can redo after window creation.\n");
5798 result
= SendMessage(hwnd
, EM_REDO
, 0, 0);
5799 ok (result
== FALSE
, "Redo operation successful with nothing undone.\n");
5801 /* Test the effect of arrows keys during typing on undo transactions*/
5802 simulate_typing_characters(hwnd
, "one two three");
5803 SendMessage(hwnd
, WM_KEYDOWN
, VK_RIGHT
, 1);
5804 SendMessage(hwnd
, WM_KEYUP
, VK_RIGHT
, 1);
5805 simulate_typing_characters(hwnd
, " four five six");
5807 result
= SendMessage(hwnd
, EM_CANREDO
, 0, 0);
5808 ok (result
== FALSE
, "Can redo before anything is undone.\n");
5809 result
= SendMessage(hwnd
, EM_CANUNDO
, 0, 0);
5810 ok (result
== TRUE
, "Cannot undo typed characters.\n");
5811 result
= SendMessage(hwnd
, EM_UNDO
, 0, 0);
5812 ok (result
== TRUE
, "EM_UNDO Failed to undo typed characters.\n");
5813 result
= SendMessage(hwnd
, EM_CANREDO
, 0, 0);
5814 ok (result
== TRUE
, "Cannot redo after undo.\n");
5815 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5816 result
= strcmp(buffer
, "one two three");
5817 ok (result
== 0, "expected '%s' but got '%s'\n", "one two three", buffer
);
5819 result
= SendMessage(hwnd
, EM_CANUNDO
, 0, 0);
5820 ok (result
== TRUE
, "Cannot undo typed characters.\n");
5821 result
= SendMessage(hwnd
, WM_UNDO
, 0, 0);
5822 ok (result
== TRUE
, "Failed to undo typed characters.\n");
5823 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5824 result
= strcmp(buffer
, "");
5825 ok (result
== 0, "expected '%s' but got '%s'\n", "", buffer
);
5827 /* Test the effect of focus changes during typing on undo transactions*/
5828 simulate_typing_characters(hwnd
, "one two three");
5829 result
= SendMessage(hwnd
, EM_CANREDO
, 0, 0);
5830 ok (result
== FALSE
, "Redo buffer should have been cleared by typing.\n");
5831 SendMessage(hwnd
, WM_KILLFOCUS
, 0, 0);
5832 SendMessage(hwnd
, WM_SETFOCUS
, 0, 0);
5833 simulate_typing_characters(hwnd
, " four five six");
5834 result
= SendMessage(hwnd
, EM_UNDO
, 0, 0);
5835 ok (result
== TRUE
, "Failed to undo typed characters.\n");
5836 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5837 result
= strcmp(buffer
, "one two three");
5838 ok (result
== 0, "expected '%s' but got '%s'\n", "one two three", buffer
);
5840 /* Test the effect of the back key during typing on undo transactions */
5841 SendMessage(hwnd
, EM_EMPTYUNDOBUFFER
, 0, 0);
5842 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"");
5843 ok (result
== TRUE
, "Failed to clear the text.\n");
5844 simulate_typing_characters(hwnd
, "one two threa");
5845 result
= SendMessage(hwnd
, EM_CANREDO
, 0, 0);
5846 ok (result
== FALSE
, "Redo buffer should have been cleared by typing.\n");
5847 SendMessage(hwnd
, WM_KEYDOWN
, VK_BACK
, 1);
5848 SendMessage(hwnd
, WM_KEYUP
, VK_BACK
, 1);
5849 simulate_typing_characters(hwnd
, "e four five six");
5850 result
= SendMessage(hwnd
, EM_UNDO
, 0, 0);
5851 ok (result
== TRUE
, "Failed to undo typed characters.\n");
5852 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5853 result
= strcmp(buffer
, "");
5854 ok (result
== 0, "expected '%s' but got '%s'\n", "", buffer
);
5856 /* Test the effect of the delete key during typing on undo transactions */
5857 SendMessage(hwnd
, EM_EMPTYUNDOBUFFER
, 0, 0);
5858 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"abcd");
5859 ok(result
== TRUE
, "Failed to set the text.\n");
5860 SendMessage(hwnd
, EM_SETSEL
, 1, 1);
5861 SendMessage(hwnd
, WM_KEYDOWN
, VK_DELETE
, 1);
5862 SendMessage(hwnd
, WM_KEYUP
, VK_DELETE
, 1);
5863 SendMessage(hwnd
, WM_KEYDOWN
, VK_DELETE
, 1);
5864 SendMessage(hwnd
, WM_KEYUP
, VK_DELETE
, 1);
5865 result
= SendMessage(hwnd
, EM_UNDO
, 0, 0);
5866 ok (result
== TRUE
, "Failed to undo typed characters.\n");
5867 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5868 result
= strcmp(buffer
, "acd");
5869 ok (result
== 0, "expected '%s' but got '%s'\n", "acd", buffer
);
5870 result
= SendMessage(hwnd
, EM_UNDO
, 0, 0);
5871 ok (result
== TRUE
, "Failed to undo typed characters.\n");
5872 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5873 result
= strcmp(buffer
, "abcd");
5874 ok (result
== 0, "expected '%s' but got '%s'\n", "abcd", buffer
);
5876 /* Test the effect of EM_STOPGROUPTYPING on undo transactions*/
5877 SendMessage(hwnd
, EM_EMPTYUNDOBUFFER
, 0, 0);
5878 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"");
5879 ok (result
== TRUE
, "Failed to clear the text.\n");
5880 simulate_typing_characters(hwnd
, "one two three");
5881 result
= SendMessage(hwnd
, EM_STOPGROUPTYPING
, 0, 0);
5882 ok (result
== 0, "expected %d but got %d\n", 0, result
);
5883 simulate_typing_characters(hwnd
, " four five six");
5884 result
= SendMessage(hwnd
, EM_UNDO
, 0, 0);
5885 ok (result
== TRUE
, "Failed to undo typed characters.\n");
5886 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5887 result
= strcmp(buffer
, "one two three");
5888 ok (result
== 0, "expected '%s' but got '%s'\n", "one two three", buffer
);
5889 result
= SendMessage(hwnd
, EM_UNDO
, 0, 0);
5890 ok (result
== TRUE
, "Failed to undo typed characters.\n");
5891 SendMessageA(hwnd
, WM_GETTEXT
, sizeof(buffer
), (LPARAM
)buffer
);
5892 result
= strcmp(buffer
, "");
5893 ok (result
== 0, "expected '%s' but got '%s'\n", "", buffer
);
5895 DestroyWindow(hwnd
);
5898 static LONG CALLBACK
customWordBreakProc(WCHAR
*text
, int pos
, int bytes
, int code
)
5902 /* MSDN lied, length is actually the number of bytes. */
5903 length
= bytes
/ sizeof(WCHAR
);
5906 case WB_ISDELIMITER
:
5907 return text
[pos
] == 'X';
5909 case WB_MOVEWORDLEFT
:
5910 if (customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
5912 return min(customWordBreakProc(text
, pos
, bytes
, WB_LEFTBREAK
)-1, 0);
5915 while (pos
> 0 && !customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
5919 case WB_MOVEWORDRIGHT
:
5920 if (customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
5922 return min(customWordBreakProc(text
, pos
, bytes
, WB_RIGHTBREAK
)+1, length
);
5925 while (pos
< length
&& !customWordBreakProc(text
, pos
, bytes
, WB_ISDELIMITER
))
5929 ok(FALSE
, "Unexpected code %d\n", code
);
5935 static void test_word_movement(void)
5939 int sel_start
, sel_end
;
5940 const WCHAR textW
[] = {'o','n','e',' ','t','w','o','X','t','h','r','e','e',0};
5942 /* multi-line control inserts CR normally */
5943 hwnd
= new_richedit(NULL
);
5945 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"one two three");
5946 ok (result
== TRUE
, "Failed to clear the text.\n");
5947 SendMessage(hwnd
, EM_SETSEL
, 0, 0);
5948 /* |one two three */
5950 send_ctrl_key(hwnd
, VK_RIGHT
);
5951 /* one |two three */
5952 SendMessage(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5953 ok(sel_start
== sel_end
, "Selection should be empty\n");
5954 ok(sel_start
== 4, "Cursor is at %d instead of %d\n", sel_start
, 4);
5956 send_ctrl_key(hwnd
, VK_RIGHT
);
5957 /* one two |three */
5958 SendMessage(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5959 ok(sel_start
== sel_end
, "Selection should be empty\n");
5960 ok(sel_start
== 9, "Cursor is at %d instead of %d\n", sel_start
, 9);
5962 send_ctrl_key(hwnd
, VK_LEFT
);
5963 /* one |two three */
5964 SendMessage(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5965 ok(sel_start
== sel_end
, "Selection should be empty\n");
5966 ok(sel_start
== 4, "Cursor is at %d instead of %d\n", sel_start
, 4);
5968 send_ctrl_key(hwnd
, VK_LEFT
);
5969 /* |one two three */
5970 SendMessage(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5971 ok(sel_start
== sel_end
, "Selection should be empty\n");
5972 ok(sel_start
== 0, "Cursor is at %d instead of %d\n", sel_start
, 0);
5974 SendMessage(hwnd
, EM_SETSEL
, 8, 8);
5975 /* one two | three */
5976 send_ctrl_key(hwnd
, VK_RIGHT
);
5977 /* one two |three */
5978 SendMessage(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5979 ok(sel_start
== sel_end
, "Selection should be empty\n");
5980 ok(sel_start
== 9, "Cursor is at %d instead of %d\n", sel_start
, 9);
5982 SendMessage(hwnd
, EM_SETSEL
, 11, 11);
5983 /* one two th|ree */
5984 send_ctrl_key(hwnd
, VK_LEFT
);
5985 /* one two |three */
5986 SendMessage(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5987 ok(sel_start
== sel_end
, "Selection should be empty\n");
5988 ok(sel_start
== 9, "Cursor is at %d instead of %d\n", sel_start
, 9);
5990 /* Test with a custom word break procedure that uses X as the delimiter. */
5991 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0, (LPARAM
)"one twoXthree");
5992 ok (result
== TRUE
, "Failed to clear the text.\n");
5993 SendMessage(hwnd
, EM_SETWORDBREAKPROC
, 0, (LPARAM
)customWordBreakProc
);
5994 /* |one twoXthree */
5995 send_ctrl_key(hwnd
, VK_RIGHT
);
5996 /* one twoX|three */
5997 SendMessage(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
5998 ok(sel_start
== sel_end
, "Selection should be empty\n");
5999 ok(sel_start
== 8, "Cursor is at %d instead of %d\n", sel_start
, 8);
6001 DestroyWindow(hwnd
);
6003 /* Make sure the behaviour is the same with a unicode richedit window,
6004 * and using unicode functions. */
6006 hwnd
= CreateWindowW(RICHEDIT_CLASS20W
, NULL
,
6007 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
6008 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6010 /* Test with a custom word break procedure that uses X as the delimiter. */
6011 result
= SendMessageW(hwnd
, WM_SETTEXT
, 0, (LPARAM
)textW
);
6012 ok (result
== TRUE
, "Failed to clear the text.\n");
6013 SendMessageW(hwnd
, EM_SETWORDBREAKPROC
, 0, (LPARAM
)customWordBreakProc
);
6014 /* |one twoXthree */
6015 send_ctrl_key(hwnd
, VK_RIGHT
);
6016 /* one twoX|three */
6017 SendMessageW(hwnd
, EM_GETSEL
, (WPARAM
)&sel_start
, (LPARAM
)&sel_end
);
6018 ok(sel_start
== sel_end
, "Selection should be empty\n");
6019 ok(sel_start
== 8, "Cursor is at %d instead of %d\n", sel_start
, 8);
6021 DestroyWindow(hwnd
);
6024 static void test_EM_CHARFROMPOS(void)
6033 /* multi-line control inserts CR normally */
6034 hwnd
= new_richedit(NULL
);
6035 result
= SendMessageA(hwnd
, WM_SETTEXT
, 0,
6036 (LPARAM
)"one two three four five six seven\reight");
6037 ok(result
== 1, "Expected 1, got %d\n", result
);
6038 GetClientRect(hwnd
, &rcClient
);
6040 result
= SendMessage(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6041 ok(result
== 34, "expected character index of 34 but got %d\n", result
);
6043 /* Test with points outside the bounds of the richedit control. */
6046 result
= SendMessage(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6047 todo_wine
ok(result
== 34, "expected character index of 34 but got %d\n", result
);
6051 result
= SendMessage(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6052 todo_wine
ok(result
== 33, "expected character index of 33 but got %d\n", result
);
6056 result
= SendMessage(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6057 todo_wine
ok(result
== 39, "expected character index of 39 but got %d\n", result
);
6061 result
= SendMessage(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6062 todo_wine
ok(result
== 0, "expected character index of 0 but got %d\n", result
);
6065 point
.y
= rcClient
.bottom
+ 1;
6066 result
= SendMessage(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6067 todo_wine
ok(result
== 34, "expected character index of 34 but got %d\n", result
);
6070 point
.y
= rcClient
.bottom
;
6071 result
= SendMessage(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
)&point
);
6072 todo_wine
ok(result
== 39, "expected character index of 39 but got %d\n", result
);
6074 DestroyWindow(hwnd
);
6077 static void test_word_wrap(void)
6080 POINTL point
= {0, 60}; /* This point must be below the first line */
6081 const char *text
= "Must be long enough to test line wrapping";
6082 DWORD dwCommonStyle
= WS_VISIBLE
|WS_POPUP
|WS_VSCROLL
|ES_MULTILINE
;
6083 int res
, pos
, lines
;
6085 /* Test the effect of WS_HSCROLL and ES_AUTOHSCROLL styles on wrapping
6086 * when specified on window creation and set later. */
6087 hwnd
= CreateWindow(RICHEDIT_CLASS
, NULL
, dwCommonStyle
,
6088 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6089 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6090 res
= SendMessage(hwnd
, WM_SETTEXT
, 0, (LPARAM
) text
);
6091 ok(res
, "WM_SETTEXT failed.\n");
6092 pos
= SendMessage(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
) &point
);
6093 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
6094 lines
= SendMessage(hwnd
, EM_GETLINECOUNT
, 0, 0);
6095 ok(lines
> 1, "Line was expected to wrap (lines=%d).\n", lines
);
6097 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
|WS_HSCROLL
|ES_AUTOHSCROLL
);
6098 pos
= SendMessage(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
) &point
);
6099 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
6100 DestroyWindow(hwnd
);
6102 hwnd
= CreateWindow(RICHEDIT_CLASS
, NULL
, dwCommonStyle
|WS_HSCROLL
,
6103 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6104 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6106 res
= SendMessage(hwnd
, WM_SETTEXT
, 0, (LPARAM
) text
);
6107 ok(res
, "WM_SETTEXT failed.\n");
6108 pos
= SendMessage(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
) &point
);
6109 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6110 lines
= SendMessage(hwnd
, EM_GETLINECOUNT
, 0, 0);
6111 ok(lines
== 1, "Line wasn't expected to wrap (lines=%d).\n", lines
);
6113 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
);
6114 pos
= SendMessage(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
) &point
);
6115 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6116 DestroyWindow(hwnd
);
6118 hwnd
= CreateWindow(RICHEDIT_CLASS
, NULL
, dwCommonStyle
|ES_AUTOHSCROLL
,
6119 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6120 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6121 res
= SendMessage(hwnd
, WM_SETTEXT
, 0, (LPARAM
) text
);
6122 ok(res
, "WM_SETTEXT failed.\n");
6123 pos
= SendMessage(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
) &point
);
6124 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6126 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
);
6127 pos
= SendMessage(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
) &point
);
6128 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6129 DestroyWindow(hwnd
);
6131 hwnd
= CreateWindow(RICHEDIT_CLASS
, NULL
,
6132 dwCommonStyle
|WS_HSCROLL
|ES_AUTOHSCROLL
,
6133 0, 0, 200, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6134 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6135 res
= SendMessage(hwnd
, WM_SETTEXT
, 0, (LPARAM
) text
);
6136 ok(res
, "WM_SETTEXT failed.\n");
6137 pos
= SendMessage(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
) &point
);
6138 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6140 SetWindowLongW(hwnd
, GWL_STYLE
, dwCommonStyle
);
6141 pos
= SendMessage(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
) &point
);
6142 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6144 /* Test the effect of EM_SETTARGETDEVICE on word wrap. */
6145 res
= SendMessage(hwnd
, EM_SETTARGETDEVICE
, 0, 1);
6146 ok(res
, "EM_SETTARGETDEVICE failed (returned %d).\n", res
);
6147 pos
= SendMessage(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
) &point
);
6148 ok(!pos
, "pos=%d indicating word wrap when none is expected.\n", pos
);
6150 res
= SendMessage(hwnd
, EM_SETTARGETDEVICE
, 0, 0);
6151 ok(res
, "EM_SETTARGETDEVICE failed (returned %d).\n", res
);
6152 pos
= SendMessage(hwnd
, EM_CHARFROMPOS
, 0, (LPARAM
) &point
);
6153 ok(pos
, "pos=%d indicating no word wrap when it is expected.\n", pos
);
6154 DestroyWindow(hwnd
);
6156 /* Test to see if wrapping happens with redraw disabled. */
6157 hwnd
= CreateWindow(RICHEDIT_CLASS
, NULL
, dwCommonStyle
,
6158 0, 0, 400, 80, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6159 ok(hwnd
!= NULL
, "error: %d\n", (int) GetLastError());
6160 SendMessage(hwnd
, WM_SETREDRAW
, FALSE
, 0);
6161 res
= SendMessage(hwnd
, EM_REPLACESEL
, FALSE
, (LPARAM
) text
);
6162 ok(res
, "EM_REPLACESEL failed.\n");
6163 lines
= SendMessage(hwnd
, EM_GETLINECOUNT
, 0, 0);
6164 ok(lines
== 1, "Line wasn't expected to wrap (lines=%d).\n", lines
);
6165 MoveWindow(hwnd
, 0, 0, 200, 80, FALSE
);
6166 lines
= SendMessage(hwnd
, EM_GETLINECOUNT
, 0, 0);
6167 ok(lines
> 1, "Line was expected to wrap (lines=%d).\n", lines
);
6169 SendMessage(hwnd
, WM_SETREDRAW
, TRUE
, 0);
6170 DestroyWindow(hwnd
);
6173 static void test_autoscroll(void)
6175 HWND hwnd
= new_richedit(NULL
);
6176 int lines
, ret
, redraw
;
6179 for (redraw
= 0; redraw
<= 1; redraw
++) {
6180 trace("testing with WM_SETREDRAW=%d\n", redraw
);
6181 SendMessage(hwnd
, WM_SETREDRAW
, redraw
, 0);
6182 SendMessage(hwnd
, EM_REPLACESEL
, 0, (LPARAM
)"1\n2\n3\n4\n5\n6\n7\n8");
6183 lines
= SendMessage(hwnd
, EM_GETLINECOUNT
, 0, 0);
6184 ok(lines
== 8, "%d lines instead of 8\n", lines
);
6185 ret
= SendMessage(hwnd
, EM_GETSCROLLPOS
, 0, (LPARAM
)&pt
);
6186 ok(ret
== 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret
);
6187 ok(pt
.y
!= 0, "Didn't scroll down after replacing text.\n");
6188 ret
= GetWindowLong(hwnd
, GWL_STYLE
);
6189 ok(ret
& WS_VSCROLL
, "Scrollbar was not shown yet (style=%x).\n", (UINT
)ret
);
6191 SendMessage(hwnd
, WM_SETTEXT
, 0, 0);
6192 lines
= SendMessage(hwnd
, EM_GETLINECOUNT
, 0, 0);
6193 ok(lines
== 1, "%d lines instead of 1\n", lines
);
6194 ret
= SendMessage(hwnd
, EM_GETSCROLLPOS
, 0, (LPARAM
)&pt
);
6195 ok(ret
== 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret
);
6196 ok(pt
.y
== 0, "y scroll position is %d after clearing text.\n", pt
.y
);
6197 ret
= GetWindowLong(hwnd
, GWL_STYLE
);
6198 ok(!(ret
& WS_VSCROLL
), "Scrollbar is still shown (style=%x).\n", (UINT
)ret
);
6201 SendMessage(hwnd
, WM_SETREDRAW
, TRUE
, 0);
6202 DestroyWindow(hwnd
);
6204 /* The WS_VSCROLL and WS_HSCROLL styles implicitly set
6205 * auto vertical/horizontal scrolling options. */
6206 hwnd
= CreateWindowEx(0, RICHEDIT_CLASS
, NULL
,
6207 WS_POPUP
|ES_MULTILINE
|WS_VSCROLL
|WS_HSCROLL
,
6208 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6209 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS
, (int) GetLastError());
6210 ret
= SendMessage(hwnd
, EM_GETOPTIONS
, 0, 0);
6211 ok(ret
& ECO_AUTOVSCROLL
, "ECO_AUTOVSCROLL isn't set.\n");
6212 ok(ret
& ECO_AUTOHSCROLL
, "ECO_AUTOHSCROLL isn't set.\n");
6213 ret
= GetWindowLong(hwnd
, GWL_STYLE
);
6214 ok(!(ret
& ES_AUTOVSCROLL
), "ES_AUTOVSCROLL is set.\n");
6215 ok(!(ret
& ES_AUTOHSCROLL
), "ES_AUTOHSCROLL is set.\n");
6216 DestroyWindow(hwnd
);
6218 hwnd
= CreateWindowEx(0, RICHEDIT_CLASS
, NULL
,
6219 WS_POPUP
|ES_MULTILINE
,
6220 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6221 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS
, (int) GetLastError());
6222 ret
= SendMessage(hwnd
, EM_GETOPTIONS
, 0, 0);
6223 ok(!(ret
& ECO_AUTOVSCROLL
), "ECO_AUTOVSCROLL is set.\n");
6224 ok(!(ret
& ECO_AUTOHSCROLL
), "ECO_AUTOHSCROLL is set.\n");
6225 ret
= GetWindowLong(hwnd
, GWL_STYLE
);
6226 ok(!(ret
& ES_AUTOVSCROLL
), "ES_AUTOVSCROLL is set.\n");
6227 ok(!(ret
& ES_AUTOHSCROLL
), "ES_AUTOHSCROLL is set.\n");
6228 DestroyWindow(hwnd
);
6232 static void test_format_rect(void)
6235 RECT rc
, expected
, clientRect
;
6239 hwnd
= CreateWindowEx(0, RICHEDIT_CLASS
, NULL
,
6240 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
6241 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6242 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS
, (int) GetLastError());
6244 GetClientRect(hwnd
, &clientRect
);
6246 expected
= clientRect
;
6248 expected
.right
-= 1;
6249 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6250 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6251 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6252 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6253 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6254 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6256 for (n
= -3; n
<= 3; n
++)
6263 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6266 expected
.top
= max(0, rc
.top
);
6267 expected
.left
= max(0, rc
.left
);
6268 expected
.bottom
= min(clientRect
.bottom
, rc
.bottom
);
6269 expected
.right
= min(clientRect
.right
, rc
.right
);
6270 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6271 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6272 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6273 "[n=%d] rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6274 n
, rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6275 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6279 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6280 expected
= clientRect
;
6281 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6282 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6283 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6284 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6285 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6286 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6288 /* Adding the selectionbar adds the selectionbar width to the left side. */
6289 SendMessageA(hwnd
, EM_SETOPTIONS
, ECOOP_OR
, ECO_SELECTIONBAR
);
6290 options
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
6291 ok(options
& ECO_SELECTIONBAR
, "EM_SETOPTIONS failed to add selectionbar.\n");
6292 expected
.left
+= 8; /* selection bar width */
6293 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6294 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6295 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6296 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6297 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6298 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6301 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6302 expected
= clientRect
;
6303 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6304 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6305 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6306 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6307 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6308 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6310 /* Removing the selectionbar subtracts the selectionbar width from the left side,
6311 * even if the left side is already 0. */
6312 SendMessageA(hwnd
, EM_SETOPTIONS
, ECOOP_AND
, ~ECO_SELECTIONBAR
);
6313 options
= SendMessageA(hwnd
, EM_GETOPTIONS
, 0, 0);
6314 ok(!(options
& ECO_SELECTIONBAR
), "EM_SETOPTIONS failed to remove selectionbar.\n");
6315 expected
.left
-= 8; /* selection bar width */
6316 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6317 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6318 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6319 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6320 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6321 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6323 /* Set the absolute value of the formatting rectangle. */
6325 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6326 expected
= clientRect
;
6327 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6328 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6329 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6330 "[n=%d] rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6331 n
, rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6332 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6334 /* MSDN documents the EM_SETRECT message as using the rectangle provided in
6335 * LPARAM as being a relative offset when the WPARAM value is 1, but these
6336 * tests show that this isn't true. */
6339 rc
.bottom
= clientRect
.bottom
- 15;
6340 rc
.right
= clientRect
.right
- 15;
6342 SendMessageA(hwnd
, EM_SETRECT
, 1, (LPARAM
)&rc
);
6343 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6344 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6345 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6346 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6347 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6348 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6350 /* For some reason it does not limit the values to the client rect with
6351 * a WPARAM value of 1. */
6354 rc
.bottom
= clientRect
.bottom
+ 15;
6355 rc
.right
= clientRect
.right
+ 15;
6357 SendMessageA(hwnd
, EM_SETRECT
, 1, (LPARAM
)&rc
);
6358 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6359 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6360 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6361 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6362 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6363 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6365 /* Reset to default rect and check how the format rect adjusts to window
6366 * resize and how it copes with very small windows */
6367 SendMessageA(hwnd
, EM_SETRECT
, 0, 0);
6369 MoveWindow(hwnd
, 0, 0, 100, 30, FALSE
);
6370 GetClientRect(hwnd
, &clientRect
);
6372 expected
= clientRect
;
6374 expected
.right
-= 1;
6375 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6376 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6377 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6378 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6379 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6380 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6382 MoveWindow(hwnd
, 0, 0, 0, 30, FALSE
);
6383 GetClientRect(hwnd
, &clientRect
);
6385 expected
= clientRect
;
6387 expected
.right
-= 1;
6388 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6389 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6390 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6391 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6392 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6393 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6395 MoveWindow(hwnd
, 0, 0, 100, 0, FALSE
);
6396 GetClientRect(hwnd
, &clientRect
);
6398 expected
= clientRect
;
6400 expected
.right
-= 1;
6401 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6402 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6403 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6404 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6405 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6406 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6408 DestroyWindow(hwnd
);
6410 /* The extended window style affects the formatting rectangle. */
6411 hwnd
= CreateWindowEx(WS_EX_CLIENTEDGE
, RICHEDIT_CLASS
, NULL
,
6412 ES_MULTILINE
|WS_POPUP
|WS_HSCROLL
|WS_VSCROLL
|WS_VISIBLE
,
6413 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6414 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS
, (int) GetLastError());
6416 GetClientRect(hwnd
, &clientRect
);
6418 expected
= clientRect
;
6421 expected
.right
-= 1;
6422 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6423 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6424 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6425 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6426 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6427 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6437 expected
.right
+= 1;
6438 SendMessageA(hwnd
, EM_SETRECT
, 0, (LPARAM
)&rc
);
6439 SendMessageA(hwnd
, EM_GETRECT
, 0, (LPARAM
)&rc
);
6440 ok(rc
.top
== expected
.top
&& rc
.left
== expected
.left
&&
6441 rc
.bottom
== expected
.bottom
&& rc
.right
== expected
.right
,
6442 "rect a(t=%d, l=%d, b=%d, r=%d) != e(t=%d, l=%d, b=%d, r=%d)\n",
6443 rc
.top
, rc
.left
, rc
.bottom
, rc
.right
,
6444 expected
.top
, expected
.left
, expected
.bottom
, expected
.right
);
6446 DestroyWindow(hwnd
);
6449 static void test_WM_GETDLGCODE(void)
6455 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6457 hwnd
= CreateWindowEx(0, RICHEDIT_CLASS
, NULL
,
6458 ES_MULTILINE
|ES_WANTRETURN
|WS_POPUP
,
6459 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6460 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS
, (int) GetLastError());
6462 res
= SendMessage(hwnd
, WM_GETDLGCODE
, VK_RETURN
, 0);
6463 expected
= expected
| DLGC_WANTMESSAGE
;
6464 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6466 DestroyWindow(hwnd
);
6468 msg
.message
= WM_KEYDOWN
;
6469 msg
.wParam
= VK_RETURN
;
6470 msg
.lParam
= (MapVirtualKey(VK_RETURN
, MAPVK_VK_TO_VSC
) << 16) | 0x0001;
6473 msg
.time
= GetTickCount();
6475 hwnd
= CreateWindowEx(0, RICHEDIT_CLASS
, NULL
,
6476 ES_MULTILINE
|ES_WANTRETURN
|WS_POPUP
,
6477 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6478 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS
, (int) GetLastError());
6480 res
= SendMessage(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6481 expected
= expected
| DLGC_WANTMESSAGE
;
6482 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6484 DestroyWindow(hwnd
);
6486 hwnd
= CreateWindowEx(0, RICHEDIT_CLASS
, NULL
,
6487 ES_MULTILINE
|WS_POPUP
,
6488 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6489 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS
, (int) GetLastError());
6491 res
= SendMessage(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6492 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6493 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6495 DestroyWindow(hwnd
);
6497 hwnd
= CreateWindowEx(0, RICHEDIT_CLASS
, NULL
,
6498 ES_WANTRETURN
|WS_POPUP
,
6499 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6500 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS
, (int) GetLastError());
6502 res
= SendMessage(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6503 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6504 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6506 DestroyWindow(hwnd
);
6508 hwnd
= CreateWindowEx(0, RICHEDIT_CLASS
, NULL
,
6510 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6511 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS
, (int) GetLastError());
6513 res
= SendMessage(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6514 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6515 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6517 DestroyWindow(hwnd
);
6519 msg
.wParam
= VK_TAB
;
6520 msg
.lParam
= (MapVirtualKey(VK_TAB
, MAPVK_VK_TO_VSC
) << 16) | 0x0001;
6522 hwnd
= CreateWindowEx(0, RICHEDIT_CLASS
, NULL
,
6523 ES_MULTILINE
|WS_POPUP
,
6524 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6525 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS
, (int) GetLastError());
6527 res
= SendMessage(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6528 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6529 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6531 DestroyWindow(hwnd
);
6533 hwnd
= CreateWindowEx(0, RICHEDIT_CLASS
, NULL
,
6535 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6536 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS
, (int) GetLastError());
6538 res
= SendMessage(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6539 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6540 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6542 DestroyWindow(hwnd
);
6544 hold_key(VK_CONTROL
);
6546 hwnd
= CreateWindowEx(0, RICHEDIT_CLASS
, NULL
,
6547 ES_MULTILINE
|WS_POPUP
,
6548 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6549 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS
, (int) GetLastError());
6551 res
= SendMessage(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6552 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6553 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6555 DestroyWindow(hwnd
);
6557 hwnd
= CreateWindowEx(0, RICHEDIT_CLASS
, NULL
,
6559 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6560 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS
, (int) GetLastError());
6562 res
= SendMessage(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6563 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6564 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6566 DestroyWindow(hwnd
);
6568 release_key(VK_CONTROL
);
6571 msg
.lParam
= (MapVirtualKey('a', MAPVK_VK_TO_VSC
) << 16) | 0x0001;
6573 hwnd
= CreateWindowEx(0, RICHEDIT_CLASS
, NULL
,
6574 ES_MULTILINE
|WS_POPUP
,
6575 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6576 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS
, (int) GetLastError());
6578 res
= SendMessage(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6579 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6580 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6582 DestroyWindow(hwnd
);
6584 hwnd
= CreateWindowEx(0, RICHEDIT_CLASS
, NULL
,
6586 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6587 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS
, (int) GetLastError());
6589 res
= SendMessage(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6590 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6591 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6593 DestroyWindow(hwnd
);
6595 msg
.message
= WM_CHAR
;
6597 hwnd
= CreateWindowEx(0, RICHEDIT_CLASS
, NULL
,
6598 ES_MULTILINE
|WS_POPUP
,
6599 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6600 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS
, (int) GetLastError());
6602 res
= SendMessage(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6603 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
|DLGC_WANTMESSAGE
;
6604 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6606 DestroyWindow(hwnd
);
6608 hwnd
= CreateWindowEx(0, RICHEDIT_CLASS
, NULL
,
6610 0, 0, 200, 60, NULL
, NULL
, hmoduleRichEdit
, NULL
);
6611 ok(hwnd
!= NULL
, "class: %s, error: %d\n", RICHEDIT_CLASS
, (int) GetLastError());
6613 res
= SendMessage(hwnd
, WM_GETDLGCODE
, VK_RETURN
, (LPARAM
)&msg
);
6614 expected
= DLGC_WANTCHARS
|DLGC_WANTTAB
|DLGC_WANTARROWS
|DLGC_HASSETSEL
;
6615 ok(res
== expected
, "WM_GETDLGCODE returned %x but expected %x\n",
6617 DestroyWindow(hwnd
);
6620 static void test_zoom(void)
6626 int numerator
, denominator
;
6628 hwnd
= new_richedit(NULL
);
6629 GetClientRect(hwnd
, &rc
);
6630 pt
.x
= (rc
.right
- rc
.left
) / 2;
6631 pt
.y
= (rc
.bottom
- rc
.top
) / 2;
6632 ClientToScreen(hwnd
, &pt
);
6634 /* Test initial zoom value */
6635 ret
= SendMessage(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6636 ok(numerator
== 0, "Numerator should be initialized to 0 (got %d).\n", numerator
);
6637 ok(denominator
== 0, "Denominator should be initialized to 0 (got %d).\n", denominator
);
6638 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6640 /* test scroll wheel */
6641 hold_key(VK_CONTROL
);
6642 ret
= SendMessage(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
6643 MAKELPARAM(pt
.x
, pt
.y
));
6644 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6645 release_key(VK_CONTROL
);
6647 ret
= SendMessage(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6648 ok(numerator
== 110, "incorrect numerator is %d\n", numerator
);
6649 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6650 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6652 /* Test how much the mouse wheel can zoom in and out. */
6653 ret
= SendMessage(hwnd
, EM_SETZOOM
, 490, 100);
6654 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6656 hold_key(VK_CONTROL
);
6657 ret
= SendMessage(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
6658 MAKELPARAM(pt
.x
, pt
.y
));
6659 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6660 release_key(VK_CONTROL
);
6662 ret
= SendMessage(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6663 ok(numerator
== 500, "incorrect numerator is %d\n", numerator
);
6664 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6665 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6667 ret
= SendMessage(hwnd
, EM_SETZOOM
, 491, 100);
6668 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6670 hold_key(VK_CONTROL
);
6671 ret
= SendMessage(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
6672 MAKELPARAM(pt
.x
, pt
.y
));
6673 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6674 release_key(VK_CONTROL
);
6676 ret
= SendMessage(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6677 ok(numerator
== 491, "incorrect numerator is %d\n", numerator
);
6678 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6679 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6681 ret
= SendMessage(hwnd
, EM_SETZOOM
, 20, 100);
6682 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6684 hold_key(VK_CONTROL
);
6685 ret
= SendMessage(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, -WHEEL_DELTA
),
6686 MAKELPARAM(pt
.x
, pt
.y
));
6687 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6688 release_key(VK_CONTROL
);
6690 ret
= SendMessage(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6691 ok(numerator
== 10, "incorrect numerator is %d\n", numerator
);
6692 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6693 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6695 ret
= SendMessage(hwnd
, EM_SETZOOM
, 19, 100);
6696 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6698 hold_key(VK_CONTROL
);
6699 ret
= SendMessage(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, -WHEEL_DELTA
),
6700 MAKELPARAM(pt
.x
, pt
.y
));
6701 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6702 release_key(VK_CONTROL
);
6704 ret
= SendMessage(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6705 ok(numerator
== 19, "incorrect numerator is %d\n", numerator
);
6706 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6707 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6709 /* Test how WM_SCROLLWHEEL treats our custom denominator. */
6710 ret
= SendMessage(hwnd
, EM_SETZOOM
, 50, 13);
6711 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6713 hold_key(VK_CONTROL
);
6714 ret
= SendMessage(hwnd
, WM_MOUSEWHEEL
, MAKEWPARAM(MK_CONTROL
, WHEEL_DELTA
),
6715 MAKELPARAM(pt
.x
, pt
.y
));
6716 ok(!ret
, "WM_MOUSEWHEEL failed (%d).\n", ret
);
6717 release_key(VK_CONTROL
);
6719 ret
= SendMessage(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6720 ok(numerator
== 394, "incorrect numerator is %d\n", numerator
);
6721 ok(denominator
== 100, "incorrect denominator is %d\n", denominator
);
6722 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6724 /* Test bounds checking on EM_SETZOOM */
6725 ret
= SendMessage(hwnd
, EM_SETZOOM
, 2, 127);
6726 ok(ret
== TRUE
, "EM_SETZOOM rejected valid values (%d).\n", ret
);
6728 ret
= SendMessage(hwnd
, EM_SETZOOM
, 127, 2);
6729 ok(ret
== TRUE
, "EM_SETZOOM rejected valid values (%d).\n", ret
);
6731 ret
= SendMessage(hwnd
, EM_SETZOOM
, 2, 128);
6732 ok(ret
== FALSE
, "EM_SETZOOM accepted invalid values (%d).\n", ret
);
6734 ret
= SendMessage(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6735 ok(numerator
== 127, "incorrect numerator is %d\n", numerator
);
6736 ok(denominator
== 2, "incorrect denominator is %d\n", denominator
);
6737 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6739 ret
= SendMessage(hwnd
, EM_SETZOOM
, 128, 2);
6740 ok(ret
== FALSE
, "EM_SETZOOM accepted invalid values (%d).\n", ret
);
6742 /* See if negative numbers are accepted. */
6743 ret
= SendMessage(hwnd
, EM_SETZOOM
, -100, -100);
6744 ok(ret
== FALSE
, "EM_SETZOOM accepted invalid values (%d).\n", ret
);
6746 /* See if negative numbers are accepted. */
6747 ret
= SendMessage(hwnd
, EM_SETZOOM
, 0, 100);
6748 ok(ret
== FALSE
, "EM_SETZOOM failed (%d).\n", ret
);
6750 ret
= SendMessage(hwnd
, EM_GETZOOM
, (WPARAM
)&numerator
, (LPARAM
)&denominator
);
6751 ok(numerator
== 127, "incorrect numerator is %d\n", numerator
);
6752 ok(denominator
== 2, "incorrect denominator is %d\n", denominator
);
6753 ok(ret
== TRUE
, "EM_GETZOOM failed (%d).\n", ret
);
6755 /* Reset the zoom value */
6756 ret
= SendMessage(hwnd
, EM_SETZOOM
, 0, 0);
6757 ok(ret
== TRUE
, "EM_SETZOOM failed (%d).\n", ret
);
6759 DestroyWindow(hwnd
);
6762 struct dialog_mode_messages
6764 int wm_getdefid
, wm_close
, wm_nextdlgctl
;
6767 static struct dialog_mode_messages dm_messages
;
6769 #define test_dm_messages(wmclose, wmgetdefid, wmnextdlgctl) \
6770 ok(dm_messages.wm_close == wmclose, "expected %d WM_CLOSE message, " \
6771 "got %d\n", wmclose, dm_messages.wm_close); \
6772 ok(dm_messages.wm_getdefid == wmgetdefid, "expected %d WM_GETDIFID message, " \
6773 "got %d\n", wmgetdefid, dm_messages.wm_getdefid);\
6774 ok(dm_messages.wm_nextdlgctl == wmnextdlgctl, "expected %d WM_NEXTDLGCTL message, " \
6775 "got %d\n", wmnextdlgctl, dm_messages.wm_nextdlgctl)
6777 static LRESULT CALLBACK
dialog_mode_wnd_proc(HWND hwnd
, UINT iMsg
, WPARAM wParam
, LPARAM lParam
)
6782 dm_messages
.wm_getdefid
++;
6783 return MAKELONG(ID_RICHEDITTESTDBUTTON
, DC_HASDEFID
);
6785 dm_messages
.wm_nextdlgctl
++;
6788 dm_messages
.wm_close
++;
6792 return DefWindowProc(hwnd
, iMsg
, wParam
, lParam
);
6795 static void test_dialogmode(void)
6797 HWND hwRichEdit
, hwParent
, hwButton
;
6803 cls
.lpfnWndProc
= dialog_mode_wnd_proc
;
6806 cls
.hInstance
= GetModuleHandleA(0);
6808 cls
.hCursor
= LoadCursorA(0, IDC_ARROW
);
6809 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
6810 cls
.lpszMenuName
= NULL
;
6811 cls
.lpszClassName
= "DialogModeParentClass";
6812 if(!RegisterClassA(&cls
)) assert(0);
6814 hwParent
= CreateWindow("DialogModeParentClass", NULL
, WS_OVERLAPPEDWINDOW
,
6815 CW_USEDEFAULT
, 0, 200, 120, NULL
, NULL
, GetModuleHandleA(0), NULL
);
6817 /* Test richedit(ES_MULTILINE) */
6819 hwRichEdit
= new_window(RICHEDIT_CLASS
, ES_MULTILINE
, hwParent
);
6821 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6822 ok(0 == r
, "expected 0, got %d\n", r
);
6823 lcount
= SendMessage(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
6824 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
6826 r
= SendMessage(hwRichEdit
, WM_GETDLGCODE
, 0, 0);
6827 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
6829 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6830 ok(0 == r
, "expected 0, got %d\n", r
);
6831 lcount
= SendMessage(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
6832 ok(3 == lcount
, "expected 3, got %d\n", lcount
);
6834 r
= SendMessage(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
6835 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
6836 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6837 ok(0 == r
, "expected 0, got %d\n", r
);
6838 lcount
= SendMessage(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
6839 ok(3 == lcount
, "expected 3, got %d\n", lcount
);
6841 DestroyWindow(hwRichEdit
);
6843 /* Test standalone richedit(ES_MULTILINE) */
6845 hwRichEdit
= new_window(RICHEDIT_CLASS
, ES_MULTILINE
, NULL
);
6847 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6848 ok(0 == r
, "expected 0, got %d\n", r
);
6849 lcount
= SendMessage(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
6850 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
6852 r
= SendMessage(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
6853 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
6855 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6856 ok(0 == r
, "expected 0, got %d\n", r
);
6857 lcount
= SendMessage(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
6858 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
6860 DestroyWindow(hwRichEdit
);
6862 /* Check a destination for messages */
6864 hwRichEdit
= new_window(RICHEDIT_CLASS
, ES_MULTILINE
, hwParent
);
6866 SetWindowLong(hwRichEdit
, GWL_STYLE
, GetWindowLong(hwRichEdit
, GWL_STYLE
)& ~WS_POPUP
);
6867 SetParent( hwRichEdit
, NULL
);
6869 r
= SendMessage(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
6870 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
6872 memset(&dm_messages
, 0, sizeof(dm_messages
));
6873 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6874 ok(0 == r
, "expected 0, got %d\n", r
);
6875 test_dm_messages(0, 1, 0);
6877 memset(&dm_messages
, 0, sizeof(dm_messages
));
6878 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
6879 ok(0 == r
, "expected 0, got %d\n", r
);
6880 test_dm_messages(0, 0, 1);
6882 DestroyWindow(hwRichEdit
);
6884 /* Check messages from richedit(ES_MULTILINE) */
6886 hwRichEdit
= new_window(RICHEDIT_CLASS
, ES_MULTILINE
, hwParent
);
6888 memset(&dm_messages
, 0, sizeof(dm_messages
));
6889 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6890 ok(0 == r
, "expected 0, got %d\n", r
);
6891 test_dm_messages(0, 0, 0);
6893 lcount
= SendMessage(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
6894 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
6896 memset(&dm_messages
, 0, sizeof(dm_messages
));
6897 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
6898 ok(0 == r
, "expected 0, got %d\n", r
);
6899 test_dm_messages(0, 0, 0);
6901 memset(&dm_messages
, 0, sizeof(dm_messages
));
6902 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
6903 ok(0 == r
, "expected 0, got %d\n", r
);
6904 test_dm_messages(0, 0, 0);
6906 memset(&dm_messages
, 0, sizeof(dm_messages
));
6907 r
= SendMessage(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
6908 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
6909 test_dm_messages(0, 0, 0);
6911 memset(&dm_messages
, 0, sizeof(dm_messages
));
6912 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6913 ok(0 == r
, "expected 0, got %d\n", r
);
6914 test_dm_messages(0, 1, 0);
6916 lcount
= SendMessage(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
6917 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
6919 memset(&dm_messages
, 0, sizeof(dm_messages
));
6920 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
6921 ok(0 == r
, "expected 0, got %d\n", r
);
6922 test_dm_messages(0, 0, 0);
6924 memset(&dm_messages
, 0, sizeof(dm_messages
));
6925 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
6926 ok(0 == r
, "expected 0, got %d\n", r
);
6927 test_dm_messages(0, 0, 1);
6929 hwButton
= CreateWindow("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
6930 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
6931 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
6933 memset(&dm_messages
, 0, sizeof(dm_messages
));
6934 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6935 ok(0 == r
, "expected 0, got %d\n", r
);
6936 test_dm_messages(0, 1, 1);
6938 lcount
= SendMessage(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
6939 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
6941 DestroyWindow(hwButton
);
6942 DestroyWindow(hwRichEdit
);
6944 /* Check messages from richedit(ES_MULTILINE|ES_WANTRETURN) */
6946 hwRichEdit
= new_window(RICHEDIT_CLASS
, ES_MULTILINE
|ES_WANTRETURN
, hwParent
);
6948 memset(&dm_messages
, 0, sizeof(dm_messages
));
6949 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6950 ok(0 == r
, "expected 0, got %d\n", r
);
6951 test_dm_messages(0, 0, 0);
6953 lcount
= SendMessage(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
6954 ok(2 == lcount
, "expected 2, got %d\n", lcount
);
6956 memset(&dm_messages
, 0, sizeof(dm_messages
));
6957 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
6958 ok(0 == r
, "expected 0, got %d\n", r
);
6959 test_dm_messages(0, 0, 0);
6961 memset(&dm_messages
, 0, sizeof(dm_messages
));
6962 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
6963 ok(0 == r
, "expected 0, got %d\n", r
);
6964 test_dm_messages(0, 0, 0);
6966 memset(&dm_messages
, 0, sizeof(dm_messages
));
6967 r
= SendMessage(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
6968 ok(0x8f == r
, "expected 0x8f, got 0x%x\n", r
);
6969 test_dm_messages(0, 0, 0);
6971 memset(&dm_messages
, 0, sizeof(dm_messages
));
6972 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6973 ok(0 == r
, "expected 0, got %d\n", r
);
6974 test_dm_messages(0, 0, 0);
6976 lcount
= SendMessage(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
6977 ok(3 == lcount
, "expected 3, got %d\n", lcount
);
6979 memset(&dm_messages
, 0, sizeof(dm_messages
));
6980 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
6981 ok(0 == r
, "expected 0, got %d\n", r
);
6982 test_dm_messages(0, 0, 0);
6984 memset(&dm_messages
, 0, sizeof(dm_messages
));
6985 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
6986 ok(0 == r
, "expected 0, got %d\n", r
);
6987 test_dm_messages(0, 0, 1);
6989 hwButton
= CreateWindow("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
6990 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
6991 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
6993 memset(&dm_messages
, 0, sizeof(dm_messages
));
6994 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
6995 ok(0 == r
, "expected 0, got %d\n", r
);
6996 test_dm_messages(0, 0, 0);
6998 lcount
= SendMessage(hwRichEdit
, EM_GETLINECOUNT
, 0, 0);
6999 ok(4 == lcount
, "expected 4, got %d\n", lcount
);
7001 DestroyWindow(hwButton
);
7002 DestroyWindow(hwRichEdit
);
7004 /* Check messages from richedit(0) */
7006 hwRichEdit
= new_window(RICHEDIT_CLASS
, 0, hwParent
);
7008 memset(&dm_messages
, 0, sizeof(dm_messages
));
7009 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7010 ok(0 == r
, "expected 0, got %d\n", r
);
7011 test_dm_messages(0, 0, 0);
7013 memset(&dm_messages
, 0, sizeof(dm_messages
));
7014 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7015 ok(0 == r
, "expected 0, got %d\n", r
);
7016 test_dm_messages(0, 0, 0);
7018 memset(&dm_messages
, 0, sizeof(dm_messages
));
7019 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7020 ok(0 == r
, "expected 0, got %d\n", r
);
7021 test_dm_messages(0, 0, 0);
7023 memset(&dm_messages
, 0, sizeof(dm_messages
));
7024 r
= SendMessage(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7025 ok(0x8b == r
, "expected 0x8b, got 0x%x\n", r
);
7026 test_dm_messages(0, 0, 0);
7028 memset(&dm_messages
, 0, sizeof(dm_messages
));
7029 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7030 ok(0 == r
, "expected 0, got %d\n", r
);
7031 test_dm_messages(0, 1, 0);
7033 memset(&dm_messages
, 0, sizeof(dm_messages
));
7034 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_ESCAPE
, 0x10001);
7035 ok(0 == r
, "expected 0, got %d\n", r
);
7036 test_dm_messages(0, 0, 0);
7038 memset(&dm_messages
, 0, sizeof(dm_messages
));
7039 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_TAB
, 0xf0001);
7040 ok(0 == r
, "expected 0, got %d\n", r
);
7041 test_dm_messages(0, 0, 1);
7043 hwButton
= CreateWindow("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
7044 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
7045 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
7047 memset(&dm_messages
, 0, sizeof(dm_messages
));
7048 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7049 ok(0 == r
, "expected 0, got %d\n", r
);
7050 test_dm_messages(0, 1, 1);
7052 DestroyWindow(hwRichEdit
);
7054 /* Check messages from richedit(ES_WANTRETURN) */
7056 hwRichEdit
= new_window(RICHEDIT_CLASS
, ES_WANTRETURN
, hwParent
);
7058 memset(&dm_messages
, 0, sizeof(dm_messages
));
7059 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7060 ok(0 == r
, "expected 0, got %d\n", r
);
7061 test_dm_messages(0, 0, 0);
7063 memset(&dm_messages
, 0, sizeof(dm_messages
));
7064 r
= SendMessage(hwRichEdit
, WM_GETDLGCODE
, 0, (LPARAM
)&msg
);
7065 ok(0x8b == r
, "expected 0x8b, got 0x%x\n", r
);
7066 test_dm_messages(0, 0, 0);
7068 memset(&dm_messages
, 0, sizeof(dm_messages
));
7069 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7070 ok(0 == r
, "expected 0, got %d\n", r
);
7071 test_dm_messages(0, 0, 0);
7073 hwButton
= CreateWindow("BUTTON", "OK", WS_VISIBLE
|WS_CHILD
|BS_PUSHBUTTON
,
7074 100, 100, 50, 20, hwParent
, (HMENU
)ID_RICHEDITTESTDBUTTON
, GetModuleHandleA(0), NULL
);
7075 ok(hwButton
!=NULL
, "CreateWindow failed with error code %d\n", GetLastError());
7077 memset(&dm_messages
, 0, sizeof(dm_messages
));
7078 r
= SendMessage(hwRichEdit
, WM_KEYDOWN
, VK_RETURN
, 0x1c0001);
7079 ok(0 == r
, "expected 0, got %d\n", r
);
7080 test_dm_messages(0, 0, 0);
7082 DestroyWindow(hwRichEdit
);
7083 DestroyWindow(hwParent
);
7086 static void test_EM_FINDWORDBREAK_W(void)
7088 static const struct {
7090 BOOL isdelimiter
; /* expected result of WB_ISDELIMITER */
7091 } delimiter_tests
[] = {
7092 {0x0a, FALSE
}, /* newline */
7093 {0x0b, FALSE
}, /* vertical tab */
7094 {0x0c, FALSE
}, /* form feed */
7095 {0x0d, FALSE
}, /* carriage return */
7096 {0x20, TRUE
}, /* space */
7097 {0x61, FALSE
}, /* capital letter a */
7098 {0xa0, FALSE
}, /* no-break space */
7099 {0x2000, FALSE
}, /* en quad */
7100 {0x3000, FALSE
}, /* Ideographic space */
7101 {0x1100, FALSE
}, /* Hangul Choseong Kiyeok (G sound) Ordinary Letter*/
7102 {0x11ff, FALSE
}, /* Hangul Jongseoung Kiyeok-Hieuh (Hard N sound) Ordinary Letter*/
7103 {0x115f, FALSE
}, /* Hangul Choseong Filler (no sound, used with two letter Hangul words) Ordinary Letter */
7104 {0xac00, FALSE
}, /* Hangul character GA*/
7105 {0xd7af, FALSE
}, /* End of Hangul character chart */
7106 {0xf020, TRUE
}, /* MS private for CP_SYMBOL round trip?, see kb897872 */
7107 {0xff20, FALSE
}, /* fullwidth commercial @ */
7108 {WCH_EMBEDDING
, FALSE
}, /* object replacement character*/
7111 HWND hwndRichEdit
= new_richeditW(NULL
);
7112 ok(IsWindowUnicode(hwndRichEdit
), "window should be unicode\n");
7113 for (i
= 0; i
< sizeof(delimiter_tests
)/sizeof(delimiter_tests
[0]); i
++)
7118 wbuf
[0] = delimiter_tests
[i
].c
;
7120 SendMessageW(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)wbuf
);
7121 result
= SendMessageW(hwndRichEdit
, EM_FINDWORDBREAK
, WB_ISDELIMITER
,0);
7122 if (wbuf
[0] == 0x20 || wbuf
[0] == 0xf020)
7124 ok(result
== delimiter_tests
[i
].isdelimiter
,
7125 "wanted ISDELIMITER_W(0x%x) %d, got %d\n",
7126 delimiter_tests
[i
].c
, delimiter_tests
[i
].isdelimiter
,result
);
7128 ok(result
== delimiter_tests
[i
].isdelimiter
,
7129 "wanted ISDELIMITER_W(0x%x) %d, got %d\n",
7130 delimiter_tests
[i
].c
, delimiter_tests
[i
].isdelimiter
, result
);
7132 DestroyWindow(hwndRichEdit
);
7135 static void test_EM_FINDWORDBREAK_A(void)
7137 static const struct {
7139 BOOL isdelimiter
; /* expected result of WB_ISDELIMITER */
7140 } delimiter_tests
[] = {
7141 {0x0a, FALSE
}, /* newline */
7142 {0x0b, FALSE
}, /* vertical tab */
7143 {0x0c, FALSE
}, /* form feed */
7144 {0x0d, FALSE
}, /* carriage return */
7145 {0x20, TRUE
}, /* space */
7146 {0x61, FALSE
}, /* capital letter a */
7149 HWND hwndRichEdit
= new_richedit(NULL
);
7151 ok(!IsWindowUnicode(hwndRichEdit
), "window should not be unicode\n");
7152 for (i
= 0; i
< sizeof(delimiter_tests
)/sizeof(delimiter_tests
[0]); i
++)
7156 buf
[0] = delimiter_tests
[i
].c
;
7158 SendMessageW(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
)buf
);
7159 result
= SendMessage(hwndRichEdit
, EM_FINDWORDBREAK
, WB_ISDELIMITER
, 0);
7162 ok(result
== delimiter_tests
[i
].isdelimiter
,
7163 "wanted ISDELIMITER_A(0x%x) %d, got %d\n",
7164 delimiter_tests
[i
].c
, delimiter_tests
[i
].isdelimiter
,result
);
7166 ok(result
== delimiter_tests
[i
].isdelimiter
,
7167 "wanted ISDELIMITER_A(0x%x) %d, got %d\n",
7168 delimiter_tests
[i
].c
, delimiter_tests
[i
].isdelimiter
, result
);
7170 DestroyWindow(hwndRichEdit
);
7174 * This test attempts to show the effect of enter on a richedit
7175 * control v1.0 inserts CRLF whereas for higher versions it only
7176 * inserts CR. If shows that EM_GETTEXTEX with GT_USECRLF == WM_GETTEXT
7177 * and also shows that GT_USECRLF has no effect in richedit 1.0, but
7178 * does for higher. The same test is cloned in riched32 and riched20.
7180 static void test_enter(void)
7182 static const struct {
7183 const char *initialtext
;
7185 const char *expectedwmtext
;
7186 const char *expectedemtext
;
7187 const char *expectedemtextcrlf
;
7188 } testenteritems
[] = {
7189 { "aaabbb\r\n", 3, "aaa\r\nbbb\r\n", "aaa\rbbb\r", "aaa\r\nbbb\r\n"},
7190 { "aaabbb\r\n", 6, "aaabbb\r\n\r\n", "aaabbb\r\r", "aaabbb\r\n\r\n"},
7191 { "aa\rabbb\r\n", 7, "aa\r\nabbb\r\n\r\n", "aa\rabbb\r\r", "aa\r\nabbb\r\n\r\n"},
7192 { "aa\rabbb\r\n", 3, "aa\r\n\r\nabbb\r\n", "aa\r\rabbb\r", "aa\r\n\r\nabbb\r\n"},
7193 { "aa\rabbb\r\n", 2, "aa\r\n\r\nabbb\r\n", "aa\r\rabbb\r", "aa\r\n\r\nabbb\r\n"}
7196 char expectedbuf
[1024];
7197 char resultbuf
[1024];
7198 HWND hwndRichEdit
= new_richedit(NULL
);
7201 for (i
= 0; i
< sizeof(testenteritems
)/sizeof(testenteritems
[0]); i
++) {
7203 char buf
[1024] = {0};
7206 const char *expected
;
7208 /* Set the text to the initial text */
7209 result
= SendMessage(hwndRichEdit
, WM_SETTEXT
, 0, (LPARAM
) testenteritems
[i
].initialtext
);
7210 ok (result
== 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i
, result
);
7213 SendMessage(hwndRichEdit
, EM_SETSEL
, testenteritems
[i
].cursor
, testenteritems
[i
].cursor
);
7214 simulate_typing_characters(hwndRichEdit
, "\r");
7216 /* 1. Retrieve with WM_GETTEXT */
7218 result
= SendMessage(hwndRichEdit
, WM_GETTEXT
, 1024, (LPARAM
) buf
);
7219 expected
= testenteritems
[i
].expectedwmtext
;
7222 for (j
= 0; j
< (UINT
)result
; j
++)
7223 sprintf(resultbuf
+strlen(resultbuf
), "%02x", buf
[j
] & 0xFF);
7224 expectedbuf
[0] = '\0';
7225 for (j
= 0; j
< strlen(expected
); j
++)
7226 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", expected
[j
] & 0xFF);
7228 result
= strcmp(expected
, buf
);
7230 "[%d] WM_GETTEXT unexpected '%s' expected '%s'\n",
7231 i
, resultbuf
, expectedbuf
);
7233 /* 2. Retrieve with EM_GETTEXTEX, GT_DEFAULT */
7234 getText
.cb
= sizeof(buf
);
7235 getText
.flags
= GT_DEFAULT
;
7236 getText
.codepage
= CP_ACP
;
7237 getText
.lpDefaultChar
= NULL
;
7238 getText
.lpUsedDefChar
= NULL
;
7240 result
= SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buf
);
7241 expected
= testenteritems
[i
].expectedemtext
;
7244 for (j
= 0; j
< (UINT
)result
; j
++)
7245 sprintf(resultbuf
+strlen(resultbuf
), "%02x", buf
[j
] & 0xFF);
7246 expectedbuf
[0] = '\0';
7247 for (j
= 0; j
< strlen(expected
); j
++)
7248 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", expected
[j
] & 0xFF);
7250 result
= strcmp(expected
, buf
);
7252 "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n",
7253 i
, resultbuf
, expectedbuf
);
7255 /* 3. Retrieve with EM_GETTEXTEX, GT_USECRLF */
7256 getText
.cb
= sizeof(buf
);
7257 getText
.flags
= GT_USECRLF
;
7258 getText
.codepage
= CP_ACP
;
7259 getText
.lpDefaultChar
= NULL
;
7260 getText
.lpUsedDefChar
= NULL
;
7262 result
= SendMessage(hwndRichEdit
, EM_GETTEXTEX
, (WPARAM
)&getText
, (LPARAM
) buf
);
7263 expected
= testenteritems
[i
].expectedemtextcrlf
;
7266 for (j
= 0; j
< (UINT
)result
; j
++)
7267 sprintf(resultbuf
+strlen(resultbuf
), "%02x", buf
[j
] & 0xFF);
7268 expectedbuf
[0] = '\0';
7269 for (j
= 0; j
< strlen(expected
); j
++)
7270 sprintf(expectedbuf
+strlen(expectedbuf
), "%02x", expected
[j
] & 0xFF);
7272 result
= strcmp(expected
, buf
);
7274 "[%d] EM_GETTEXTEX, GT_USECRLF unexpected '%s', expected '%s'\n",
7275 i
, resultbuf
, expectedbuf
);
7278 DestroyWindow(hwndRichEdit
);
7281 START_TEST( editor
)
7284 /* Must explicitly LoadLibrary(). The test has no references to functions in
7285 * RICHED20.DLL, so the linker doesn't actually link to it. */
7286 hmoduleRichEdit
= LoadLibrary("RICHED20.DLL");
7287 ok(hmoduleRichEdit
!= NULL
, "error: %d\n", (int) GetLastError());
7292 test_EM_POSFROMCHAR();
7293 test_EM_SCROLLCARET();
7295 test_scrollbar_visibility();
7297 test_EM_LINELENGTH();
7298 test_EM_SETCHARFORMAT();
7299 test_EM_SETTEXTMODE();
7300 test_TM_PLAINTEXT();
7301 test_EM_SETOPTIONS();
7303 test_EM_GETTEXTRANGE();
7304 test_EM_GETSELTEXT();
7305 test_EM_SETUNDOLIMIT();
7307 test_EM_SETTEXTEX();
7308 test_EM_LIMITTEXT();
7309 test_EM_EXLIMITTEXT();
7310 test_EM_GETLIMITTEXT();
7312 test_EM_GETMODIFY();
7316 test_EM_STREAMOUT();
7317 test_EM_STREAMOUT_FONTTBL();
7318 test_EM_StreamIn_Undo();
7319 test_EM_FORMATRANGE();
7320 test_unicode_conversions();
7321 test_EM_GETTEXTLENGTHEX();
7322 test_EM_REPLACESEL(1);
7323 test_EM_REPLACESEL(0);
7325 test_EM_AUTOURLDETECT();
7327 test_undo_coalescing();
7328 test_word_movement();
7329 test_EM_CHARFROMPOS();
7330 test_SETPARAFORMAT();
7334 test_WM_GETDLGCODE();
7337 test_EM_FINDWORDBREAK_W();
7338 test_EM_FINDWORDBREAK_A();
7341 /* Set the environment variable WINETEST_RICHED20 to keep windows
7342 * responsive and open for 30 seconds. This is useful for debugging.
7344 if (getenv( "WINETEST_RICHED20" )) {
7345 keep_responsive(30);
7348 OleFlushClipboard();
7349 ret
= FreeLibrary(hmoduleRichEdit
);
7350 ok(ret
, "error: %d\n", (int) GetLastError());