ReactOS 0.4.15-dev-7788-g1ad9096
editor.c
Go to the documentation of this file.
1/*
2* Unit test suite for rich edit control
3*
4* Copyright 2006 Google (Thomas Kho)
5* Copyright 2007 Matt Finnicum
6* Copyright 2007 Dmitry Timoshkov
7*
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.
12*
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.
17*
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
21*/
22
23#define COBJMACROS
24
25#include <stdarg.h>
26#include <stdio.h>
27#include <assert.h>
28#include <windef.h>
29#include <winbase.h>
30#include <wingdi.h>
31#include <winuser.h>
32#include <winnls.h>
33#include <ole2.h>
34#include <richedit.h>
35#include <richole.h>
36#include <commdlg.h>
37#include <time.h>
38#include <wine/test.h>
39
40#define ID_RICHEDITTESTDBUTTON 0x123
41
43
44#define ok_w3(format, szString1, szString2, szString3) \
45 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
46 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
47 WideCharToMultiByte(CP_ACP, 0, szString3, -1, string3, MAX_PATH, NULL, NULL); \
48 ok(!lstrcmpW(szString3, szString1) || !lstrcmpW(szString3, szString2), \
49 format, string1, string2, string3);
50
53
54static HWND new_window(LPCSTR lpClassName, DWORD dwStyle, HWND parent) {
55 HWND hwnd;
56 hwnd = CreateWindowA(lpClassName, NULL, dwStyle|WS_POPUP|WS_HSCROLL|WS_VSCROLL
57 |WS_VISIBLE, 0, 0, 200, 60, parent, NULL,
59 ok(hwnd != NULL, "class: %s, error: %d\n", lpClassName, (int) GetLastError());
60 return hwnd;
61}
62
63static HWND new_windowW(LPCWSTR lpClassName, DWORD dwStyle, HWND parent) {
64 HWND hwnd;
65 hwnd = CreateWindowW(lpClassName, NULL, dwStyle|WS_POPUP|WS_HSCROLL|WS_VSCROLL
66 |WS_VISIBLE, 0, 0, 200, 60, parent, NULL,
68 ok(hwnd != NULL, "class: %s, error: %d\n", wine_dbgstr_w(lpClassName), (int) GetLastError());
69 return hwnd;
70}
71
74}
75
78}
79
82}
83
84/* Keeps the window reponsive for the deley_time in seconds.
85 * This is useful for debugging a test to see what is happening. */
86static void keep_responsive(time_t delay_time)
87{
88 MSG msg;
89 time_t end;
90
91 /* The message pump uses PeekMessage() to empty the queue and then
92 * sleeps for 50ms before retrying the queue. */
93 end = time(NULL) + delay_time;
94 while (time(NULL) < end) {
95 if (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
98 } else {
99 Sleep(50);
100 }
101 }
102}
103
104static void simulate_typing_characters(HWND hwnd, const char* szChars)
105{
106 int ret;
107
108 while (*szChars != '\0') {
109 SendMessageA(hwnd, WM_KEYDOWN, *szChars, 1);
110 ret = SendMessageA(hwnd, WM_CHAR, *szChars, 1);
111 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *szChars, ret);
112 SendMessageA(hwnd, WM_KEYUP, *szChars, 1);
113 szChars++;
114 }
115}
116
117static BOOL hold_key(int vk)
118{
119 BYTE key_state[256];
120 BOOL result;
121
122 result = GetKeyboardState(key_state);
123 ok(result, "GetKeyboardState failed.\n");
124 if (!result) return FALSE;
125 key_state[vk] |= 0x80;
126 result = SetKeyboardState(key_state);
127 ok(result, "SetKeyboardState failed.\n");
128 return result != 0;
129}
130
131static BOOL release_key(int vk)
132{
133 BYTE key_state[256];
134 BOOL result;
135
136 result = GetKeyboardState(key_state);
137 ok(result, "GetKeyboardState failed.\n");
138 if (!result) return FALSE;
139 key_state[vk] &= ~0x80;
140 result = SetKeyboardState(key_state);
141 ok(result, "SetKeyboardState failed.\n");
142 return result != 0;
143}
144
145static const char haystack[] = "WINEWine wineWine wine WineWine";
146 /* ^0 ^10 ^20 ^30 */
147
148struct find_s {
149 int start;
150 int end;
151 const char *needle;
152 int flags;
154};
155
156
157static struct find_s find_tests[] = {
158 /* Find in empty text */
159 {0, -1, "foo", FR_DOWN, -1},
160 {0, -1, "foo", 0, -1},
161 {0, -1, "", FR_DOWN, -1},
162 {20, 5, "foo", FR_DOWN, -1},
163 {5, 20, "foo", FR_DOWN, -1}
164};
165
166static struct find_s find_tests2[] = {
167 /* No-result find */
168 {0, -1, "foo", FR_DOWN | FR_MATCHCASE, -1},
169 {5, 20, "WINE", FR_DOWN | FR_MATCHCASE, -1},
170
171 /* Subsequent finds */
172 {0, -1, "Wine", FR_DOWN | FR_MATCHCASE, 4},
173 {5, 31, "Wine", FR_DOWN | FR_MATCHCASE, 13},
174 {14, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23},
175 {24, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27},
176
177 /* Find backwards */
178 {19, 20, "Wine", FR_MATCHCASE, 13},
179 {10, 20, "Wine", FR_MATCHCASE, 4},
180 {20, 10, "Wine", FR_MATCHCASE, 13},
181
182 /* Case-insensitive */
183 {1, 31, "wInE", FR_DOWN, 4},
184 {1, 31, "Wine", FR_DOWN, 4},
185
186 /* High-to-low ranges */
187 {20, 5, "Wine", FR_DOWN, -1},
188 {2, 1, "Wine", FR_DOWN, -1},
189 {30, 29, "Wine", FR_DOWN, -1},
190 {20, 5, "Wine", 0, 13},
191
192 /* Find nothing */
193 {5, 10, "", FR_DOWN, -1},
194 {10, 5, "", FR_DOWN, -1},
195 {0, -1, "", FR_DOWN, -1},
196 {10, 5, "", 0, -1},
197
198 /* Whole-word search */
199 {0, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18},
200 {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1},
201 {13, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18},
202 {0, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 0},
203 {10, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 23},
204 {11, -1, "winewine", FR_WHOLEWORD, 0},
205 {31, -1, "winewine", FR_WHOLEWORD, 23},
206
207 /* Bad ranges */
208 {5, 200, "XXX", FR_DOWN, -1},
209 {-20, 20, "Wine", FR_DOWN, -1},
210 {-20, 20, "Wine", FR_DOWN, -1},
211 {-15, -20, "Wine", FR_DOWN, -1},
212 {1<<12, 1<<13, "Wine", FR_DOWN, -1},
213
214 /* Check the case noted in bug 4479 where matches at end aren't recognized */
215 {23, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23},
216 {27, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27},
217 {27, 32, "Wine", FR_DOWN | FR_MATCHCASE, 27},
218 {13, 31, "WineWine", FR_DOWN | FR_MATCHCASE, 23},
219 {13, 32, "WineWine", FR_DOWN | FR_MATCHCASE, 23},
220
221 /* The backwards case of bug 4479; bounds look right
222 * Fails because backward find is wrong */
223 {19, 20, "WINE", FR_MATCHCASE, 0},
224 {0, 20, "WINE", FR_MATCHCASE, -1},
225
226 {0, -1, "wineWine wine", 0, -1},
227};
228
229static WCHAR *atowstr(const char *str)
230{
231 WCHAR *ret;
232 DWORD len;
233 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
234 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
236 return ret;
237}
238
239static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id, BOOL unicode)
240{
241 int findloc;
242
243 if(unicode){
244 FINDTEXTW ftw;
245 memset(&ftw, 0, sizeof(ftw));
246 ftw.chrg.cpMin = f->start;
247 ftw.chrg.cpMax = f->end;
248 ftw.lpstrText = atowstr(f->needle);
249
250 findloc = SendMessageA(hwnd, EM_FINDTEXT, f->flags, (LPARAM)&ftw);
251 ok(findloc == f->expected_loc,
252 "EM_FINDTEXT(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
253 name, id, unicode, f->needle, f->start, f->end, f->flags, findloc, f->expected_loc);
254
255 findloc = SendMessageA(hwnd, EM_FINDTEXTW, f->flags, (LPARAM)&ftw);
256 ok(findloc == f->expected_loc,
257 "EM_FINDTEXTW(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
258 name, id, unicode, f->needle, f->start, f->end, f->flags, findloc, f->expected_loc);
259
260 HeapFree(GetProcessHeap(), 0, (void*)ftw.lpstrText);
261 }else{
262 FINDTEXTA fta;
263 memset(&fta, 0, sizeof(fta));
264 fta.chrg.cpMin = f->start;
265 fta.chrg.cpMax = f->end;
266 fta.lpstrText = f->needle;
267
268 findloc = SendMessageA(hwnd, EM_FINDTEXT, f->flags, (LPARAM)&fta);
269 ok(findloc == f->expected_loc,
270 "EM_FINDTEXT(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
271 name, id, unicode, f->needle, f->start, f->end, f->flags, findloc, f->expected_loc);
272 }
273}
274
275static void check_EM_FINDTEXTEX(HWND hwnd, const char *name, struct find_s *f,
276 int id, BOOL unicode)
277{
278 int findloc;
279 int expected_end_loc;
280
281 if(unicode){
282 FINDTEXTEXW ftw;
283 memset(&ftw, 0, sizeof(ftw));
284 ftw.chrg.cpMin = f->start;
285 ftw.chrg.cpMax = f->end;
286 ftw.lpstrText = atowstr(f->needle);
287 findloc = SendMessageA(hwnd, EM_FINDTEXTEX, f->flags, (LPARAM)&ftw);
288 ok(findloc == f->expected_loc,
289 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
290 name, id, f->needle, f->start, f->end, f->flags, findloc);
291 ok(ftw.chrgText.cpMin == f->expected_loc,
292 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
293 name, id, f->needle, f->start, f->end, f->flags, ftw.chrgText.cpMin);
294 expected_end_loc = ((f->expected_loc == -1) ? -1
295 : f->expected_loc + strlen(f->needle));
296 ok(ftw.chrgText.cpMax == expected_end_loc,
297 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n",
298 name, id, f->needle, f->start, f->end, f->flags, ftw.chrgText.cpMax, expected_end_loc);
299 HeapFree(GetProcessHeap(), 0, (void*)ftw.lpstrText);
300 }else{
301 FINDTEXTEXA fta;
302 memset(&fta, 0, sizeof(fta));
303 fta.chrg.cpMin = f->start;
304 fta.chrg.cpMax = f->end;
305 fta.lpstrText = f->needle;
306 findloc = SendMessageA(hwnd, EM_FINDTEXTEX, f->flags, (LPARAM)&fta);
307 ok(findloc == f->expected_loc,
308 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
309 name, id, f->needle, f->start, f->end, f->flags, findloc);
310 ok(fta.chrgText.cpMin == f->expected_loc,
311 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
312 name, id, f->needle, f->start, f->end, f->flags, fta.chrgText.cpMin);
313 expected_end_loc = ((f->expected_loc == -1) ? -1
314 : f->expected_loc + strlen(f->needle));
315 ok(fta.chrgText.cpMax == expected_end_loc,
316 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n",
317 name, id, f->needle, f->start, f->end, f->flags, fta.chrgText.cpMax, expected_end_loc);
318 }
319}
320
321static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *find,
322 int num_tests, BOOL unicode)
323{
324 int i;
325
326 for (i = 0; i < num_tests; i++) {
327 check_EM_FINDTEXT(hwnd, name, &find[i], i, unicode);
328 check_EM_FINDTEXTEX(hwnd, name, &find[i], i, unicode);
329 }
330}
331
332static void test_EM_FINDTEXT(BOOL unicode)
333{
334 HWND hwndRichEdit;
335 CHARFORMAT2A cf2;
336
337 if(unicode)
338 hwndRichEdit = new_richeditW(NULL);
339 else
340 hwndRichEdit = new_richedit(NULL);
341
342 /* Empty rich edit control */
343 run_tests_EM_FINDTEXT(hwndRichEdit, "1", find_tests, ARRAY_SIZE(find_tests), unicode);
344
345 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)haystack);
346
347 /* Haystack text */
348 run_tests_EM_FINDTEXT(hwndRichEdit, "2", find_tests2, ARRAY_SIZE(find_tests2), unicode);
349
350 /* Setting a format on an arbitrary range should have no effect in search
351 results. This tests correct offset reporting across runs. */
352 cf2.cbSize = sizeof(CHARFORMAT2A);
353 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2);
354 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
355 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
356 SendMessageA(hwndRichEdit, EM_SETSEL, 6, 20);
357 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
358
359 /* Haystack text, again */
360 run_tests_EM_FINDTEXT(hwndRichEdit, "2-bis", find_tests2, ARRAY_SIZE(find_tests2), unicode);
361
362 /* Yet another range */
363 cf2.dwMask = CFM_BOLD | cf2.dwMask;
364 cf2.dwEffects = CFE_BOLD ^ cf2.dwEffects;
365 SendMessageA(hwndRichEdit, EM_SETSEL, 11, 15);
366 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
367
368 /* Haystack text, again */
369 run_tests_EM_FINDTEXT(hwndRichEdit, "2-bisbis", find_tests2, ARRAY_SIZE(find_tests2), unicode);
370
371 DestroyWindow(hwndRichEdit);
372}
373
374static const struct getline_s {
375 int line;
377 const char *text;
378} gl[] = {
379 {0, 10, "foo bar\r"},
380 {1, 10, "\r"},
381 {2, 10, "bar\r"},
382 {3, 10, "\r"},
383
384 /* Buffer smaller than line length */
385 {0, 2, "foo bar\r"},
386 {0, 1, "foo bar\r"},
387 {0, 0, "foo bar\r"}
389
390static void test_EM_GETLINE(void)
391{
392 int i;
393 HWND hwndRichEdit = new_richedit(NULL);
394 static const int nBuf = 1024;
395 char dest[1024], origdest[1024];
396 const char text[] = "foo bar\n"
397 "\n"
398 "bar\n";
399
400 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
401
402 memset(origdest, 0xBB, nBuf);
403 for (i = 0; i < ARRAY_SIZE(gl); i++)
404 {
405 int nCopied;
406 int expected_nCopied = min(gl[i].buffer_len, strlen(gl[i].text));
407 int expected_bytes_written = min(gl[i].buffer_len, strlen(gl[i].text));
408 memset(dest, 0xBB, nBuf);
409 *(WORD *) dest = gl[i].buffer_len;
410
411 /* EM_GETLINE appends a "\r\0" to the end of the line
412 * nCopied counts up to and including the '\r' */
413 nCopied = SendMessageA(hwndRichEdit, EM_GETLINE, gl[i].line, (LPARAM)dest);
414 ok(nCopied == expected_nCopied, "%d: %d!=%d\n", i, nCopied,
415 expected_nCopied);
416 /* two special cases since a parameter is passed via dest */
417 if (gl[i].buffer_len == 0)
418 ok(!dest[0] && !dest[1] && !strncmp(dest+2, origdest+2, nBuf-2),
419 "buffer_len=0\n");
420 else if (gl[i].buffer_len == 1)
421 ok(dest[0] == gl[i].text[0] && !dest[1] &&
422 !strncmp(dest+2, origdest+2, nBuf-2), "buffer_len=1\n");
423 else
424 {
425 /* Prepare hex strings of buffers to dump on failure. */
426 char expectedbuf[1024];
427 char resultbuf[1024];
428 int j;
429 resultbuf[0] = '\0';
430 for (j = 0; j < 32; j++)
431 sprintf(resultbuf+strlen(resultbuf), "%02x", dest[j] & 0xFF);
432 expectedbuf[0] = '\0';
433 for (j = 0; j < expected_bytes_written; j++) /* Written bytes */
434 sprintf(expectedbuf+strlen(expectedbuf), "%02x", gl[i].text[j] & 0xFF);
435 for (; j < gl[i].buffer_len; j++) /* Ignored bytes */
436 sprintf(expectedbuf+strlen(expectedbuf), "??");
437 for (; j < 32; j++) /* Bytes after declared buffer size */
438 sprintf(expectedbuf+strlen(expectedbuf), "%02x", origdest[j] & 0xFF);
439
440 /* Test the part of the buffer that is expected to be written according
441 * to the MSDN documentation fo EM_GETLINE, which does not state that
442 * a NULL terminating character will be added unless no text is copied.
443 *
444 * Windows NT does not append a NULL terminating character, but
445 * Windows 2000 and up do append a NULL terminating character if there
446 * is space in the buffer. The test will ignore this difference. */
447 ok(!strncmp(dest, gl[i].text, expected_bytes_written),
448 "%d: expected_bytes_written=%d\n" "expected=0x%s\n" "but got= 0x%s\n",
449 i, expected_bytes_written, expectedbuf, resultbuf);
450 /* Test the part of the buffer after the declared length to make sure
451 * there are no buffer overruns. */
452 ok(!strncmp(dest + gl[i].buffer_len, origdest + gl[i].buffer_len,
453 nBuf - gl[i].buffer_len),
454 "%d: expected_bytes_written=%d\n" "expected=0x%s\n" "but got= 0x%s\n",
455 i, expected_bytes_written, expectedbuf, resultbuf);
456 }
457 }
458
459 DestroyWindow(hwndRichEdit);
460}
461
462static void test_EM_LINELENGTH(void)
463{
464 HWND hwndRichEdit = new_richedit(NULL);
465 const char * text =
466 "richedit1\r"
467 "richedit1\n"
468 "richedit1\r\n"
469 "richedit1";
470 int offset_test[10][2] = {
471 {0, 9},
472 {5, 9},
473 {10, 9},
474 {15, 9},
475 {20, 9},
476 {25, 9},
477 {30, 9},
478 {35, 9},
479 {40, 0},
480 {45, 0},
481 };
482 int i;
484
485 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
486
487 for (i = 0; i < 10; i++) {
488 result = SendMessageA(hwndRichEdit, EM_LINELENGTH, offset_test[i][0], 0);
489 ok(result == offset_test[i][1], "Length of line at offset %d is %ld, expected %d\n",
490 offset_test[i][0], result, offset_test[i][1]);
491 }
492
493 /* Test with multibyte character */
494 if (!is_lang_japanese)
495 skip("Skip multibyte character tests on non-Japanese platform\n");
496 else
497 {
498 const char *text1 =
499 "wine\n"
500 "richedit\x8e\xf0\n"
501 "wine";
502 int offset_test1[3][2] = {
503 {0, 4}, /* Line 1: |wine\n */
504 {5, 9}, /* Line 2: |richedit\x8e\xf0\n */
505 {15, 4}, /* Line 3: |wine */
506 };
507 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
508 for (i = 0; i < ARRAY_SIZE(offset_test1); i++) {
509 result = SendMessageA(hwndRichEdit, EM_LINELENGTH, offset_test1[i][0], 0);
510 ok(result == offset_test1[i][1], "Length of line at offset %d is %ld, expected %d\n",
511 offset_test1[i][0], result, offset_test1[i][1]);
512 }
513 }
514
515 DestroyWindow(hwndRichEdit);
516}
517
519{
520 POINT p = {-1, -1};
522 ok(p.x != -1 && p.y != -1, "p.x:%d p.y:%d\n", p.x, p.y);
523 return p.y;
524}
525
526static void move_cursor(HWND hwnd, LONG charindex)
527{
528 CHARRANGE cr;
529 cr.cpMax = charindex;
530 cr.cpMin = charindex;
532}
533
534static void line_scroll(HWND hwnd, int amount)
535{
536 SendMessageA(hwnd, EM_LINESCROLL, 0, amount);
537}
538
539static void test_EM_SCROLLCARET(void)
540{
541 int prevY, curY;
542 const char text[] = "aa\n"
543 "this is a long line of text that should be longer than the "
544 "control's width\n"
545 "cc\n"
546 "dd\n"
547 "ee\n"
548 "ff\n"
549 "gg\n"
550 "hh\n";
551 /* The richedit window height needs to be large enough vertically to fit in
552 * more than two lines of text, so the new_richedit function can't be used
553 * since a height of 60 was not large enough on some systems.
554 */
557 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
558 ok(hwndRichEdit != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
559
560 /* Can't verify this */
561 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0);
562
563 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
564
565 /* Caret above visible window */
566 line_scroll(hwndRichEdit, 3);
567 prevY = get_scroll_pos_y(hwndRichEdit);
568 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0);
569 curY = get_scroll_pos_y(hwndRichEdit);
570 ok(prevY != curY, "%d == %d\n", prevY, curY);
571
572 /* Caret below visible window */
573 move_cursor(hwndRichEdit, sizeof(text) - 1);
574 line_scroll(hwndRichEdit, -3);
575 prevY = get_scroll_pos_y(hwndRichEdit);
576 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0);
577 curY = get_scroll_pos_y(hwndRichEdit);
578 ok(prevY != curY, "%d == %d\n", prevY, curY);
579
580 /* Caret in visible window */
581 move_cursor(hwndRichEdit, sizeof(text) - 2);
582 prevY = get_scroll_pos_y(hwndRichEdit);
583 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0);
584 curY = get_scroll_pos_y(hwndRichEdit);
585 ok(prevY == curY, "%d != %d\n", prevY, curY);
586
587 /* Caret still in visible window */
588 line_scroll(hwndRichEdit, -1);
589 prevY = get_scroll_pos_y(hwndRichEdit);
590 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0);
591 curY = get_scroll_pos_y(hwndRichEdit);
592 ok(prevY == curY, "%d != %d\n", prevY, curY);
593
594 DestroyWindow(hwndRichEdit);
595}
596
597static void test_EM_POSFROMCHAR(void)
598{
599 HWND hwndRichEdit = new_richedit(NULL);
600 int i, expected;
602 unsigned int height = 0;
603 int xpos = 0;
604 POINTL pt;
605 LOCALESIGNATURE sig;
606 BOOL rtl;
608 static const char text[] = "aa\n"
609 "this is a long line of text that should be longer than the "
610 "control's width\n"
611 "cc\n"
612 "dd\n"
613 "ee\n"
614 "ff\n"
615 "gg\n"
616 "hh\n";
617
619 (LPSTR) &sig, sizeof(LOCALESIGNATURE)) &&
620 (sig.lsUsb[3] & 0x08000000) != 0);
621
622 /* Fill the control to lines to ensure that most of them are offscreen */
623 for (i = 0; i < 50; i++)
624 {
625 /* Do not modify the string; it is exactly 16 characters long. */
626 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 0);
627 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"0123456789ABCDE\n");
628 }
629
630 /*
631 Richedit 1.0 receives a POINTL* on wParam and character offset on lParam, returns void.
632 Richedit 2.0 receives character offset on wParam, ignores lParam, returns MAKELONG(x,y)
633 Richedit 3.0 accepts either of the above API conventions.
634 */
635
636 /* Testing Richedit 2.0 API format */
637
638 /* Testing start of lines. X-offset should be constant on all cases (native is 1).
639 Since all lines are identical and drawn with the same font,
640 they should have the same height... right?
641 */
642 for (i = 0; i < 50; i++)
643 {
644 /* All the lines are 16 characters long */
645 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, i * 16, 0);
646 if (i == 0)
647 {
648 ok(HIWORD(result) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result));
649 ok(LOWORD(result) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
650 xpos = LOWORD(result);
651 }
652 else if (i == 1)
653 {
654 ok(HIWORD(result) > 0, "EM_POSFROMCHAR reports y=%d, expected > 0\n", HIWORD(result));
655 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
657 }
658 else
659 {
661 ok(HIWORD(result) == i * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), i * height);
662 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
663 }
664 }
665
666 /* Testing position at end of text */
667 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 50 * 16, 0);
668 ok(HIWORD(result) == 50 * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), 50 * height);
669 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
670
671 /* Testing position way past end of text */
672 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 55 * 16, 0);
673 ok(HIWORD(result) == 50 * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), 50 * height);
674 expected = (rtl ? 8 : 1);
675 ok(LOWORD(result) == expected, "EM_POSFROMCHAR reports x=%d, expected %d\n", LOWORD(result), expected);
676
677 /* Testing that vertical scrolling does, in fact, have an effect on EM_POSFROMCHAR */
678 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */
679 for (i = 0; i < 50; i++)
680 {
681 /* All the lines are 16 characters long */
682 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, i * 16, 0);
683 ok((signed short)(HIWORD(result)) == (i - 1) * height,
684 "EM_POSFROMCHAR reports y=%hd, expected %d\n",
685 (signed short)(HIWORD(result)), (i - 1) * height);
686 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
687 }
688
689 /* Testing position at end of text */
690 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 50 * 16, 0);
691 ok(HIWORD(result) == (50 - 1) * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), (50 - 1) * height);
692 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
693
694 /* Testing position way past end of text */
695 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 55 * 16, 0);
696 ok(HIWORD(result) == (50 - 1) * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), (50 - 1) * height);
697 expected = (rtl ? 8 : 1);
698 ok(LOWORD(result) == expected, "EM_POSFROMCHAR reports x=%d, expected %d\n", LOWORD(result), expected);
699
700 /* Testing that horizontal scrolling does, in fact, have an effect on EM_POSFROMCHAR */
701 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
702 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */
703
704 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 0, 0);
705 ok(HIWORD(result) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result));
706 ok(LOWORD(result) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
707 xpos = LOWORD(result);
708
709 SendMessageA(hwndRichEdit, WM_HSCROLL, SB_LINERIGHT, 0);
710 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 0, 0);
711 ok(HIWORD(result) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result));
712 ok((signed short)(LOWORD(result)) < xpos,
713 "EM_POSFROMCHAR reports x=%hd, expected value less than %d\n",
714 (signed short)(LOWORD(result)), xpos);
715 SendMessageA(hwndRichEdit, WM_HSCROLL, SB_LINELEFT, 0);
716
717 /* Test around end of text that doesn't end in a newline. */
718 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"12345678901234");
719 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt,
720 SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0)-1);
721 ok(pt.x > 1, "pt.x = %d\n", pt.x);
722 xpos = pt.x;
723 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt,
724 SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0));
725 ok(pt.x > xpos, "pt.x = %d\n", pt.x);
726 xpos = (rtl ? pt.x + 7 : pt.x);
727 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt,
728 SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0)+1);
729 ok(pt.x == xpos, "pt.x = %d\n", pt.x);
730
731 /* Try a negative position. */
732 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt, -1);
733 ok(pt.x == 1, "pt.x = %d\n", pt.x);
734
735 /* test negative indentation */
736 SendMessageA(hwndRichEdit, WM_SETTEXT, 0,
737 (LPARAM)"{\\rtf1\\pard\\fi-200\\li-200\\f1 TestSomeText\\par}");
738 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt, 0);
739 ok(pt.x == 1, "pt.x = %d\n", pt.x);
740
741 fmt.cbSize = sizeof(fmt);
742 SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt);
743 ok(fmt.dxStartIndent == -400, "got %d\n", fmt.dxStartIndent);
744 ok(fmt.dxOffset == 200, "got %d\n", fmt.dxOffset);
745 ok(fmt.wAlignment == PFA_LEFT, "got %d\n", fmt.wAlignment);
746
747 DestroyWindow(hwndRichEdit);
748}
749
750static void test_EM_SETCHARFORMAT(void)
751{
752 HWND hwndRichEdit = new_richedit(NULL);
753 CHARFORMAT2A cf2;
754 CHARFORMAT2W cfW;
755 CHARFORMATA cf1a;
756 CHARFORMATW cf1w;
757 int rc = 0;
758 int tested_effects[] = {
759 CFE_BOLD,
764 CFE_LINK,
767 0
768 };
769 int i;
770 CHARRANGE cr;
771 LOCALESIGNATURE sig;
772 BOOL rtl;
773 DWORD expect_effects;
774
776 (LPSTR) &sig, sizeof(LOCALESIGNATURE)) &&
777 (sig.lsUsb[3] & 0x08000000) != 0);
778
779 /* check charformat defaults */
780 memset(&cf2, 0, sizeof(CHARFORMAT2A));
781 cf2.cbSize = sizeof(CHARFORMAT2A);
782 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
783 ok(cf2.dwMask == CFM_ALL2, "got %08x\n", cf2.dwMask);
784 expect_effects = CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR;
785 if (cf2.wWeight > 550) expect_effects |= CFE_BOLD;
786 ok(cf2.dwEffects == expect_effects, "got %08x\n", cf2.dwEffects);
787 ok(cf2.yOffset == 0, "got %d\n", cf2.yOffset);
788 ok(cf2.sSpacing == 0, "got %d\n", cf2.sSpacing);
789 ok(cf2.lcid == GetSystemDefaultLCID(), "got %x\n", cf2.lcid);
790 ok(cf2.sStyle == 0, "got %d\n", cf2.sStyle);
791 ok(cf2.wKerning == 0, "got %d\n", cf2.wKerning);
792 ok(cf2.bAnimation == 0, "got %d\n", cf2.bAnimation);
793 ok(cf2.bRevAuthor == 0, "got %d\n", cf2.bRevAuthor);
794
795 /* Invalid flags, CHARFORMAT2 structure blanked out */
796 memset(&cf2, 0, sizeof(cf2));
797 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)0xfffffff0, (LPARAM)&cf2);
798 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
799
800 /* A valid flag, CHARFORMAT2 structure blanked out */
801 memset(&cf2, 0, sizeof(cf2));
802 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2);
803 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
804
805 /* A valid flag, CHARFORMAT2 structure blanked out */
806 memset(&cf2, 0, sizeof(cf2));
807 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2);
808 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
809
810 /* A valid flag, CHARFORMAT2 structure blanked out */
811 memset(&cf2, 0, sizeof(cf2));
812 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_WORD, (LPARAM)&cf2);
813 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
814
815 /* A valid flag, CHARFORMAT2 structure blanked out */
816 memset(&cf2, 0, sizeof(cf2));
817 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2);
818 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
819
820 /* Invalid flags, CHARFORMAT2 structure minimally filled */
821 memset(&cf2, 0, sizeof(cf2));
822 cf2.cbSize = sizeof(CHARFORMAT2A);
823 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)0xfffffff0, (LPARAM)&cf2);
824 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
825 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
826 ok(rc == FALSE, "Should not be able to undo here.\n");
827 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0);
828
829 /* A valid flag, CHARFORMAT2 structure minimally filled */
830 memset(&cf2, 0, sizeof(cf2));
831 cf2.cbSize = sizeof(CHARFORMAT2A);
832 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2);
833 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
834 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
835 ok(rc == FALSE, "Should not be able to undo here.\n");
836 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0);
837
838 /* A valid flag, CHARFORMAT2 structure minimally filled */
839 memset(&cf2, 0, sizeof(cf2));
840 cf2.cbSize = sizeof(CHARFORMAT2A);
841 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2);
842 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
843 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
844 ok(rc == FALSE, "Should not be able to undo here.\n");
845 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0);
846
847 /* A valid flag, CHARFORMAT2 structure minimally filled */
848 memset(&cf2, 0, sizeof(cf2));
849 cf2.cbSize = sizeof(CHARFORMAT2A);
850 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_WORD, (LPARAM)&cf2);
851 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
852 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
853 todo_wine ok(rc == TRUE, "Should not be able to undo here.\n");
854 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0);
855
856 /* A valid flag, CHARFORMAT2 structure minimally filled */
857 memset(&cf2, 0, sizeof(cf2));
858 cf2.cbSize = sizeof(CHARFORMAT2A);
859 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2);
860 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
861 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
862 ok(rc == TRUE, "Should not be able to undo here.\n");
863 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0);
864
865 cf2.cbSize = sizeof(CHARFORMAT2A);
866 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2);
867
868 /* Test state of modify flag before and after valid EM_SETCHARFORMAT */
869 cf2.cbSize = sizeof(CHARFORMAT2A);
870 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2);
871 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
872 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
873
874 /* wParam==0 is default char format, does not set modify */
875 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
876 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
877 ok(rc == 0, "Text marked as modified, expected not modified!\n");
878 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, 0, (LPARAM)&cf2);
879 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
880 if (! rtl)
881 {
882 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
883 ok(rc == 0, "Text marked as modified, expected not modified!\n");
884 }
885 else
886 skip("RTL language found\n");
887
888 /* wParam==SCF_SELECTION sets modify if nonempty selection */
889 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
890 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
891 ok(rc == 0, "Text marked as modified, expected not modified!\n");
892 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
893 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
894 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
895 ok(rc == 0, "Text marked as modified, expected not modified!\n");
896
897 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
898 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
899 ok(rc == 0, "Text marked as modified, expected not modified!\n");
900 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
901 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
902 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
903 ok(rc == 0, "Text marked as modified, expected not modified!\n");
904 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2);
905 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
906 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
907 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
908 ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc);
909
910 /* wParam==SCF_ALL sets modify regardless of whether text is present */
911 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
912 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
913 ok(rc == 0, "Text marked as modified, expected not modified!\n");
914 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2);
915 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
916 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
917 ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc);
918
919 DestroyWindow(hwndRichEdit);
920
921 /* EM_GETCHARFORMAT tests */
922 for (i = 0; tested_effects[i]; i++)
923 {
924 hwndRichEdit = new_richedit(NULL);
925 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
926
927 /* Need to set a TrueType font to get consistent CFM_BOLD results */
928 memset(&cf2, 0, sizeof(CHARFORMAT2A));
929 cf2.cbSize = sizeof(CHARFORMAT2A);
931 cf2.dwEffects = 0;
932 strcpy(cf2.szFaceName, "Courier New");
933 cf2.wWeight = FW_DONTCARE;
934 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2);
935
936 memset(&cf2, 0, sizeof(CHARFORMAT2A));
937 cf2.cbSize = sizeof(CHARFORMAT2A);
938 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 4);
939 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
940 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
941 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
942 ||
943 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
944 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
945 ok((cf2.dwEffects & tested_effects[i]) == 0,
946 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i, cf2.dwEffects, tested_effects[i]);
947
948 memset(&cf2, 0, sizeof(CHARFORMAT2A));
949 cf2.cbSize = sizeof(CHARFORMAT2A);
950 cf2.dwMask = tested_effects[i];
951 if (cf2.dwMask == CFE_SUBSCRIPT || cf2.dwMask == CFE_SUPERSCRIPT)
952 cf2.dwMask = CFM_SUPERSCRIPT;
953 cf2.dwEffects = tested_effects[i];
954 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2);
955 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
956
957 memset(&cf2, 0, sizeof(CHARFORMAT2A));
958 cf2.cbSize = sizeof(CHARFORMAT2A);
959 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2);
960 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
961 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
962 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
963 ||
964 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
965 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
966 ok((cf2.dwEffects & tested_effects[i]) == tested_effects[i],
967 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, tested_effects[i]);
968
969 memset(&cf2, 0, sizeof(CHARFORMAT2A));
970 cf2.cbSize = sizeof(CHARFORMAT2A);
971 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 4);
972 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
973 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
974 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
975 ||
976 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
977 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
978 ok((cf2.dwEffects & tested_effects[i]) == 0,
979 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i, cf2.dwEffects, tested_effects[i]);
980
981 memset(&cf2, 0, sizeof(CHARFORMAT2A));
982 cf2.cbSize = sizeof(CHARFORMAT2A);
983 SendMessageA(hwndRichEdit, EM_SETSEL, 1, 3);
984 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
985 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
986 (cf2.dwMask & CFM_SUPERSCRIPT) == 0)
987 ||
988 (cf2.dwMask & tested_effects[i]) == 0),
989 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i, cf2.dwMask, tested_effects[i]);
990
991 DestroyWindow(hwndRichEdit);
992 }
993
994 for (i = 0; tested_effects[i]; i++)
995 {
996 hwndRichEdit = new_richedit(NULL);
997 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
998
999 /* Need to set a TrueType font to get consistent CFM_BOLD results */
1000 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1001 cf2.cbSize = sizeof(CHARFORMAT2A);
1003 cf2.dwEffects = 0;
1004 strcpy(cf2.szFaceName, "Courier New");
1005 cf2.wWeight = FW_DONTCARE;
1006 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2);
1007
1008 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1009 cf2.cbSize = sizeof(CHARFORMAT2A);
1010 cf2.dwMask = tested_effects[i];
1011 if (cf2.dwMask == CFE_SUBSCRIPT || cf2.dwMask == CFE_SUPERSCRIPT)
1012 cf2.dwMask = CFM_SUPERSCRIPT;
1013 cf2.dwEffects = tested_effects[i];
1014 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 4);
1015 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1016
1017 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1018 cf2.cbSize = sizeof(CHARFORMAT2A);
1019 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2);
1020 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1021 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
1022 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
1023 ||
1024 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
1025 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
1026 ok((cf2.dwEffects & tested_effects[i]) == 0,
1027 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i, cf2.dwEffects, tested_effects[i]);
1028
1029 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1030 cf2.cbSize = sizeof(CHARFORMAT2A);
1031 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 4);
1032 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1033 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
1034 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
1035 ||
1036 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
1037 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
1038 ok((cf2.dwEffects & tested_effects[i]) == tested_effects[i],
1039 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, tested_effects[i]);
1040
1041 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1042 cf2.cbSize = sizeof(CHARFORMAT2A);
1043 SendMessageA(hwndRichEdit, EM_SETSEL, 1, 3);
1044 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1045 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
1046 (cf2.dwMask & CFM_SUPERSCRIPT) == 0)
1047 ||
1048 (cf2.dwMask & tested_effects[i]) == 0),
1049 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i, cf2.dwMask, tested_effects[i]);
1050 ok((cf2.dwEffects & tested_effects[i]) == tested_effects[i],
1051 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x set\n", i, cf2.dwEffects, tested_effects[i]);
1052
1053 DestroyWindow(hwndRichEdit);
1054 }
1055
1056 /* Effects applied on an empty selection should take effect when selection is
1057 replaced with text */
1058 hwndRichEdit = new_richedit(NULL);
1059 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1060 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */
1061
1062 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1063 cf2.cbSize = sizeof(CHARFORMAT2A);
1064 cf2.dwMask = CFM_BOLD;
1065 cf2.dwEffects = CFE_BOLD;
1066 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1067
1068 /* Selection is now nonempty */
1069 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi");
1070
1071 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1072 cf2.cbSize = sizeof(CHARFORMAT2A);
1073 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 6);
1074 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1075
1076 ok (((cf2.dwMask & CFM_BOLD) == CFM_BOLD),
1077 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD);
1078 ok((cf2.dwEffects & CFE_BOLD) == CFE_BOLD,
1079 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD);
1080
1081
1082 /* Set two effects on an empty selection */
1083 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1084 /* first clear bold, italic */
1085 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
1086 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1087 cf2.cbSize = sizeof(CHARFORMAT2A);
1088 cf2.dwMask = CFM_BOLD | CFM_ITALIC;
1089 cf2.dwEffects = 0;
1090 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1091
1092 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */
1093
1094 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1095 cf2.cbSize = sizeof(CHARFORMAT2A);
1096 cf2.dwMask = CFM_BOLD;
1097 cf2.dwEffects = CFE_BOLD;
1098 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1099 cf2.dwMask = CFM_ITALIC;
1100 cf2.dwEffects = CFE_ITALIC;
1101 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1102
1103 /* Selection is now nonempty */
1104 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi");
1105
1106 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1107 cf2.cbSize = sizeof(CHARFORMAT2A);
1108 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 6);
1109 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1110
1111 ok (((cf2.dwMask & (CFM_BOLD|CFM_ITALIC)) == (CFM_BOLD|CFM_ITALIC)),
1112 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, (CFM_BOLD|CFM_ITALIC));
1114 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, (CFE_BOLD|CFE_ITALIC));
1115
1116 /* Setting the (empty) selection to exactly the same place as before should
1117 NOT clear the insertion style! */
1118 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1119 /* first clear bold, italic */
1120 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
1121 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1122 cf2.cbSize = sizeof(CHARFORMAT2A);
1123 cf2.dwMask = CFM_BOLD | CFM_ITALIC;
1124 cf2.dwEffects = 0;
1125 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1126
1127 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */
1128
1129 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1130 cf2.cbSize = sizeof(CHARFORMAT2A);
1131 cf2.dwMask = CFM_BOLD;
1132 cf2.dwEffects = CFE_BOLD;
1133 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1134
1135 /* Empty selection in same place, insert style should NOT be forgotten here. */
1136 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2);
1137
1138 /* Selection is now nonempty */
1139 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi");
1140
1141 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1142 cf2.cbSize = sizeof(CHARFORMAT2A);
1143 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 6);
1144 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1145
1146 ok (((cf2.dwMask & CFM_BOLD) == CFM_BOLD),
1147 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD);
1148 ok((cf2.dwEffects & CFE_BOLD) == CFE_BOLD,
1149 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD);
1150
1151 /* Moving the selection will clear the insertion style */
1152 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1153 /* first clear bold, italic */
1154 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
1155 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1156 cf2.cbSize = sizeof(CHARFORMAT2A);
1157 cf2.dwMask = CFM_BOLD | CFM_ITALIC;
1158 cf2.dwEffects = 0;
1159 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1160
1161 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */
1162
1163 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1164 cf2.cbSize = sizeof(CHARFORMAT2A);
1165 cf2.dwMask = CFM_BOLD;
1166 cf2.dwEffects = CFE_BOLD;
1167 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1168
1169 /* Move selection and then put it back, insert style should be forgotten here. */
1170 SendMessageA(hwndRichEdit, EM_SETSEL, 3, 3);
1171 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */
1172
1173 /* Selection is now nonempty */
1174 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi");
1175
1176 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1177 cf2.cbSize = sizeof(CHARFORMAT2A);
1178 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 6);
1179 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1180
1181 ok(((cf2.dwMask & CFM_BOLD) == CFM_BOLD),
1182 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD);
1183 ok((cf2.dwEffects & CFE_BOLD) == 0,
1184 "%d, cf2.dwEffects == 0x%08x not expecting effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD);
1185
1186 /* Ditto with EM_EXSETSEL */
1187 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1188 /* first clear bold, italic */
1189 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
1190 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1191 cf2.cbSize = sizeof(CHARFORMAT2A);
1192 cf2.dwMask = CFM_BOLD | CFM_ITALIC;
1193 cf2.dwEffects = 0;
1194 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1195
1196 cr.cpMin = 2; cr.cpMax = 2;
1197 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); /* Empty selection */
1198
1199 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1200 cf2.cbSize = sizeof(CHARFORMAT2A);
1201 cf2.dwMask = CFM_BOLD;
1202 cf2.dwEffects = CFE_BOLD;
1203 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1204
1205 /* Empty selection in same place, insert style should NOT be forgotten here. */
1206 cr.cpMin = 2; cr.cpMax = 2;
1207 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); /* Empty selection */
1208
1209 /* Selection is now nonempty */
1210 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi");
1211
1212 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1213 cf2.cbSize = sizeof(CHARFORMAT2A);
1214 cr.cpMin = 2; cr.cpMax = 6;
1215 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); /* Empty selection */
1216 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1217
1218 ok (((cf2.dwMask & CFM_BOLD) == CFM_BOLD),
1219 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD);
1220 ok((cf2.dwEffects & CFE_BOLD) == CFE_BOLD,
1221 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD);
1222
1223 /* show that wWeight is at the correct offset in CHARFORMAT2A */
1224 memset(&cf2, 0, sizeof(cf2));
1225 cf2.cbSize = sizeof(cf2);
1226 cf2.dwMask = CFM_WEIGHT;
1227 cf2.wWeight = 100;
1228 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1229 memset(&cf2, 0, sizeof(cf2));
1230 cf2.cbSize = sizeof(cf2);
1231 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1232 ok(cf2.wWeight == 100, "got %d\n", cf2.wWeight);
1233
1234 memset(&cf2, 0, sizeof(cf2));
1235 cf2.cbSize = sizeof(cf2);
1236 cf2.dwMask = CFM_SPACING;
1237 cf2.sSpacing = 10;
1238 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1239 memset(&cf2, 0, sizeof(cf2));
1240 cf2.cbSize = sizeof(cf2);
1241 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1242 ok(cf2.sSpacing == 10, "got %d\n", cf2.sSpacing);
1243
1244 /* show that wWeight is at the correct offset in CHARFORMAT2W */
1245 memset(&cfW, 0, sizeof(cfW));
1246 cfW.cbSize = sizeof(cfW);
1247 cfW.dwMask = CFM_WEIGHT;
1248 cfW.wWeight = 100;
1249 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfW);
1250 memset(&cfW, 0, sizeof(cfW));
1251 cfW.cbSize = sizeof(cfW);
1252 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfW);
1253 ok(cfW.wWeight == 100, "got %d\n", cfW.wWeight);
1254
1255 memset(&cfW, 0, sizeof(cfW));
1256 cfW.cbSize = sizeof(cfW);
1257 cfW.dwMask = CFM_SPACING;
1258 cfW.sSpacing = 10;
1259 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfW);
1260 memset(&cfW, 0, sizeof(cfW));
1261 cfW.cbSize = sizeof(cfW);
1262 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfW);
1263 ok(cfW.sSpacing == 10, "got %d\n", cfW.sSpacing);
1264
1265 /* test CFE_UNDERLINE and bUnderlineType interaction */
1266 /* clear bold, italic */
1267 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
1268 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1269 cf2.cbSize = sizeof(CHARFORMAT2A);
1270 cf2.dwMask = CFM_BOLD | CFM_ITALIC;
1271 cf2.dwEffects = 0;
1272 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1273
1274 /* check CFE_UNDERLINE is clear and bUnderlineType is CFU_UNDERLINE */
1275 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1276 cf2.cbSize = sizeof(CHARFORMAT2A);
1277 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1279 "got %08x\n", cf2.dwMask);
1280 ok(!(cf2.dwEffects & CFE_UNDERLINE), "got %08x\n", cf2.dwEffects);
1281 ok(cf2.bUnderlineType == CFU_UNDERLINE, "got %x\n", cf2.bUnderlineType);
1282
1283 /* simply touching bUnderlineType will toggle CFE_UNDERLINE */
1286 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1287 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1288 cf2.cbSize = sizeof(CHARFORMAT2A);
1289 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1291 "got %08x\n", cf2.dwMask);
1292 ok(cf2.dwEffects & CFE_UNDERLINE, "got %08x\n", cf2.dwEffects);
1293 ok(cf2.bUnderlineType == CFU_UNDERLINE, "got %x\n", cf2.bUnderlineType);
1294
1295 /* setting bUnderline to CFU_UNDERLINENONE clears CFE_UNDERLINE */
1298 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1299 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1300 cf2.cbSize = sizeof(CHARFORMAT2A);
1301 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1303 "got %08x\n", cf2.dwMask);
1304 ok(!(cf2.dwEffects & CFE_UNDERLINE), "got %08x\n", cf2.dwEffects);
1305 ok(cf2.bUnderlineType == CFU_UNDERLINENONE, "got %x\n", cf2.bUnderlineType);
1306
1307 /* another underline type also sets CFE_UNDERLINE */
1310 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1311 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1312 cf2.cbSize = sizeof(CHARFORMAT2A);
1313 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1315 "got %08x\n", cf2.dwMask);
1316 ok(cf2.dwEffects & CFE_UNDERLINE, "got %08x\n", cf2.dwEffects);
1317 ok(cf2.bUnderlineType == CFU_UNDERLINEDOUBLE, "got %x\n", cf2.bUnderlineType);
1318
1319 /* However explicitly clearing CFE_UNDERLINE results in it remaining cleared */
1322 cf2.dwEffects = 0;
1323 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1324 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1325 cf2.cbSize = sizeof(CHARFORMAT2A);
1326 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1328 "got %08x\n", cf2.dwMask);
1329 ok(!(cf2.dwEffects & CFE_UNDERLINE), "got %08x\n", cf2.dwEffects);
1330 ok(cf2.bUnderlineType == CFU_UNDERLINEDOUBLE, "got %x\n", cf2.bUnderlineType);
1331
1332 /* And turing it back on again by just setting CFE_UNDERLINE */
1333 cf2.dwMask = CFM_UNDERLINE;
1335 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1336 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1337 cf2.cbSize = sizeof(CHARFORMAT2A);
1338 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1340 "got %08x\n", cf2.dwMask);
1341 ok(cf2.dwEffects & CFE_UNDERLINE, "got %08x\n", cf2.dwEffects);
1342 ok(cf2.bUnderlineType == CFU_UNDERLINEDOUBLE, "got %x\n", cf2.bUnderlineType);
1343
1344 /* Check setting CFM_ALL2/CFM_EFFECTS2 in CHARFORMAT(A/W). */
1345 memset(&cf1a, 0, sizeof(CHARFORMATA));
1346 memset(&cf1w, 0, sizeof(CHARFORMATW));
1347 cf1a.cbSize = sizeof(CHARFORMATA);
1348 cf1w.cbSize = sizeof(CHARFORMATW);
1349 cf1a.dwMask = cf1w.dwMask = CFM_ALL2;
1350 cf1a.dwEffects = cf1w.dwEffects = CFM_EFFECTS2;
1351 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf1a);
1352 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf1a);
1353 /* flags only valid for CHARFORMAT2 should be masked out */
1354 ok((cf1a.dwMask & (CFM_ALL2 & ~CFM_ALL)) == 0, "flags were not masked out\n");
1355 ok((cf1a.dwEffects & (CFM_EFFECTS2 & ~CFM_EFFECTS)) == 0, "flags were not masked out\n");
1356 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf1w);
1357 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf1w);
1358 ok((cf1w.dwMask & (CFM_ALL2 & ~CFM_ALL)) == 0, "flags were not masked out\n");
1359 ok((cf1w.dwEffects & (CFM_EFFECTS2 & ~CFM_EFFECTS)) == 0, "flags were not masked out\n");
1360
1361 DestroyWindow(hwndRichEdit);
1362}
1363
1364static void test_EM_SETTEXTMODE(void)
1365{
1366 HWND hwndRichEdit = new_richedit(NULL);
1367 CHARFORMAT2A cf2, cf2test;
1368 CHARRANGE cr;
1369 int rc = 0;
1370
1371 /*Attempt to use mutually exclusive modes*/
1373 ok(rc == E_INVALIDARG,
1374 "EM_SETTEXTMODE: using mutually exclusive mode flags - returned: %x\n", rc);
1375
1376 /*Test that EM_SETTEXTMODE fails if text exists within the control*/
1377 /*Insert text into the control*/
1378
1379 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1380
1381 /*Attempt to change the control to plain text mode*/
1382 rc = SendMessageA(hwndRichEdit, EM_SETTEXTMODE, (WPARAM)TM_PLAINTEXT, 0);
1383 ok(rc == E_UNEXPECTED,
1384 "EM_SETTEXTMODE: changed text mode in control containing text - returned: %x\n", rc);
1385
1386 /*Test that EM_SETTEXTMODE does not allow rich edit text to be pasted.
1387 If rich text is pasted, it should have the same formatting as the rest
1388 of the text in the control*/
1389
1390 /*Italicize the text
1391 *NOTE: If the default text was already italicized, the test will simply
1392 reverse; in other words, it will copy a regular "wine" into a plain
1393 text window that uses an italicized format*/
1394 cf2.cbSize = sizeof(CHARFORMAT2A);
1395 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2);
1396
1397 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
1398 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
1399
1400 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
1401 ok(rc == 0, "Text marked as modified, expected not modified!\n");
1402
1403 /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine;
1404 however, SCF_ALL has been implemented*/
1405 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2);
1406 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
1407
1408 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
1409 ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc);
1410
1411 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1412
1413 /*Select the string "wine"*/
1414 cr.cpMin = 0;
1415 cr.cpMax = 4;
1416 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1417
1418 /*Copy the italicized "wine" to the clipboard*/
1419 SendMessageA(hwndRichEdit, WM_COPY, 0, 0);
1420
1421 /*Reset the formatting to default*/
1422 cf2.dwEffects = CFE_ITALIC^cf2.dwEffects;
1423 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2);
1424 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
1425
1426 /*Clear the text in the control*/
1427 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
1428
1429 /*Switch to Plain Text Mode*/
1430 rc = SendMessageA(hwndRichEdit, EM_SETTEXTMODE, (WPARAM)TM_PLAINTEXT, 0);
1431 ok(rc == 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control: returned: %d\n", rc);
1432
1433 /*Input "wine" again in normal format*/
1434 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1435
1436 /*Paste the italicized "wine" into the control*/
1437 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
1438
1439 /*Select a character from the first "wine" string*/
1440 cr.cpMin = 2;
1441 cr.cpMax = 3;
1442 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1443
1444 /*Retrieve its formatting*/
1446
1447 /*Select a character from the second "wine" string*/
1448 cr.cpMin = 5;
1449 cr.cpMax = 6;
1450 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1451
1452 /*Retrieve its formatting*/
1453 cf2test.cbSize = sizeof(CHARFORMAT2A);
1454 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2test);
1455
1456 /*Compare the two formattings*/
1457 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
1458 "two formats found in plain text mode - cf2.dwEffects: %x cf2test.dwEffects: %x\n",
1459 cf2.dwEffects, cf2test.dwEffects);
1460 /*Test TM_RICHTEXT by: switching back to Rich Text mode
1461 printing "wine" in the current format(normal)
1462 pasting "wine" from the clipboard(italicized)
1463 comparing the two formats(should differ)*/
1464
1465 /*Attempt to switch with text in control*/
1466 rc = SendMessageA(hwndRichEdit, EM_SETTEXTMODE, (WPARAM)TM_RICHTEXT, 0);
1467 ok(rc != 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc);
1468
1469 /*Clear control*/
1470 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
1471
1472 /*Switch into Rich Text mode*/
1473 rc = SendMessageA(hwndRichEdit, EM_SETTEXTMODE, (WPARAM)TM_RICHTEXT, 0);
1474 ok(rc == 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc);
1475
1476 /*Print "wine" in normal formatting into the control*/
1477 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1478
1479 /*Paste italicized "wine" into the control*/
1480 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
1481
1482 /*Select text from the first "wine" string*/
1483 cr.cpMin = 1;
1484 cr.cpMax = 3;
1485 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1486
1487 /*Retrieve its formatting*/
1489
1490 /*Select text from the second "wine" string*/
1491 cr.cpMin = 6;
1492 cr.cpMax = 7;
1493 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1494
1495 /*Retrieve its formatting*/
1496 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2test);
1497
1498 /*Test that the two formattings are not the same*/
1499 todo_wine ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects != cf2test.dwEffects),
1500 "expected different formats - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1501 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
1502
1503 DestroyWindow(hwndRichEdit);
1504}
1505
1506static void test_SETPARAFORMAT(void)
1507{
1508 HWND hwndRichEdit = new_richedit(NULL);
1510 HRESULT ret;
1511 LONG expectedMask = PFM_ALL2 & ~PFM_TABLEROWDELIMITER;
1512 fmt.cbSize = sizeof(PARAFORMAT2);
1513 fmt.dwMask = PFM_ALIGNMENT;
1514 fmt.wAlignment = PFA_LEFT;
1515
1516 ret = SendMessageA(hwndRichEdit, EM_SETPARAFORMAT, 0, (LPARAM)&fmt);
1517 ok(ret != 0, "expected non-zero got %d\n", ret);
1518
1519 fmt.cbSize = sizeof(PARAFORMAT2);
1520 fmt.dwMask = -1;
1521 ret = SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt);
1522 /* Ignore the PFM_TABLEROWDELIMITER bit because it changes
1523 * between richedit different native builds of riched20.dll
1524 * used on different Windows versions. */
1525 ret &= ~PFM_TABLEROWDELIMITER;
1526 fmt.dwMask &= ~PFM_TABLEROWDELIMITER;
1527
1528 ok(ret == expectedMask, "expected %x got %x\n", expectedMask, ret);
1529 ok(fmt.dwMask == expectedMask, "expected %x got %x\n", expectedMask, fmt.dwMask);
1530
1531 /* Test some other paraformat field defaults */
1532 ok( fmt.wNumbering == 0, "got %d\n", fmt.wNumbering );
1533 ok( fmt.wNumberingStart == 0, "got %d\n", fmt.wNumberingStart );
1534 ok( fmt.wNumberingStyle == 0, "got %04x\n", fmt.wNumberingStyle );
1535 ok( fmt.wNumberingTab == 0, "got %d\n", fmt.wNumberingTab );
1536
1537 DestroyWindow(hwndRichEdit);
1538}
1539
1540static void test_TM_PLAINTEXT(void)
1541{
1542 /*Tests plain text properties*/
1543
1544 HWND hwndRichEdit = new_richedit(NULL);
1545 CHARFORMAT2A cf2, cf2test;
1546 CHARRANGE cr;
1547 int rc = 0;
1548
1549 /*Switch to plain text mode*/
1550
1551 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
1552 SendMessageA(hwndRichEdit, EM_SETTEXTMODE, TM_PLAINTEXT, 0);
1553
1554 /*Fill control with text*/
1555
1556 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"Is Wine an emulator? No it's not");
1557
1558 /*Select some text and bold it*/
1559
1560 cr.cpMin = 10;
1561 cr.cpMax = 20;
1562 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1563 cf2.cbSize = sizeof(CHARFORMAT2A);
1564 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2);
1565
1566 cf2.dwMask = CFM_BOLD | cf2.dwMask;
1567 cf2.dwEffects = CFE_BOLD ^ cf2.dwEffects;
1568
1569 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1570 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
1571
1572 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_WORD | SCF_SELECTION, (LPARAM)&cf2);
1573 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
1574
1575 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2);
1576 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
1577
1578 /*Get the formatting of those characters*/
1579
1580 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1581
1582 /*Get the formatting of some other characters*/
1583 cf2test.cbSize = sizeof(CHARFORMAT2A);
1584 cr.cpMin = 21;
1585 cr.cpMax = 30;
1586 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1587 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2test);
1588
1589 /*Test that they are the same as plain text allows only one formatting*/
1590
1591 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
1592 "two selections' formats differ - cf2.dwMask: %x, cf2test.dwMask %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1593 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
1594
1595 /*Fill the control with a "wine" string, which when inserted will be bold*/
1596
1597 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1598
1599 /*Copy the bolded "wine" string*/
1600
1601 cr.cpMin = 0;
1602 cr.cpMax = 4;
1603 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1604 SendMessageA(hwndRichEdit, WM_COPY, 0, 0);
1605
1606 /*Swap back to rich text*/
1607
1608 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
1609 SendMessageA(hwndRichEdit, EM_SETTEXTMODE, TM_RICHTEXT, 0);
1610
1611 /*Set the default formatting to bold italics*/
1612
1613 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2);
1614 cf2.dwMask |= CFM_ITALIC;
1615 cf2.dwEffects ^= CFE_ITALIC;
1616 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2);
1617 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
1618
1619 /*Set the text in the control to "wine", which will be bold and italicized*/
1620
1621 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1622
1623 /*Paste the plain text "wine" string, which should take the insert
1624 formatting, which at the moment is bold italics*/
1625
1626 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
1627
1628 /*Select the first "wine" string and retrieve its formatting*/
1629
1630 cr.cpMin = 1;
1631 cr.cpMax = 3;
1632 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1633 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1634
1635 /*Select the second "wine" string and retrieve its formatting*/
1636
1637 cr.cpMin = 5;
1638 cr.cpMax = 7;
1639 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1640 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2test);
1641
1642 /*Compare the two formattings. They should be the same.*/
1643
1644 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
1645 "Copied text retained formatting - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1646 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
1647 DestroyWindow(hwndRichEdit);
1648}
1649
1650static void test_WM_GETTEXT(void)
1651{
1652 HWND hwndRichEdit = new_richedit(NULL);
1653 static const char text[] = "Hello. My name is RichEdit!";
1654 static const char text2[] = "Hello. My name is RichEdit!\r";
1655 static const char text2_after[] = "Hello. My name is RichEdit!\r\n";
1656 char buffer[1024] = {0};
1657 int result;
1658
1659 /* Baseline test with normal-sized buffer */
1660 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
1661 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
1663 "WM_GETTEXT returned %d, expected %d\n", result, lstrlenA(buffer));
1664 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
1666 ok(result == 0,
1667 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
1668
1669 /* Test for returned value of WM_GETTEXTLENGTH */
1670 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
1671 ok(result == lstrlenA(text),
1672 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
1673 result, lstrlenA(text));
1674
1675 /* Test for behavior in overflow case */
1676 memset(buffer, 0, 1024);
1677 result = SendMessageA(hwndRichEdit, WM_GETTEXT, strlen(text), (LPARAM)buffer);
1678 ok(result == 0 ||
1679 result == lstrlenA(text) - 1, /* XP, win2k3 */
1680 "WM_GETTEXT returned %d, expected 0 or %d\n", result, lstrlenA(text) - 1);
1682 if (result)
1683 result = strncmp(buffer, text, lstrlenA(text) - 1); /* XP, win2k3 */
1684 ok(result == 0,
1685 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
1686
1687 /* Baseline test with normal-sized buffer and carriage return */
1688 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
1689 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
1691 "WM_GETTEXT returned %d, expected %d\n", result, lstrlenA(buffer));
1692 result = strcmp(buffer,text2_after);
1693 ok(result == 0,
1694 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
1695
1696 /* Test for returned value of WM_GETTEXTLENGTH */
1697 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
1698 ok(result == lstrlenA(text2_after),
1699 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
1700 result, lstrlenA(text2_after));
1701
1702 /* Test for behavior of CRLF conversion in case of overflow */
1703 memset(buffer, 0, 1024);
1704 result = SendMessageA(hwndRichEdit, WM_GETTEXT, strlen(text2), (LPARAM)buffer);
1705 ok(result == 0 ||
1706 result == lstrlenA(text2) - 1, /* XP, win2k3 */
1707 "WM_GETTEXT returned %d, expected 0 or %d\n", result, lstrlenA(text2) - 1);
1708 result = strcmp(buffer,text2);
1709 if (result)
1710 result = strncmp(buffer, text2, lstrlenA(text2) - 1); /* XP, win2k3 */
1711 ok(result == 0,
1712 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
1713
1714 DestroyWindow(hwndRichEdit);
1715}
1716
1717static void test_EM_GETTEXTRANGE(void)
1718{
1719 HWND hwndRichEdit = new_richedit(NULL);
1720 const char * text1 = "foo bar\r\nfoo bar";
1721 const char * text2 = "foo bar\rfoo bar";
1722 const char * expect = "bar\rfoo";
1723 char buffer[1024] = {0};
1725 TEXTRANGEA textRange;
1726
1727 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
1728
1729 textRange.lpstrText = buffer;
1730 textRange.chrg.cpMin = 4;
1731 textRange.chrg.cpMax = 11;
1732 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1733 ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result);
1734 ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1735
1736 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
1737
1738 textRange.lpstrText = buffer;
1739 textRange.chrg.cpMin = 4;
1740 textRange.chrg.cpMax = 11;
1741 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1742 ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result);
1743 ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1744
1745 /* cpMax of text length is used instead of -1 in this case */
1746 textRange.lpstrText = buffer;
1747 textRange.chrg.cpMin = 0;
1748 textRange.chrg.cpMax = -1;
1749 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1750 ok(result == strlen(text2), "EM_GETTEXTRANGE returned %ld\n", result);
1751 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1752
1753 /* cpMin < 0 causes no text to be copied, and 0 to be returned */
1754 textRange.lpstrText = buffer;
1755 textRange.chrg.cpMin = -1;
1756 textRange.chrg.cpMax = 1;
1757 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1758 ok(result == 0, "EM_GETTEXTRANGE returned %ld\n", result);
1759 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1760
1761 /* cpMax of -1 is not replaced with text length if cpMin != 0 */
1762 textRange.lpstrText = buffer;
1763 textRange.chrg.cpMin = 1;
1764 textRange.chrg.cpMax = -1;
1765 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1766 ok(result == 0, "EM_GETTEXTRANGE returned %ld\n", result);
1767 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1768
1769 /* no end character is copied if cpMax - cpMin < 0 */
1770 textRange.lpstrText = buffer;
1771 textRange.chrg.cpMin = 5;
1772 textRange.chrg.cpMax = 5;
1773 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1774 ok(result == 0, "EM_GETTEXTRANGE returned %ld\n", result);
1775 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1776
1777 /* cpMax of text length is used if cpMax > text length*/
1778 textRange.lpstrText = buffer;
1779 textRange.chrg.cpMin = 0;
1780 textRange.chrg.cpMax = 1000;
1781 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1782 ok(result == strlen(text2), "EM_GETTEXTRANGE returned %ld\n", result);
1783 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1784
1785 /* Test with multibyte character */
1786 if (!is_lang_japanese)
1787 skip("Skip multibyte character tests on non-Japanese platform\n");
1788 else
1789 {
1790 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk");
1791 textRange.chrg.cpMin = 4;
1792 textRange.chrg.cpMax = 8;
1793 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1794 todo_wine ok(result == 5, "EM_GETTEXTRANGE returned %ld\n", result);
1795 todo_wine ok(!strcmp("ef\x8e\xf0g", buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1796 }
1797
1798 DestroyWindow(hwndRichEdit);
1799}
1800
1801static void test_EM_GETSELTEXT(void)
1802{
1803 HWND hwndRichEdit = new_richedit(NULL);
1804 const char * text1 = "foo bar\r\nfoo bar";
1805 const char * text2 = "foo bar\rfoo bar";
1806 const char * expect = "bar\rfoo";
1807 char buffer[1024] = {0};
1809
1810 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
1811
1812 SendMessageA(hwndRichEdit, EM_SETSEL, 4, 11);
1813 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
1814 ok(result == 7, "EM_GETSELTEXT returned %ld\n", result);
1815 ok(!strcmp(expect, buffer), "EM_GETSELTEXT filled %s\n", buffer);
1816
1817 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
1818
1819 SendMessageA(hwndRichEdit, EM_SETSEL, 4, 11);
1820 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
1821 ok(result == 7, "EM_GETSELTEXT returned %ld\n", result);
1822 ok(!strcmp(expect, buffer), "EM_GETSELTEXT filled %s\n", buffer);
1823
1824 /* Test with multibyte character */
1825 if (!is_lang_japanese)
1826 skip("Skip multibyte character tests on non-Japanese platform\n");
1827 else
1828 {
1829 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk");
1830 SendMessageA(hwndRichEdit, EM_SETSEL, 4, 8);
1831 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
1832 todo_wine ok(result == 5, "EM_GETSELTEXT returned %ld\n", result);
1833 todo_wine ok(!strcmp("ef\x8e\xf0g", buffer), "EM_GETSELTEXT filled %s\n", buffer);
1834 }
1835
1836 DestroyWindow(hwndRichEdit);
1837}
1838
1839/* FIXME: need to test unimplemented options and robustly test wparam */
1840static void test_EM_SETOPTIONS(void)
1841{
1842 HWND hwndRichEdit;
1843 static const char text[] = "Hello. My name is RichEdit!";
1844 char buffer[1024] = {0};
1845 DWORD dwStyle, options, oldOptions;
1849
1850 /* Test initial options. */
1852 0, 0, 200, 60, NULL, NULL,
1854 ok(hwndRichEdit != NULL, "class: %s, error: %d\n",
1856 options = SendMessageA(hwndRichEdit, EM_GETOPTIONS, 0, 0);
1857 ok(options == 0, "Incorrect initial options %x\n", options);
1858 DestroyWindow(hwndRichEdit);
1859
1860 hwndRichEdit = CreateWindowA(RICHEDIT_CLASS20A, NULL,
1862 0, 0, 200, 60, NULL, NULL,
1864 ok(hwndRichEdit != NULL, "class: %s, error: %d\n",
1866 options = SendMessageA(hwndRichEdit, EM_GETOPTIONS, 0, 0);
1867 /* WS_[VH]SCROLL cause the ECO_AUTO[VH]SCROLL options to be set */
1869 "Incorrect initial options %x\n", options);
1870
1871 /* NEGATIVE TESTING - NO OPTIONS SET */
1872 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
1873 SendMessageA(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, 0);
1874
1875 /* testing no readonly by sending 'a' to the control*/
1876 SendMessageA(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
1877 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
1878 ok(buffer[0]=='a',
1879 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text, buffer);
1880 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
1881
1882 /* READONLY - sending 'a' to the control */
1883 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
1885 SendMessageA(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
1886 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
1887 ok(buffer[0]==text[0],
1888 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer);
1889
1890 /* EM_SETOPTIONS changes the window style, but changing the
1891 * window style does not change the options. */
1892 dwStyle = GetWindowLongA(hwndRichEdit, GWL_STYLE);
1893 ok(dwStyle & ES_READONLY, "Readonly style not set by EM_SETOPTIONS\n");
1894 SetWindowLongA(hwndRichEdit, GWL_STYLE, dwStyle & ~ES_READONLY);
1895 options = SendMessageA(hwndRichEdit, EM_GETOPTIONS, 0, 0);
1896 ok(options & ES_READONLY, "Readonly option set by SetWindowLong\n");
1897 /* Confirm that the text is still read only. */
1898 SendMessageA(hwndRichEdit, WM_CHAR, 'a', ('a' << 16) | 0x0001);
1899 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
1900 ok(buffer[0]==text[0],
1901 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer);
1902
1903 oldOptions = options;
1904 SetWindowLongA(hwndRichEdit, GWL_STYLE, dwStyle|optionStyles);
1905 options = SendMessageA(hwndRichEdit, EM_GETOPTIONS, 0, 0);
1906 ok(options == oldOptions,
1907 "Options set by SetWindowLong (%x -> %x)\n", oldOptions, options);
1908
1909 DestroyWindow(hwndRichEdit);
1910}
1911
1912static BOOL check_CFE_LINK_selection(HWND hwnd, int sel_start, int sel_end)
1913{
1914 CHARFORMAT2A text_format;
1915 text_format.cbSize = sizeof(text_format);
1916 SendMessageA(hwnd, EM_SETSEL, sel_start, sel_end);
1918 return (text_format.dwEffects & CFE_LINK) != 0;
1919}
1920
1921static void check_CFE_LINK_rcvd(HWND hwnd, BOOL is_url, const char * url)
1922{
1923 BOOL link_present = FALSE;
1924
1925 link_present = check_CFE_LINK_selection(hwnd, 0, 1);
1926 if (is_url)
1927 { /* control text is url; should get CFE_LINK */
1928 ok(link_present, "URL Case: CFE_LINK not set for [%s].\n", url);
1929 }
1930 else
1931 {
1932 ok(!link_present, "Non-URL Case: CFE_LINK set for [%s].\n", url);
1933 }
1934}
1935
1937 return new_window("Static", 0, parent);
1938}
1939
1940static void test_EM_AUTOURLDETECT(void)
1941{
1942 /* DO NOT change the properties of the first two elements. To shorten the
1943 tests, all tests after WM_SETTEXT test just the first two elements -
1944 one non-URL and one URL */
1945 struct urls_s {
1946 const char *text;
1947 BOOL is_url;
1948 } urls[12] = {
1949 {"winehq.org", FALSE},
1950 {"http://www.winehq.org", TRUE},
1951 {"http//winehq.org", FALSE},
1952 {"ww.winehq.org", FALSE},
1953 {"www.winehq.org", TRUE},
1954 {"ftp://192.168.1.1", TRUE},
1955 {"ftp//192.168.1.1", FALSE},
1956 {"mailto:your@email.com", TRUE},
1957 {"prospero:prosperoserver", TRUE},
1958 {"telnet:test", TRUE},
1959 {"news:newserver", TRUE},
1960 {"wais:waisserver", TRUE}
1961 };
1962
1963 int i, j;
1964 int urlRet=-1;
1965 HWND hwndRichEdit, parent;
1966
1967 /* All of the following should cause the URL to be detected */
1968 const char * templates_delim[] = {
1969 "This is some text with X on it",
1970 "This is some text with (X) on it",
1971 "This is some text with X\r on it",
1972 "This is some text with ---X--- on it",
1973 "This is some text with \"X\" on it",
1974 "This is some text with 'X' on it",
1975 "This is some text with 'X' on it",
1976 "This is some text with :X: on it",
1977
1978 "This text ends with X",
1979
1980 "This is some text with X) on it",
1981 "This is some text with X--- on it",
1982 "This is some text with X\" on it",
1983 "This is some text with X' on it",
1984 "This is some text with X: on it",
1985
1986 "This is some text with (X on it",
1987 "This is some text with \rX on it",
1988 "This is some text with ---X on it",
1989 "This is some text with \"X on it",
1990 "This is some text with 'X on it",
1991 "This is some text with :X on it",
1992 };
1993 /* None of these should cause the URL to be detected */
1994 const char * templates_non_delim[] = {
1995 "This is some text with |X| on it",
1996 "This is some text with *X* on it",
1997 "This is some text with /X/ on it",
1998 "This is some text with +X+ on it",
1999 "This is some text with %X% on it",
2000 "This is some text with #X# on it",
2001 "This is some text with @X@ on it",
2002 "This is some text with \\X\\ on it",
2003 "This is some text with |X on it",
2004 "This is some text with *X on it",
2005 "This is some text with /X on it",
2006 "This is some text with +X on it",
2007 "This is some text with %X on it",
2008 "This is some text with #X on it",
2009 "This is some text with @X on it",
2010 "This is some text with \\X on it",
2011 "This is some text with _X on it",
2012 };
2013 /* All of these cause the URL detection to be extended by one more byte,
2014 thus demonstrating that the tested character is considered as part
2015 of the URL. */
2016 const char * templates_xten_delim[] = {
2017 "This is some text with X| on it",
2018 "This is some text with X* on it",
2019 "This is some text with X/ on it",
2020 "This is some text with X+ on it",
2021 "This is some text with X% on it",
2022 "This is some text with X# on it",
2023 "This is some text with X@ on it",
2024 "This is some text with X\\ on it",
2025 "This is some text with X_ on it",
2026 };
2027 /* These delims act as neutral breaks. Whether the url is ended
2028 or not depends on the next non-neutral character. We'll test
2029 with Y unchanged, in which case the url should include the
2030 deliminator and the Y. We'll also test with the Y changed
2031 to a space, in which case the url stops before the
2032 deliminator. */
2033 const char * templates_neutral_delim[] = {
2034 "This is some text with X-Y on it",
2035 "This is some text with X--Y on it",
2036 "This is some text with X!Y on it",
2037 "This is some text with X[Y on it",
2038 "This is some text with X]Y on it",
2039 "This is some text with X{Y on it",
2040 "This is some text with X}Y on it",
2041 "This is some text with X(Y on it",
2042 "This is some text with X)Y on it",
2043 "This is some text with X\"Y on it",
2044 "This is some text with X;Y on it",
2045 "This is some text with X:Y on it",
2046 "This is some text with X'Y on it",
2047 "This is some text with X?Y on it",
2048 "This is some text with X<Y on it",
2049 "This is some text with X>Y on it",
2050 "This is some text with X.Y on it",
2051 "This is some text with X,Y on it",
2052 };
2053 char buffer[1024];
2054
2056 hwndRichEdit = new_richedit(parent);
2057 /* Try and pass EM_AUTOURLDETECT some test wParam values */
2058 urlRet=SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
2059 ok(urlRet==0, "Good wParam: urlRet is: %d\n", urlRet);
2060 urlRet=SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, 1, 0);
2061 ok(urlRet==0, "Good wParam2: urlRet is: %d\n", urlRet);
2062 /* Windows returns -2147024809 (0x80070057) on bad wParam values */
2063 urlRet=SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, 8, 0);
2064 ok(urlRet==E_INVALIDARG, "Bad wParam: urlRet is: %d\n", urlRet);
2065 urlRet=SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, (WPARAM)"h", (LPARAM)"h");
2066 ok(urlRet==E_INVALIDARG, "Bad wParam2: urlRet is: %d\n", urlRet);
2067 /* for each url, check the text to see if CFE_LINK effect is present */
2068 for (i = 0; i < ARRAY_SIZE(urls); i++) {
2069
2070 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
2071 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)urls[i].text);
2072 check_CFE_LINK_rcvd(hwndRichEdit, FALSE, urls[i].text);
2073
2074 /* Link detection should happen immediately upon WM_SETTEXT */
2075 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2076 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)urls[i].text);
2077 check_CFE_LINK_rcvd(hwndRichEdit, urls[i].is_url, urls[i].text);
2078 }
2079 DestroyWindow(hwndRichEdit);
2080
2081 /* Test detection of URLs within normal text - WM_SETTEXT case. */
2082 for (i = 0; i < ARRAY_SIZE(urls); i++) {
2083 hwndRichEdit = new_richedit(parent);
2084
2085 for (j = 0; j < ARRAY_SIZE(templates_delim); j++) {
2086 char * at_pos;
2087 int at_offset;
2088 int end_offset;
2089
2090 at_pos = strchr(templates_delim[j], 'X');
2091 at_offset = at_pos - templates_delim[j];
2092 memcpy(buffer, templates_delim[j], at_offset);
2093 buffer[at_offset] = '\0';
2094 strcat(buffer, urls[i].text);
2095 strcat(buffer, templates_delim[j] + at_offset + 1);
2096 end_offset = at_offset + strlen(urls[i].text);
2097
2098 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2099 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer);
2100
2101 /* This assumes no templates start with the URL itself, and that they
2102 have at least two characters before the URL text */
2103 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2104 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2105 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2106 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2107 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2108 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2109
2110 if (urls[i].is_url)
2111 {
2112 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2113 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2114 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2115 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2116 }
2117 else
2118 {
2119 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2120 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2121 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2122 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2123 }
2124 if (buffer[end_offset] != '\0')
2125 {
2126 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2127 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2128 if (buffer[end_offset +1] != '\0')
2129 {
2130 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2131 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2132 }
2133 }
2134 }
2135
2136 for (j = 0; j < ARRAY_SIZE(templates_non_delim); j++) {
2137 char * at_pos;
2138 int at_offset;
2139 int end_offset;
2140
2141 at_pos = strchr(templates_non_delim[j], 'X');
2142 at_offset = at_pos - templates_non_delim[j];
2143 memcpy(buffer, templates_non_delim[j], at_offset);
2144 buffer[at_offset] = '\0';
2145 strcat(buffer, urls[i].text);
2146 strcat(buffer, templates_non_delim[j] + at_offset + 1);
2147 end_offset = at_offset + strlen(urls[i].text);
2148
2149 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2150 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer);
2151
2152 /* This assumes no templates start with the URL itself, and that they
2153 have at least two characters before the URL text */
2154 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2155 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2156 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2157 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2158 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2159 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2160
2161 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2162 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2163 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2164 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2165 if (buffer[end_offset] != '\0')
2166 {
2167 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2168 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2169 if (buffer[end_offset +1] != '\0')
2170 {
2171 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2172 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2173 }
2174 }
2175 }
2176
2177 for (j = 0; j < ARRAY_SIZE(templates_xten_delim); j++) {
2178 char * at_pos;
2179 int at_offset;
2180 int end_offset;
2181
2182 at_pos = strchr(templates_xten_delim[j], 'X');
2183 at_offset = at_pos - templates_xten_delim[j];
2184 memcpy(buffer, templates_xten_delim[j], at_offset);
2185 buffer[at_offset] = '\0';
2186 strcat(buffer, urls[i].text);
2187 strcat(buffer, templates_xten_delim[j] + at_offset + 1);
2188 end_offset = at_offset + strlen(urls[i].text);
2189
2190 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2191 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer);
2192
2193 /* This assumes no templates start with the URL itself, and that they
2194 have at least two characters before the URL text */
2195 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2196 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2197 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2198 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2199 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2200 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2201
2202 if (urls[i].is_url)
2203 {
2204 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2205 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2206 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2207 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2208 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2209 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer);
2210 }
2211 else
2212 {
2213 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2214 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2215 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2216 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2217 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2218 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer);
2219 }
2220 if (buffer[end_offset +1] != '\0')
2221 {
2222 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2223 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset + 2, buffer);
2224 if (buffer[end_offset +2] != '\0')
2225 {
2226 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +2, end_offset +3),
2227 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +2, end_offset +3, buffer);
2228 }
2229 }
2230 }
2231
2232 for (j = 0; j < ARRAY_SIZE(templates_neutral_delim); j++) {
2233 char * at_pos, * end_pos;
2234 int at_offset;
2235 int end_offset;
2236
2237 if (!urls[i].is_url) continue;
2238
2239 at_pos = strchr(templates_neutral_delim[j], 'X');
2240 at_offset = at_pos - templates_neutral_delim[j];
2241 memcpy(buffer, templates_neutral_delim[j], at_offset);
2242 buffer[at_offset] = '\0';
2243 strcat(buffer, urls[i].text);
2244 strcat(buffer, templates_neutral_delim[j] + at_offset + 1);
2245
2246 end_pos = strchr(buffer, 'Y');
2247 end_offset = end_pos - buffer;
2248
2249 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2250 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer);
2251
2252 /* This assumes no templates start with the URL itself, and that they
2253 have at least two characters before the URL text */
2254 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2255 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2256 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2257 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2258 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2259 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2260
2261 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2262 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2263 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2264 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2265 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2266 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer);
2267
2268 *end_pos = ' ';
2269
2270 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2271 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer);
2272
2273 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2274 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2275 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2276 "CFE_LINK set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2277 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2278 "CFE_LINK set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer);
2279 }
2280
2281 DestroyWindow(hwndRichEdit);
2282 hwndRichEdit = NULL;
2283 }
2284
2285 /* Test detection of URLs within normal text - WM_CHAR case. */
2286 /* Test only the first two URL examples for brevity */
2287 for (i = 0; i < 2; i++) {
2288 hwndRichEdit = new_richedit(parent);
2289
2290 /* Also for brevity, test only the first three delimiters */
2291 for (j = 0; j < 3; j++) {
2292 char * at_pos;
2293 int at_offset;
2294 int end_offset;
2295 int u, v;
2296
2297 at_pos = strchr(templates_delim[j], 'X');
2298 at_offset = at_pos - templates_delim[j];
2299 end_offset = at_offset + strlen(urls[i].text);
2300
2301 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2302 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
2303 for (u = 0; templates_delim[j][u]; u++) {
2304 if (templates_delim[j][u] == '\r') {
2305 simulate_typing_characters(hwndRichEdit, "\r");
2306 } else if (templates_delim[j][u] != 'X') {
2307 SendMessageA(hwndRichEdit, WM_CHAR, templates_delim[j][u], 1);
2308 } else {
2309 for (v = 0; urls[i].text[v]; v++) {
2310 SendMessageA(hwndRichEdit, WM_CHAR, urls[i].text[v], 1);
2311 }
2312 }
2313 }
2314 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2315
2316 /* This assumes no templates start with the URL itself, and that they
2317 have at least two characters before the URL text */
2318 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2319 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2320 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2321 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2322 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2323 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2324
2325 if (urls[i].is_url)
2326 {
2327 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2328 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2329 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2330 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2331 }
2332 else
2333 {
2334 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2335 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2336 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2337 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2338 }
2339 if (buffer[end_offset] != '\0')
2340 {
2341 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2342 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2343 if (buffer[end_offset +1] != '\0')
2344 {
2345 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2346 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2347 }
2348 }
2349
2350 /* The following will insert a paragraph break after the first character
2351 of the URL candidate, thus breaking the URL. It is expected that the
2352 CFE_LINK attribute should break across both pieces of the URL */
2353 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset+1, at_offset+1);
2354 simulate_typing_characters(hwndRichEdit, "\r");
2355 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2356
2357 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2358 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2359 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2360 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2361 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2362 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2363
2364 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2365 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2366 /* end_offset moved because of paragraph break */
2367 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2368 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset+1, buffer);
2369 ok(buffer[end_offset], "buffer \"%s\" ended prematurely. Is it missing a newline character?\n", buffer);
2370 if (buffer[end_offset] != 0 && buffer[end_offset+1] != '\0')
2371 {
2372 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset+1, end_offset +2),
2373 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset+1, end_offset +2, buffer);
2374 if (buffer[end_offset +2] != '\0')
2375 {
2376 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +2, end_offset +3),
2377 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +2, end_offset +3, buffer);
2378 }
2379 }
2380
2381 /* The following will remove the just-inserted paragraph break, thus
2382 restoring the URL */
2383 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset+2, at_offset+2);
2384 simulate_typing_characters(hwndRichEdit, "\b");
2385 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2386
2387 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2388 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2389 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2390 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2391 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2392 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2393
2394 if (urls[i].is_url)
2395 {
2396 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2397 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2398 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2399 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2400 }
2401 else
2402 {
2403 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2404 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2405 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2406 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2407 }
2408 if (buffer[end_offset] != '\0')
2409 {
2410 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2411 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2412 if (buffer[end_offset +1] != '\0')
2413 {
2414 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2415 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2416 }
2417 }
2418 }
2419 DestroyWindow(hwndRichEdit);
2420 hwndRichEdit = NULL;
2421 }
2422
2423 /* Test detection of URLs within normal text - EM_SETTEXTEX case. */
2424 /* Test just the first two URL examples for brevity */
2425 for (i = 0; i < 2; i++) {
2426 SETTEXTEX st;
2427
2428 hwndRichEdit = new_richedit(parent);
2429
2430 /* There are at least three ways in which EM_SETTEXTEX must cause URLs to
2431 be detected:
2432 1) Set entire text, a la WM_SETTEXT
2433 2) Set a selection of the text to the URL
2434 3) Set a portion of the text at a time, which eventually results in
2435 an URL
2436 All of them should give equivalent results
2437 */
2438
2439 /* Set entire text in one go, like WM_SETTEXT */
2440 for (j = 0; j < ARRAY_SIZE(templates_delim); j++) {
2441 char * at_pos;
2442 int at_offset;
2443 int end_offset;
2444
2445 st.codepage = CP_ACP;
2446 st.flags = ST_DEFAULT;
2447
2448 at_pos = strchr(templates_delim[j], 'X');
2449 at_offset = at_pos - templates_delim[j];
2450 memcpy(buffer, templates_delim[j], at_offset);
2451 buffer[at_offset] = '\0';
2452 strcat(buffer, urls[i].text);
2453 strcat(buffer, templates_delim[j] + at_offset + 1);
2454 end_offset = at_offset + strlen(urls[i].text);
2455
2456 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2457 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)buffer);
2458
2459 /* This assumes no templates start with the URL itself, and that they
2460 have at least two characters before the URL text */
2461 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2462 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2463 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2464 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2465 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2466 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2467
2468 if (urls[i].is_url)
2469 {
2470 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2471 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2472 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2473 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2474 }
2475 else
2476 {
2477 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2478 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2479 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2480 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2481 }
2482 if (buffer[end_offset] != '\0')
2483 {
2484 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2485 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2486 if (buffer[end_offset +1] != '\0')
2487 {
2488 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2489 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2490 }
2491 }
2492 }
2493
2494 /* Set selection with X to the URL */
2495 for (j = 0; j < ARRAY_SIZE(templates_delim); j++) {
2496 char * at_pos;
2497 int at_offset;
2498 int end_offset;
2499
2500 at_pos = strchr(templates_delim[j], 'X');
2501 at_offset = at_pos - templates_delim[j];
2502 end_offset = at_offset + strlen(urls[i].text);
2503
2504 st.codepage = CP_ACP;
2505 st.flags = ST_DEFAULT;
2506 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2507 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)templates_delim[j]);
2508 st.flags = ST_SELECTION;
2509 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1);
2510 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)urls[i].text);
2511 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2512
2513 /* This assumes no templates start with the URL itself, and that they
2514 have at least two characters before the URL text */
2515 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2516 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2517 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2518 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2519 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2520 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2521
2522 if (urls[i].is_url)
2523 {
2524 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2525 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2526 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2527 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2528 }
2529 else
2530 {
2531 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2532 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2533 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2534 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2535 }
2536 if (buffer[end_offset] != '\0')
2537 {
2538 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2539 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2540 if (buffer[end_offset +1] != '\0')
2541 {
2542 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2543 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2544 }
2545 }
2546 }
2547
2548 /* Set selection with X to the first character of the URL, then the rest */
2549 for (j = 0; j < ARRAY_SIZE(templates_delim); j++) {
2550 char * at_pos;
2551 int at_offset;
2552 int end_offset;
2553
2554 at_pos = strchr(templates_delim[j], 'X');
2555 at_offset = at_pos - templates_delim[j];
2556 end_offset = at_offset + strlen(urls[i].text);
2557
2558 strcpy(buffer, "YY");
2559 buffer[0] = urls[i].text[0];
2560
2561 st.codepage = CP_ACP;
2562 st.flags = ST_DEFAULT;
2563 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2564 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)templates_delim[j]);
2565 st.flags = ST_SELECTION;
2566 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1);
2567 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)buffer);
2568 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset+1, at_offset+2);
2569 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)(urls[i].text + 1));
2570 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2571
2572 /* This assumes no templates start with the URL itself, and that they
2573 have at least two characters before the URL text */
2574 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2575 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2576 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2577 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2578 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2579 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2580
2581 if (urls[i].is_url)
2582 {
2583 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2584 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2585 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2586 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2587 }
2588 else
2589 {
2590 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2591 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2592 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2593 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2594 }
2595 if (buffer[end_offset] != '\0')
2596 {
2597 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2598 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2599 if (buffer[end_offset +1] != '\0')
2600 {
2601 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2602 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2603 }
2604 }
2605 }
2606
2607 DestroyWindow(hwndRichEdit);
2608 hwndRichEdit = NULL;
2609 }
2610
2611 /* Test detection of URLs within normal text - EM_REPLACESEL case. */
2612 /* Test just the first two URL examples for brevity */
2613 for (i = 0; i < 2; i++) {
2614 hwndRichEdit = new_richedit(parent);
2615
2616 /* Set selection with X to the URL */
2617 for (j = 0; j < ARRAY_SIZE(templates_delim); j++) {
2618 char * at_pos;
2619 int at_offset;
2620 int end_offset;
2621
2622 at_pos = strchr(templates_delim[j], 'X');
2623 at_offset = at_pos - templates_delim[j];
2624 end_offset = at_offset + strlen(urls[i].text);
2625
2626 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2627 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)templates_delim[j]);
2628 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1);
2629 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)urls[i].text);
2630 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2631
2632 /* This assumes no templates start with the URL itself, and that they
2633 have at least two characters before the URL text */
2634 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2635 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2636 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2637 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2638 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2639 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2640
2641 if (urls[i].is_url)
2642 {
2643 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2644 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2645 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2646 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2647 }
2648 else
2649 {
2650 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2651 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2652 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2653 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2654 }
2655 if (buffer[end_offset] != '\0')
2656 {
2657 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2658 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2659 if (buffer[end_offset +1] != '\0')
2660 {
2661 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2662 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2663 }
2664 }
2665 }
2666
2667 /* Set selection with X to the first character of the URL, then the rest */
2668 for (j = 0; j < ARRAY_SIZE(templates_delim); j++) {
2669 char * at_pos;
2670 int at_offset;
2671 int end_offset;
2672
2673 at_pos = strchr(templates_delim[j], 'X');
2674 at_offset = at_pos - templates_delim[j];
2675 end_offset = at_offset + strlen(urls[i].text);
2676
2677 strcpy(buffer, "YY");
2678 buffer[0] = urls[i].text[0];
2679
2680 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2681 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)templates_delim[j]);
2682 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1);
2683 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)buffer);
2684 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset+1, at_offset+2);
2685 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)(urls[i].text + 1));
2686 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2687
2688 /* This assumes no templates start with the URL itself, and that they
2689 have at least two characters before the URL text */
2690 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2691 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2692 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2693 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2694 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2695 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2696
2697 if (urls[i].is_url)
2698 {
2699 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2700 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2701 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2702 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2703 }
2704 else
2705 {
2706 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2707 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2708 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2709 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2710 }
2711 if (buffer[end_offset] != '\0')
2712 {
2713 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2714 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2715 if (buffer[end_offset +1] != '\0')
2716 {
2717 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2718 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2719 }
2720 }
2721 }
2722
2723 DestroyWindow(hwndRichEdit);
2724 hwndRichEdit = NULL;
2725 }
2726
2728}
2729
2730static void test_EM_SCROLL(void)
2731{
2732 int i, j;
2733 int r; /* return value */
2734 int expr; /* expected return value */
2735 HWND hwndRichEdit = new_richedit(NULL);
2736 int y_before, y_after; /* units of lines of text */
2737
2738 /* test a richedit box containing a single line of text */
2739 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");/* one line of text */
2740 expr = 0x00010000;
2741 for (i = 0; i < 4; i++) {
2742 static const int cmd[4] = { SB_PAGEDOWN, SB_PAGEUP, SB_LINEDOWN, SB_LINEUP };
2743
2744 r = SendMessageA(hwndRichEdit, EM_SCROLL, cmd[i], 0);
2745 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2746 ok(expr == r, "EM_SCROLL improper return value returned (i == %d). "
2747 "Got 0x%08x, expected 0x%08x\n", i, r, expr);
2748 ok(y_after == 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 "
2749 "(i == %d)\n", y_after, i);
2750 }
2751
2752 /*
2753 * test a richedit box that will scroll. There are two general
2754 * cases: the case without any long lines and the case with a long
2755 * line.
2756 */
2757 for (i = 0; i < 2; i++) { /* iterate through different bodies of text */
2758 if (i == 0)
2759 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a\nb\nc\nd\ne");
2760 else
2761 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)
2762 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
2763 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
2764 "LONG LINE \nb\nc\nd\ne");
2765 for (j = 0; j < 12; j++) /* reset scroll position to top */
2766 SendMessageA(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0);
2767
2768 /* get first visible line */
2769 y_before = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2770 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0); /* page down */
2771
2772 /* get new current first visible line */
2773 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2774
2775 ok(((r & 0xffffff00) == 0x00010000) &&
2776 ((r & 0x000000ff) != 0x00000000),
2777 "EM_SCROLL page down didn't scroll by a small positive number of "
2778 "lines (r == 0x%08x)\n", r);
2779 ok(y_after > y_before, "EM_SCROLL page down not functioning "
2780 "(line %d scrolled to line %d\n", y_before, y_after);
2781
2782 y_before = y_after;
2783
2784 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0); /* page up */
2785 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2786 ok(((r & 0xffffff00) == 0x0001ff00),
2787 "EM_SCROLL page up didn't scroll by a small negative number of lines "
2788 "(r == 0x%08x)\n", r);
2789 ok(y_after < y_before, "EM_SCROLL page up not functioning (line "
2790 "%d scrolled to line %d\n", y_before, y_after);
2791
2792 y_before = y_after;
2793
2794 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */
2795
2796 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2797
2798 ok(r == 0x00010001, "EM_SCROLL line down didn't scroll by one line "
2799 "(r == 0x%08x)\n", r);
2800 ok(y_after -1 == y_before, "EM_SCROLL line down didn't go down by "
2801 "1 line (%d scrolled to %d)\n", y_before, y_after);
2802
2803 y_before = y_after;
2804
2805 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */
2806
2807 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2808
2809 ok(r == 0x0001ffff, "EM_SCROLL line up didn't scroll by one line "
2810 "(r == 0x%08x)\n", r);
2811 ok(y_after +1 == y_before, "EM_SCROLL line up didn't go up by 1 "
2812 "line (%d scrolled to %d)\n", y_before, y_after);
2813
2814 y_before = y_after;
2815
2816 r = SendMessageA(hwndRichEdit, EM_SCROLL,
2817 SB_LINEUP, 0); /* lineup beyond top */
2818
2819 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2820
2821 ok(r == 0x00010000,
2822 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r);
2823 ok(y_before == y_after,
2824 "EM_SCROLL line up beyond top worked (%d)\n", y_after);
2825
2826 y_before = y_after;
2827
2828 r = SendMessageA(hwndRichEdit, EM_SCROLL,
2829 SB_PAGEUP, 0);/*page up beyond top */
2830
2831 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2832
2833 ok(r == 0x00010000,
2834 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r);
2835 ok(y_before == y_after,
2836 "EM_SCROLL page up beyond top worked (%d)\n", y_after);
2837
2838 for (j = 0; j < 12; j++) /* page down all the way to the bottom */
2839 SendMessageA(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0);
2840 y_before = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2841 r = SendMessageA(hwndRichEdit, EM_SCROLL,
2842 SB_PAGEDOWN, 0); /* page down beyond bot */
2843 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2844
2845 ok(r == 0x00010000,
2846 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r);
2847 ok(y_before == y_after,
2848 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n",
2849 y_before, y_after);
2850
2851 y_before = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2852 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down beyond bot */
2853 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2854
2855 ok(r == 0x00010000,
2856 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r);
2857 ok(y_before == y_after,
2858 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n",
2859 y_before, y_after);
2860 }
2861 DestroyWindow(hwndRichEdit);
2862}
2863
2864static unsigned int recursionLevel = 0;
2865static unsigned int WM_SIZE_recursionLevel = 0;
2868
2870{
2871 LRESULT r;
2872
2873 if (bailedOutOfRecursion) return 0;
2874 if (recursionLevel >= 32) {
2876 return 0;
2877 }
2878
2880 switch (message) {
2881 case WM_SIZE:
2883 r = richeditProc(hwnd, message, wParam, lParam);
2884 /* Because, uhhhh... I never heard of ES_DISABLENOSCROLL */
2887 break;
2888 default:
2889 r = richeditProc(hwnd, message, wParam, lParam);
2890 break;
2891 }
2893 return r;
2894}
2895
2897{
2898 HWND hwndRichEdit;
2899 const char * text="a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n";
2900 SCROLLINFO si;
2901 WNDCLASSA cls;
2902 BOOL r;
2903
2904 /* These tests show that richedit should temporarily refrain from automatically
2905 hiding or showing its scrollbars (vertical at least) when an explicit request
2906 is made via ShowScrollBar() or similar, outside of standard richedit logic.
2907 Some applications depend on forced showing (when otherwise richedit would
2908 hide the vertical scrollbar) and are thrown on an endless recursive loop
2909 if richedit auto-hides the scrollbar again. Apparently they never heard of
2910 the ES_DISABLENOSCROLL style... */
2911
2912 hwndRichEdit = new_richedit(NULL);
2913
2914 /* Test default scrollbar visibility behavior */
2915 memset(&si, 0, sizeof(si));
2916 si.cbSize = sizeof(si);
2917 si.fMask = SIF_PAGE | SIF_RANGE;
2918 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2919 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2920 "Vertical scrollbar is visible, should be invisible.\n");
2921 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
2922 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2923 si.nPage, si.nMin, si.nMax);
2924
2925 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
2926 memset(&si, 0, sizeof(si));
2927 si.cbSize = sizeof(si);
2928 si.fMask = SIF_PAGE | SIF_RANGE;
2929 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2930 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2931 "Vertical scrollbar is visible, should be invisible.\n");
2932 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
2933 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2934 si.nPage, si.nMin, si.nMax);
2935
2936 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
2937 memset(&si, 0, sizeof(si));
2938 si.cbSize = sizeof(si);
2939 si.fMask = SIF_PAGE | SIF_RANGE;
2940 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2941 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2942 "Vertical scrollbar is invisible, should be visible.\n");
2943 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2944 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2945 si.nPage, si.nMin, si.nMax);
2946
2947 /* Oddly, setting text to NULL does *not* reset the scrollbar range,
2948 even though it hides the scrollbar */
2949 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
2950 memset(&si, 0, sizeof(si));
2951 si.cbSize = sizeof(si);
2952 si.fMask = SIF_PAGE | SIF_RANGE;
2953 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2954 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2955 "Vertical scrollbar is visible, should be invisible.\n");
2956 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2957 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2958 si.nPage, si.nMin, si.nMax);
2959
2960 /* Setting non-scrolling text again does *not* reset scrollbar range */
2961 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
2962 memset(&si, 0, sizeof(si));
2963 si.cbSize = sizeof(si);
2964 si.fMask = SIF_PAGE | SIF_RANGE;
2965 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2966 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2967 "Vertical scrollbar is visible, should be invisible.\n");
2968 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2969 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2970 si.nPage, si.nMin, si.nMax);
2971
2972 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
2973 memset(&si, 0, sizeof(si));
2974 si.cbSize = sizeof(si);
2975 si.fMask = SIF_PAGE | SIF_RANGE;
2976 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2977 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2978 "Vertical scrollbar is visible, should be invisible.\n");
2979 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2980 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2981 si.nPage, si.nMin, si.nMax);
2982
2983 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
2984 memset(&si, 0, sizeof(si));
2985 si.cbSize = sizeof(si);
2986 si.fMask = SIF_PAGE | SIF_RANGE;
2987 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2988 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2989 "Vertical scrollbar is visible, should be invisible.\n");
2990 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2991 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2992 si.nPage, si.nMin, si.nMax);
2993
2994 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
2995 memset(&si, 0, sizeof(si));
2996 si.cbSize = sizeof(si);
2997 si.fMask = SIF_PAGE | SIF_RANGE;
2998 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2999 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3000 "Vertical scrollbar is visible, should be invisible.\n");
3001 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3002 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3003 si.nPage, si.nMin, si.nMax);
3004
3005 DestroyWindow(hwndRichEdit);
3006
3007 /* Test again, with ES_DISABLENOSCROLL style */
3009
3010 /* Test default scrollbar visibility behavior */
3011 memset(&si, 0, sizeof(si));
3012 si.cbSize = sizeof(si);
3013 si.fMask = SIF_PAGE | SIF_RANGE;
3014 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3015 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3016 "Vertical scrollbar is invisible, should be visible.\n");
3017 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 1,
3018 "reported page/range is %d (%d..%d) expected 0 (0..1)\n",
3019 si.nPage, si.nMin, si.nMax);
3020
3021 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3022 memset(&si, 0, sizeof(si));
3023 si.cbSize = sizeof(si);
3024 si.fMask = SIF_PAGE | SIF_RANGE;
3025 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3026 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3027 "Vertical scrollbar is invisible, should be visible.\n");
3028 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 1,
3029 "reported page/range is %d (%d..%d) expected 0 (0..1)\n",
3030 si.nPage, si.nMin, si.nMax);
3031
3032 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
3033 memset(&si, 0, sizeof(si));
3034 si.cbSize = sizeof(si);
3035 si.fMask = SIF_PAGE | SIF_RANGE;
3036 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3037 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3038 "Vertical scrollbar is invisible, should be visible.\n");
3039 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
3040 "reported page/range is %d (%d..%d)\n",
3041 si.nPage, si.nMin, si.nMax);
3042
3043 /* Oddly, setting text to NULL does *not* reset the scrollbar range */
3044 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3045 memset(&si, 0, sizeof(si));
3046 si.cbSize = sizeof(si);
3047 si.fMask = SIF_PAGE | SIF_RANGE;
3048 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3049 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3050 "Vertical scrollbar is invisible, should be visible.\n");
3051 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
3052 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3053 si.nPage, si.nMin, si.nMax);
3054
3055 /* Setting non-scrolling text again does *not* reset scrollbar range */
3056 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
3057 memset(&si, 0, sizeof(si));
3058 si.cbSize = sizeof(si);
3059 si.fMask = SIF_PAGE | SIF_RANGE;
3060 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3061 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3062 "Vertical scrollbar is invisible, should be visible.\n");
3063 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
3064 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3065 si.nPage, si.nMin, si.nMax);
3066
3067 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3068 memset(&si, 0, sizeof(si));
3069 si.cbSize = sizeof(si);
3070 si.fMask = SIF_PAGE | SIF_RANGE;
3071 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3072 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3073 "Vertical scrollbar is invisible, should be visible.\n");
3074 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
3075 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3076 si.nPage, si.nMin, si.nMax);
3077
3078 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
3079 memset(&si, 0, sizeof(si));
3080 si.cbSize = sizeof(si);
3081 si.fMask = SIF_PAGE | SIF_RANGE;
3082 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3083 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3084 "Vertical scrollbar is invisible, should be visible.\n");
3085 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
3086 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3087 si.nPage, si.nMin, si.nMax);
3088
3089 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
3090 memset(&si, 0, sizeof(si));
3091 si.cbSize = sizeof(si);
3092 si.fMask = SIF_PAGE | SIF_RANGE;
3093 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3094 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3095 "Vertical scrollbar is invisible, should be visible.\n");
3096 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
3097 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3098 si.nPage, si.nMin, si.nMax);
3099
3100 DestroyWindow(hwndRichEdit);
3101
3102 /* Test behavior with explicit visibility request, using ShowScrollBar() */
3103 hwndRichEdit = new_richedit(NULL);
3104
3105 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */
3106 ShowScrollBar(hwndRichEdit, SB_VERT, TRUE);
3107 memset(&si, 0, sizeof(si));
3108 si.cbSize = sizeof(si);
3109 si.fMask = SIF_PAGE | SIF_RANGE;
3110 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3111 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3112 "Vertical scrollbar is invisible, should be visible.\n");
3113 todo_wine {
3114 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
3115 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
3116 si.nPage, si.nMin, si.nMax);
3117 }
3118
3119 /* Ditto, see above */
3120 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3121 memset(&si, 0, sizeof(si));
3122 si.cbSize = sizeof(si);
3123 si.fMask = SIF_PAGE | SIF_RANGE;
3124 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3125 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3126 "Vertical scrollbar is invisible, should be visible.\n");
3127 todo_wine {
3128 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
3129 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
3130 si.nPage, si.nMin, si.nMax);
3131 }
3132
3133 /* Ditto, see above */
3134 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
3135 memset(&si, 0, sizeof(si));
3136 si.cbSize = sizeof(si);
3137 si.fMask = SIF_PAGE | SIF_RANGE;
3138 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3139 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3140 "Vertical scrollbar is invisible, should be visible.\n");
3141 todo_wine {
3142 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
3143 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
3144 si.nPage, si.nMin, si.nMax);
3145 }
3146
3147 /* Ditto, see above */
3148 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a\na");
3149 memset(&si, 0, sizeof(si));
3150 si.cbSize = sizeof(si);
3151 si.fMask = SIF_PAGE | SIF_RANGE;
3152 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3153 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3154 "Vertical scrollbar is invisible, should be visible.\n");
3155 todo_wine {
3156 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
3157 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
3158 si.nPage, si.nMin, si.nMax);
3159 }
3160
3161 /* Ditto, see above */
3162 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3163 memset(&si, 0, sizeof(si));
3164 si.cbSize = sizeof(si);
3165 si.fMask = SIF_PAGE | SIF_RANGE;
3166 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3167 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3168 "Vertical scrollbar is invisible, should be visible.\n");
3169 todo_wine {
3170 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
3171 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
3172 si.nPage, si.nMin, si.nMax);
3173 }
3174
3175 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
3176 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3177 memset(&si, 0, sizeof(si));
3178 si.cbSize = sizeof(si);
3179 si.fMask = SIF_PAGE | SIF_RANGE;
3180 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3181 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3182 "Vertical scrollbar is visible, should be invisible.\n");
3183 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3184 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3185 si.nPage, si.nMin, si.nMax);
3186
3187 DestroyWindow(hwndRichEdit);
3188
3189 hwndRichEdit = new_richedit(NULL);
3190
3191 ShowScrollBar(hwndRichEdit, SB_VERT, FALSE);
3192 memset(&si, 0, sizeof(si));
3193 si.cbSize = sizeof(si);
3194 si.fMask = SIF_PAGE | SIF_RANGE;
3195 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3196 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3197 "Vertical scrollbar is visible, should be invisible.\n");
3198 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3199 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3200 si.nPage, si.nMin, si.nMax);
3201
3202 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3203 memset(&si, 0, sizeof(si));
3204 si.cbSize = sizeof(si);
3205 si.fMask = SIF_PAGE | SIF_RANGE;
3206 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3207 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3208 "Vertical scrollbar is visible, should be invisible.\n");
3209 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3210 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3211 si.nPage, si.nMin, si.nMax);
3212
3213 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
3214 memset(&si, 0, sizeof(si));
3215 si.cbSize = sizeof(si);
3216 si.fMask = SIF_PAGE | SIF_RANGE;
3217 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3218 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3219 "Vertical scrollbar is visible, should be invisible.\n");
3220 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3221 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3222 si.nPage, si.nMin, si.nMax);
3223
3224 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3225 memset(&si, 0, sizeof(si));
3226 si.cbSize = sizeof(si);
3227 si.fMask = SIF_PAGE | SIF_RANGE;
3228 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3229 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3230 "Vertical scrollbar is visible, should be invisible.\n");
3231 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3232 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3233 si.nPage, si.nMin, si.nMax);
3234
3235 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
3236 memset(&si, 0, sizeof(si));
3237 si.cbSize = sizeof(si);
3238 si.fMask = SIF_PAGE | SIF_RANGE;
3239 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3240 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3241 "Vertical scrollbar is invisible, should be visible.\n");
3242 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3243 "reported page/range is %d (%d..%d)\n",
3244 si.nPage, si.nMin, si.nMax);
3245
3246 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */
3247 ShowScrollBar(hwndRichEdit, SB_VERT, FALSE);
3248 memset(&si, 0, sizeof(si));
3249 si.cbSize = sizeof(si);
3250 si.fMask = SIF_PAGE | SIF_RANGE;
3251 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3252 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3253 "Vertical scrollbar is visible, should be invisible.\n");
3254 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3255 "reported page/range is %d (%d..%d)\n",
3256 si.nPage, si.nMin, si.nMax);
3257
3258 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
3259 memset(&si, 0, sizeof(si));
3260 si.cbSize = sizeof(si);
3261 si.fMask = SIF_PAGE | SIF_RANGE;
3262 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3263 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3264 "Vertical scrollbar is visible, should be invisible.\n");
3265 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3266 "reported page/range is %d (%d..%d)\n",
3267 si.nPage, si.nMin, si.nMax);
3268
3269 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that
3270 EM_SCROLL will make visible any forcefully invisible scrollbar */
3271 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0);
3272 memset(&si, 0, sizeof(si));
3273 si.cbSize = sizeof(si);
3274 si.fMask = SIF_PAGE | SIF_RANGE;
3275 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3276 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3277 "Vertical scrollbar is invisible, should be visible.\n");
3278 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3279 "reported page/range is %d (%d..%d)\n",
3280 si.nPage, si.nMin, si.nMax);
3281
3282 ShowScrollBar(hwndRichEdit, SB_VERT, FALSE);
3283 memset(&si, 0, sizeof(si));
3284 si.cbSize = sizeof(si);
3285 si.fMask = SIF_PAGE | SIF_RANGE;
3286 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3287 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3288 "Vertical scrollbar is visible, should be invisible.\n");
3289 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3290 "reported page/range is %d (%d..%d)\n",
3291 si.nPage, si.nMin, si.nMax);
3292
3293 /* Again, EM_SCROLL, with SB_LINEUP */
3294 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0);
3295 memset(&si, 0, sizeof(si));
3296 si.cbSize = sizeof(si);
3297 si.fMask = SIF_PAGE | SIF_RANGE;
3298 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3299 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3300 "Vertical scrollbar is invisible, should be visible.\n");
3301 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3302 "reported page/range is %d (%d..%d)\n",
3303 si.nPage, si.nMin, si.nMax);
3304
3305 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3306 memset(&si, 0, sizeof(si));
3307 si.cbSize = sizeof(si);
3308 si.fMask = SIF_PAGE | SIF_RANGE;
3309 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3310 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3311 "Vertical scrollbar is visible, should be invisible.\n");
3312 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3313 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3314 si.nPage, si.nMin, si.nMax);
3315
3316 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
3317 memset(&si, 0, sizeof(si));
3318 si.cbSize = sizeof(si);
3319 si.fMask = SIF_PAGE | SIF_RANGE;
3320 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3321 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3322 "Vertical scrollbar is invisible, should be visible.\n");
3323 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3324 "reported page/range is %d (%d..%d)\n",
3325 si.nPage, si.nMin, si.nMax);
3326
3327 DestroyWindow(hwndRichEdit);
3328
3329
3330 /* Test behavior with explicit visibility request, using SetWindowLongA()() */
3331 hwndRichEdit = new_richedit(NULL);
3332
3333#define ENABLE_WS_VSCROLL(hwnd) \
3334 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) | WS_VSCROLL)
3335#define DISABLE_WS_VSCROLL(hwnd) \
3336 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) & ~WS_VSCROLL)
3337
3338 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */
3339 ENABLE_WS_VSCROLL(hwndRichEdit);
3340 memset(&si, 0, sizeof(si));
3341 si.cbSize = sizeof(si);
3342 si.fMask = SIF_PAGE | SIF_RANGE;
3343 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3344 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3345 "Vertical scrollbar is invisible, should be visible.\n");
3346 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3347 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3348 si.nPage, si.nMin, si.nMax);
3349
3350 /* Ditto, see above */
3351 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3352 memset(&si, 0, sizeof(si));
3353 si.cbSize = sizeof(si);
3354 si.fMask = SIF_PAGE | SIF_RANGE;
3355 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3356 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3357 "Vertical scrollbar is invisible, should be visible.\n");
3358 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3359 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3360 si.nPage, si.nMin, si.nMax);
3361
3362 /* Ditto, see above */
3363 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
3364 memset(&si, 0, sizeof(si));
3365 si.cbSize = sizeof(si);
3366 si.fMask = SIF_PAGE | SIF_RANGE;
3367 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3368 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3369 "Vertical scrollbar is invisible, should be visible.\n");
3370 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3371 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3372 si.nPage, si.nMin, si.nMax);
3373
3374 /* Ditto, see above */
3375 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a\na");
3376 memset(&si, 0, sizeof(si));
3377 si.cbSize = sizeof(si);
3378 si.fMask = SIF_PAGE | SIF_RANGE;
3379 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3380 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3381 "Vertical scrollbar is invisible, should be visible.\n");
3382 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3383 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3384 si.nPage, si.nMin, si.nMax);
3385
3386 /* Ditto, see above */
3387 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3388 memset(&si, 0, sizeof(si));
3389 si.cbSize = sizeof(si);
3390 si.fMask = SIF_PAGE | SIF_RANGE;
3391 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3392 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3393 "Vertical scrollbar is invisible, should be visible.\n");
3394 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3395 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3396 si.nPage, si.nMin, si.nMax);
3397
3398 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
3399 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3400 memset(&si, 0, sizeof(si));
3401 si.cbSize = sizeof(si);
3402 si.fMask = SIF_PAGE | SIF_RANGE;
3403 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3404 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3405 "Vertical scrollbar is visible, should be invisible.\n");
3406 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3407 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3408 si.nPage, si.nMin, si.nMax);
3409
3410 DestroyWindow(hwndRichEdit);
3411
3412 hwndRichEdit = new_richedit(NULL);
3413
3414 DISABLE_WS_VSCROLL(hwndRichEdit);
3415 memset(&si, 0, sizeof(si));
3416 si.cbSize = sizeof(si);
3417 si.fMask = SIF_PAGE | SIF_RANGE;
3418 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3419 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3420 "Vertical scrollbar is visible, should be invisible.\n");
3421 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3422 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3423 si.nPage, si.nMin, si.nMax);
3424
3425 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3426 memset(&si, 0, sizeof(si));
3427 si.cbSize = sizeof(si);
3428 si.fMask = SIF_PAGE | SIF_RANGE;
3429 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3430 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3431 "Vertical scrollbar is visible, should be invisible.\n");
3432 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3433 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3434 si.nPage, si.nMin, si.nMax);
3435
3436 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
3437 memset(&si, 0, sizeof(si));
3438 si.cbSize = sizeof(si);
3439 si.fMask = SIF_PAGE | SIF_RANGE;
3440 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3441 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3442 "Vertical scrollbar is visible, should be invisible.\n");
3443 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3444 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3445 si.nPage, si.nMin, si.nMax);
3446
3447 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3448 memset(&si, 0, sizeof(si));
3449 si.cbSize = sizeof(si);
3450 si.fMask = SIF_PAGE | SIF_RANGE;
3451 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3452 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3453 "Vertical scrollbar is visible, should be invisible.\n");
3454 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3455 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3456 si.nPage, si.nMin, si.nMax);
3457
3458 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
3459 memset(&si, 0, sizeof(si));
3460 si.cbSize = sizeof(si);
3461 si.fMask = SIF_PAGE | SIF_RANGE;
3462 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3463 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3464 "Vertical scrollbar is invisible, should be visible.\n");
3465 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3466 "reported page/range is %d (%d..%d)\n",
3467 si.nPage, si.nMin, si.nMax);
3468
3469 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */
3470 DISABLE_WS_VSCROLL(hwndRichEdit);
3471 memset(&si, 0, sizeof(si));
3472 si.cbSize = sizeof(si);
3473 si.fMask = SIF_PAGE | SIF_RANGE;
3474 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3475 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3476 "Vertical scrollbar is visible, should be invisible.\n");
3477 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3478 "reported page/range is %d (%d..%d)\n",
3479 si.nPage, si.nMin, si.nMax);
3480
3481 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3482 memset(&si, 0, sizeof(si));
3483 si.cbSize = sizeof(si);
3484 si.fMask = SIF_PAGE | SIF_RANGE;
3485 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3486 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3487 "Vertical scrollbar is visible, should be invisible.\n");
3488 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3489 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3490 si.nPage, si.nMin, si.nMax);
3491
3492 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
3493 memset(&si, 0, sizeof(si));
3494 si.cbSize = sizeof(si);
3495 si.fMask = SIF_PAGE | SIF_RANGE;
3496 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3497 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3498 "Vertical scrollbar is invisible, should be visible.\n");
3499 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3500 "reported page/range is %d (%d..%d)\n",
3501 si.nPage, si.nMin, si.nMax);
3502
3503 DISABLE_WS_VSCROLL(hwndRichEdit);
3504 memset(&si, 0, sizeof(si));
3505 si.cbSize = sizeof(si);
3506 si.fMask = SIF_PAGE | SIF_RANGE;
3507 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3508 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3509 "Vertical scrollbar is visible, should be invisible.\n");
3510 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3511 "reported page/range is %d (%d..%d)\n",
3512 si.nPage, si.nMin, si.nMax);
3513
3514 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that
3515 EM_SCROLL will make visible any forcefully invisible scrollbar */
3516 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0);
3517 memset(&si, 0, sizeof(si));
3518 si.cbSize = sizeof(si);
3519 si.fMask = SIF_PAGE | SIF_RANGE;
3520 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3521 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3522 "Vertical scrollbar is invisible, should be visible.\n");
3523 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3524 "reported page/range is %d (%d..%d)\n",
3525 si.nPage, si.nMin, si.nMax);
3526
3527 DISABLE_WS_VSCROLL(hwndRichEdit);
3528 memset(&si, 0, sizeof(si));
3529 si.cbSize = sizeof(si);
3530 si.fMask = SIF_PAGE | SIF_RANGE;
3531 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3532 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3533 "Vertical scrollbar is visible, should be invisible.\n");
3534 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3535 "reported page/range is %d (%d..%d)\n",
3536 si.nPage, si.nMin, si.nMax);
3537
3538 /* Again, EM_SCROLL, with SB_LINEUP */
3539 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0);
3540 memset(&si, 0, sizeof(si));
3541 si.cbSize = sizeof(si);
3542 si.fMask = SIF_PAGE | SIF_RANGE;
3543 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3544 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3545 "Vertical scrollbar is invisible, should be visible.\n");
3546 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3547 "reported page/range is %d (%d..%d)\n",
3548 si.nPage, si.nMin, si.nMax);
3549
3550 DestroyWindow(hwndRichEdit);
3551
3552 /* This window proc models what is going on with Corman Lisp 3.0.
3553 At WM_SIZE, this proc unconditionally calls ShowScrollBar() to
3554 force the scrollbar into visibility. Recursion should NOT happen
3555 as a result of this action.
3556 */
3558 if (r) {
3559 richeditProc = cls.lpfnWndProc;
3561 cls.lpszClassName = "RicheditStupidOverride";
3562 if(!RegisterClassA(&cls)) assert(0);
3563
3564 recursionLevel = 0;
3567 hwndRichEdit = new_window(cls.lpszClassName, ES_MULTILINE, NULL);
3569 "WM_SIZE/scrollbar mutual recursion detected, expected none!\n");
3570
3571 recursionLevel = 0;
3574 MoveWindow(hwndRichEdit, 0, 0, 250, 100, TRUE);
3576 "WM_SIZE/scrollbar mutual recursion detected, expected none!\n");
3577
3578 /* Unblock window in order to process WM_DESTROY */
3579 recursionLevel = 0;
3582 DestroyWindow(hwndRichEdit);
3583 }
3584}
3585
3586static void test_EM_SETUNDOLIMIT(void)
3587{
3588 /* cases we test for:
3589 * default behaviour - limiting at 100 undo's
3590 * undo disabled - setting a limit of 0
3591 * undo limited - undo limit set to some to some number, like 2
3592 * bad input - sending a negative number should default to 100 undo's */
3593
3594 HWND hwndRichEdit = new_richedit(NULL);
3595 CHARRANGE cr;
3596 int i;
3597 int result;
3598
3599 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"x");
3600 cr.cpMin = 0;
3601 cr.cpMax = -1;
3602 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
3603
3604 SendMessageA(hwndRichEdit, WM_COPY, 0, 0);
3605 /*Load "x" into the clipboard. Paste is an easy, undo'able operation.
3606 also, multiple pastes don't combine like WM_CHAR would */
3607
3608 /* first case - check the default */
3609 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
3610 for (i=0; i<101; i++) /* Put 101 undo's on the stack */
3611 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
3612 for (i=0; i<100; i++) /* Undo 100 of them */
3613 SendMessageA(hwndRichEdit, WM_UNDO, 0, 0);
3614 ok(!SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0),
3615 "EM_SETUNDOLIMIT allowed more than a hundred undo's by default.\n");
3616
3617 /* second case - cannot undo */
3618 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0);
3619 SendMessageA(hwndRichEdit, EM_SETUNDOLIMIT, 0, 0);
3620 SendMessageA(hwndRichEdit,
3621 WM_PASTE, 0, 0); /* Try to put something in the undo stack */
3622 ok(!SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0),
3623 "EM_SETUNDOLIMIT allowed undo with UNDOLIMIT set to 0\n");
3624
3625 /* third case - set it to an arbitrary number */
3626 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0);
3627 SendMessageA(hwndRichEdit, EM_SETUNDOLIMIT, 2, 0);
3628 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
3629 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
3630 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
3631 /* If SETUNDOLIMIT is working, there should only be two undo's after this */
3632 ok(SendMessageA(hwndRichEdit, EM_CANUNDO, 0,0),
3633 "EM_SETUNDOLIMIT didn't allow the first undo with UNDOLIMIT set to 2\n");
3634 SendMessageA(hwndRichEdit, WM_UNDO, 0, 0);
3635 ok(SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0),
3636 "EM_SETUNDOLIMIT didn't allow a second undo with UNDOLIMIT set to 2\n");
3637 SendMessageA(hwndRichEdit, WM_UNDO, 0, 0);
3638 ok(!SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0),
3639 "EM_SETUNDOLIMIT allowed a third undo with UNDOLIMIT set to 2\n");
3640
3641 /* fourth case - setting negative numbers should default to 100 undos */
3642 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
3643 result = SendMessageA(hwndRichEdit, EM_SETUNDOLIMIT, -1, 0);
3644 ok (result == 100,
3645 "EM_SETUNDOLIMIT returned %d when set to -1, instead of 100\n",result);
3646
3647 DestroyWindow(hwndRichEdit);
3648}
3649
3650static void test_ES_PASSWORD(void)
3651{
3652 /* This isn't hugely testable, so we're just going to run it through its paces */
3653
3654 HWND hwndRichEdit = new_richedit(NULL);
3655 WCHAR result;
3656
3657 /* First, check the default of a regular control */
3658 result = SendMessageA(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
3659 ok (result == 0,
3660 "EM_GETPASSWORDCHAR returned %c by default, instead of NULL\n",result);
3661
3662 /* Now, set it to something normal */
3663 SendMessageA(hwndRichEdit, EM_SETPASSWORDCHAR, 'x', 0);
3664 result = SendMessageA(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
3665 ok (result == 120,
3666 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result);
3667
3668 /* Now, set it to something odd */
3669 SendMessageA(hwndRichEdit, EM_SETPASSWORDCHAR, (WCHAR)1234, 0);
3670 result = SendMessageA(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
3671 ok (result == 1234,
3672 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result);
3673 DestroyWindow(hwndRichEdit);
3674}
3675
3677
3679 LPBYTE pbBuff,
3680 LONG cb,
3681 LONG *pcb)
3682{
3683 char** str = (char**)dwCookie;
3684 *pcb = cb;
3685 if (*pcb > 0) {
3686 memcpy(*str, pbBuff, *pcb);
3687 *str += *pcb;
3688 }
3689 streamout_written = *pcb;
3690 return 0;
3691}
3692
3693static void test_WM_SETTEXT(void)
3694{
3695 HWND hwndRichEdit = new_richedit(NULL);
3696 const char * TestItem1 = "TestSomeText";
3697 const char * TestItem2 = "TestSomeText\r";
3698 const char * TestItem2_after = "TestSomeText\r\n";
3699 const char * TestItem3 = "TestSomeText\rSomeMoreText\r";
3700 const char * TestItem3_after = "TestSomeText\r\nSomeMoreText\r\n";
3701 const char * TestItem4 = "TestSomeText\n\nTestSomeText";
3702 const char * TestItem4_after = "TestSomeText\r\n\r\nTestSomeText";
3703 const char * TestItem5 = "TestSomeText\r\r\nTestSomeText";
3704 const char * TestItem5_after = "TestSomeText TestSomeText";
3705 const char * TestItem6 = "TestSomeText\r\r\n\rTestSomeText";
3706 const char * TestItem6_after = "TestSomeText \r\nTestSomeText";
3707 const char * TestItem7 = "TestSomeText\r\n\r\r\n\rTestSomeText";
3708 const char * TestItem7_after = "TestSomeText\r\n \r\nTestSomeText";
3709
3710 const char rtftextA[] = "{\\rtf sometext}";
3711 const char urtftextA[] = "{\\urtf sometext}";
3712 const WCHAR rtftextW[] = {'{','\\','r','t','f',' ','s','o','m','e','t','e','x','t','}',0};
3713 const WCHAR urtftextW[] = {'{','\\','u','r','t','f',' ','s','o','m','e','t','e','x','t','}',0};
3714 const WCHAR sometextW[] = {'s','o','m','e','t','e','x','t',0};
3715
3716 char buf[1024] = {0};
3717 WCHAR bufW[1024] = {0};
3719
3720 /* This test attempts to show that WM_SETTEXT on a riched20 control causes
3721 any solitary \r to be converted to \r\n on return. Properly paired
3722 \r\n are not affected. It also shows that the special sequence \r\r\n
3723 gets converted to a single space.
3724 */
3725
3726#define TEST_SETTEXT(a, b) \
3727 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)a); \
3728 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \
3729 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf); \
3730 ok (result == lstrlenA(buf), \
3731 "WM_GETTEXT returned %ld instead of expected %u\n", \
3732 result, lstrlenA(buf)); \
3733 result = strcmp(b, buf); \
3734 ok(result == 0, \
3735 "WM_SETTEXT round trip: strcmp = %ld, text=\"%s\"\n", result, buf);
3736
3737 TEST_SETTEXT(TestItem1, TestItem1)
3738 TEST_SETTEXT(TestItem2, TestItem2_after)
3739 TEST_SETTEXT(TestItem3, TestItem3_after)
3740 TEST_SETTEXT(TestItem3_after, TestItem3_after)
3741 TEST_SETTEXT(TestItem4, TestItem4_after)
3742 TEST_SETTEXT(TestItem5, TestItem5_after)
3743 TEST_SETTEXT(TestItem6, TestItem6_after)
3744 TEST_SETTEXT(TestItem7, TestItem7_after)
3745
3746 /* The following tests demonstrate that WM_SETTEXT supports RTF strings */
3747 TEST_SETTEXT(rtftextA, "sometext") /* interpreted as ascii rtf */
3748 TEST_SETTEXT(urtftextA, "sometext") /* interpreted as ascii rtf */
3749 TEST_SETTEXT(rtftextW, "{") /* interpreted as ascii text */
3750 TEST_SETTEXT(urtftextW, "{") /* interpreted as ascii text */
3751 DestroyWindow(hwndRichEdit);
3752#undef TEST_SETTEXT
3753
3754#define TEST_SETTEXTW(a, b) \
3755 result = SendMessageW(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)a); \
3756 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \
3757 result = SendMessageW(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufW); \
3758 ok (result == lstrlenW(bufW), \
3759 "WM_GETTEXT returned %ld instead of expected %u\n", \
3760 result, lstrlenW(bufW)); \
3761 result = lstrcmpW(b, bufW); \
3762 ok(result == 0, "WM_SETTEXT round trip: strcmp = %ld\n", result);
3763
3764 hwndRichEdit = CreateWindowW(RICHEDIT_CLASS20W, NULL,
3766 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
3767 ok(hwndRichEdit != NULL, "class: RichEdit20W, error: %d\n", (int) GetLastError());
3768 TEST_SETTEXTW(rtftextA, sometextW) /* interpreted as ascii rtf */
3769 TEST_SETTEXTW(urtftextA, sometextW) /* interpreted as ascii rtf */
3770 TEST_SETTEXTW(rtftextW, rtftextW) /* interpreted as ascii text */
3771 TEST_SETTEXTW(urtftextW, urtftextW) /* interpreted as ascii text */
3772 DestroyWindow(hwndRichEdit);
3773#undef TEST_SETTEXTW
3774
3775 /* Single-line richedit */
3776 hwndRichEdit = new_richedit_with_style(NULL, 0);
3777 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"line1\r\nline2");
3778 ok(result == 1, "WM_SETTEXT returned %ld, expected 12\n", result);
3779 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf);
3780 ok(result == 5, "WM_GETTEXT returned %ld, expected 5\n", result);
3781 ok(!strcmp(buf, "line1"), "WM_GETTEXT returned incorrect string '%s'\n", buf);
3782 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"{\\rtf1 ABC\\rtlpar\\par DEF\\par HIJ\\pard\\par}");
3783 ok(result == 1, "WM_SETTEXT returned %ld, expected 1\n", result);
3784 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf);
3785 ok(result == 3, "WM_GETTEXT returned %ld, expected 3\n", result);
3786 ok(!strcmp(buf, "ABC"), "WM_GETTEXT returned incorrect string '%s'\n", buf);
3787 DestroyWindow(hwndRichEdit);
3788}
3789
3790/* Set *pcb to one to show that the remaining cb-1 bytes are not
3791 resent to the callkack. */
3793 LPBYTE pbBuff,
3794 LONG cb,
3795 LONG *pcb)
3796{
3797 char** str = (char**)dwCookie;
3798 ok(*pcb == cb || *pcb == 0, "cb %d, *pcb %d\n", cb, *pcb);
3799 *pcb = 0;
3800 if (cb > 0) {
3801 memcpy(*str, pbBuff, cb);
3802 *str += cb;
3803 *pcb = 1;
3804 }
3805 return 0;
3806}
3807
3808static int count_pars(const char *buf)
3809{
3810 const char *p = buf;
3811 int count = 0;
3812 while ((p = strstr( p, "\\par" )) != NULL)
3813 {
3814 if (!isalpha( p[4] ))
3815 count++;
3816 p++;
3817 }
3818 return count;
3819}
3820
3821static void test_EM_STREAMOUT(void)
3822{
3823 HWND hwndRichEdit = new_richedit(NULL);
3824 int r;
3825 EDITSTREAM es;
3826 char buf[1024] = {0};
3827 char * p;
3829
3830 const char * TestItem1 = "TestSomeText";
3831 const char * TestItem2 = "TestSomeText\r";
3832 const char * TestItem3 = "TestSomeText\r\n";
3833
3834 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem1);
3835 p = buf;
3836 es.dwCookie = (DWORD_PTR)&p;
3837 es.dwError = 0;
3838 es.pfnCallback = test_WM_SETTEXT_esCallback;
3839 memset(buf, 0, sizeof(buf));
3840 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_TEXT, (LPARAM)&es);
3841 r = strlen(buf);
3842 ok(r == 12, "streamed text length is %d, expecting 12\n", r);
3843 ok(strcmp(buf, TestItem1) == 0,
3844 "streamed text different, got %s\n", buf);
3845 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written);
3846
3847 /* RTF mode writes the final end of para \r if it's part of the selection */
3848 p = buf;
3849 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF, (LPARAM)&es);
3850 ok (count_pars(buf) == 1, "got %s\n", buf);
3851 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written);
3852 p = buf;
3853 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 12);
3855 ok (count_pars(buf) == 0, "got %s\n", buf);
3856 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written);
3857 p = buf;
3858 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
3860 ok (count_pars(buf) == 1, "got %s\n", buf);
3861 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written);
3862
3863 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem2);
3864 p = buf;
3865 es.dwCookie = (DWORD_PTR)&p;
3866 es.dwError = 0;
3867 es.pfnCallback = test_WM_SETTEXT_esCallback;
3868 memset(buf, 0, sizeof(buf));
3869 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_TEXT, (LPARAM)&es);
3870 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written);
3871 r = strlen(buf);
3872 /* Here again, \r gets converted to \r\n, like WM_GETTEXT */
3873 ok(r == 14, "streamed text length is %d, expecting 14\n", r);
3874 ok(strcmp(buf, TestItem3) == 0,
3875 "streamed text different from, got %s\n", buf);
3876
3877 /* And again RTF mode writes the final end of para \r if it's part of the selection */
3878 p = buf;
3879 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF, (LPARAM)&es);
3880 ok (count_pars(buf) == 2, "got %s\n", buf);
3881 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written);
3882 p = buf;
3883 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 13);
3885 ok (count_pars(buf) == 1, "got %s\n", buf);
3886 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written);
3887 p = buf;
3888 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
3890 ok (count_pars(buf) == 2, "got %s\n", buf);
3891 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written);
3892
3893 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem3);
3894 p = buf;
3895 es.dwCookie = (DWORD_PTR)&p;
3896 es.dwError = 0;
3897 es.pfnCallback = test_WM_SETTEXT_esCallback;
3898 memset(buf, 0, sizeof(buf));
3899 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_TEXT, (LPARAM)&es);
3900 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written);
3901 r = strlen(buf);
3902 ok(r == 14, "streamed text length is %d, expecting 14\n", r);
3903 ok(strcmp(buf, TestItem3) == 0,
3904 "streamed text different, got %s\n", buf);
3905
3906 /* Use a callback that sets *pcb to one */
3907 p = buf;
3908 es.dwCookie = (DWORD_PTR)&p;
3909 es.dwError = 0;
3910 es.pfnCallback = test_esCallback_written_1;
3911 memset(buf, 0, sizeof(buf));
3912 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_TEXT, (LPARAM)&es);
3913 r = strlen(buf);
3914 ok(r == 14, "streamed text length is %d, expecting 14\n", r);
3915 ok(strcmp(buf, TestItem3) == 0,
3916 "streamed text different, got %s\n", buf);
3917 ok(result == 0, "got %ld expected 0\n", result);
3918
3919
3920 DestroyWindow(hwndRichEdit);
3921}
3922
3924{
3925 HWND hwndRichEdit = new_richedit(NULL);
3926 EDITSTREAM es;
3927 char buf[1024] = {0};
3928 char * p;
3929 char * fontTbl;
3930 int brackCount;
3931
3932 const char * TestItem = "TestSomeText";
3933
3934 /* fills in the richedit control with some text */
3935 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem);
3936
3937 /* streams out the text in rtf format */
3938 p = buf;
3939 es.dwCookie = (DWORD_PTR)&p;
3940 es.dwError = 0;
3941 es.pfnCallback = test_WM_SETTEXT_esCallback;
3942 memset(buf, 0, sizeof(buf));
3943 SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF, (LPARAM)&es);
3944
3945 /* scans for \fonttbl, error if not found */
3946 fontTbl = strstr(buf, "\\fonttbl");
3947 ok(fontTbl != NULL, "missing \\fonttbl section\n");
3948 if(fontTbl)
3949 {
3950 /* scans for terminating closing bracket */
3951 brackCount = 1;
3952 while(*fontTbl && brackCount)
3953 {
3954 if(*fontTbl == '{')
3955 brackCount++;
3956 else if(*fontTbl == '}')
3957 brackCount--;
3958 fontTbl++;
3959 }
3960 /* checks whether closing bracket is ok */
3961 ok(brackCount == 0, "missing closing bracket in \\fonttbl block\n");
3962 if(!brackCount)
3963 {
3964 /* char before closing fonttbl block should be a closed bracket */
3965 fontTbl -= 2;
3966 ok(*fontTbl == '}', "spurious character '%02x' before \\fonttbl closing bracket\n", *fontTbl);
3967
3968 /* char after fonttbl block should be a crlf */
3969 fontTbl += 2;
3970 ok(*fontTbl == 0x0d && *(fontTbl+1) == 0x0a, "missing crlf after \\fonttbl block\n");
3971 }
3972 }
3973 DestroyWindow(hwndRichEdit);
3974}
3975
3977{
3979 char buf[1024], *p = buf;
3980 EDITSTREAM es;
3981
3983
3984 memset(buf, 0, sizeof(buf));
3985 es.dwCookie = (DWORD_PTR)&p;
3986 es.dwError = 0;
3987 es.pfnCallback = test_WM_SETTEXT_esCallback;
3988
3990 ok((p = strstr(buf, "\\pard")) != NULL, "missing \\pard\n");
3991 ok(((p = strstr(p, "\\fs")) && isdigit(p[3])), "missing \\fs\n");
3992
3994}
3995
3996static void test_EM_SETTEXTEX(void)
3997{
3998 HWND hwndRichEdit, parent;
3999 SCROLLINFO si;
4000 int sel_start, sel_end;
4001 SETTEXTEX setText;
4002 GETTEXTEX getText;
4003 WCHAR TestItem1[] = {'T', 'e', 's', 't',
4004 'S', 'o', 'm', 'e',
4005 'T', 'e', 'x', 't', 0};
4006 WCHAR TestItem1alt[] = {'T', 'T', 'e', 's',
4007 't', 'S', 'o', 'm',
4008 'e', 'T', 'e', 'x',
4009 't', 't', 'S', 'o',
4010 'm', 'e', 'T', 'e',
4011 'x', 't', 0};
4012 WCHAR TestItem1altn[] = {'T','T','e','s','t','S','o','m','e','T','e','x','t',
4013 '\r','t','S','o','m','e','T','e','x','t',0};
4014 WCHAR TestItem2[] = {'T', 'e', 's', 't',
4015 'S', 'o', 'm', 'e',
4016 'T', 'e', 'x', 't',
4017 '\r', 0};
4018 const char * TestItem2_after = "TestSomeText\r\n";
4019 WCHAR TestItem3[] = {'T', 'e', 's', 't',
4020 'S', 'o', 'm', 'e',
4021 'T', 'e', 'x', 't',
4022 '\r','\n','\r','\n', 0};
4023 WCHAR TestItem3alt[] = {'T', 'e', 's', 't',
4024 'S', 'o', 'm', 'e',
4025 'T', 'e', 'x', 't',
4026 '\n','\n', 0};
4027 WCHAR TestItem3_after[] = {'T', 'e', 's', 't',
4028 'S', 'o', 'm', 'e',
4029 'T', 'e', 'x', 't',
4030 '\r','\r', 0};
4031 WCHAR TestItem4[] = {'T', 'e', 's', 't',
4032 'S', 'o', 'm', 'e',
4033 'T', 'e', 'x', 't',
4034 '\r','\r','\n','\r',
4035 '\n', 0};
4036 WCHAR TestItem4_after[] = {'T', 'e', 's', 't',
4037 'S', 'o', 'm', 'e',
4038 'T', 'e', 'x', 't',
4039 ' ','\r', 0};
4040#define MAX_BUF_LEN 1024
4042 char bufACP[MAX_BUF_LEN];
4043 char * p;
4044 int result;
4045 CHARRANGE cr;
4046 EDITSTREAM es;
4047 WNDCLASSA cls;
4048
4049 /* Test the scroll position with and without a parent window.
4050 *
4051 * For some reason the scroll position is 0 after EM_SETTEXTEX
4052 * with the ST_SELECTION flag only when the control has a parent
4053 * window, even though the selection is at the end. */
4054 cls.style = 0;
4056 cls.cbClsExtra = 0;
4057 cls.cbWndExtra = 0;
4058 cls.hInstance = GetModuleHandleA(0);
4059 cls.hIcon = 0;
4062 cls.lpszMenuName = NULL;
4063 cls.lpszClassName = "ParentTestClass";
4064 if(!RegisterClassA(&cls)) assert(0);
4065
4067 0, 0, 200, 60, NULL, NULL, NULL, NULL);
4068 ok (parent != 0, "Failed to create parent window\n");
4069
4070 hwndRichEdit = CreateWindowExA(0,
4073 0, 0, 200, 60, parent, NULL,
4075
4076 setText.codepage = CP_ACP;
4077 setText.flags = ST_SELECTION;
4078 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText,
4079 (LPARAM)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
4080 todo_wine ok(result == 18, "EM_SETTEXTEX returned %d, expected 18\n", result);
4081 si.cbSize = sizeof(si);
4082 si.fMask = SIF_ALL;
4083 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
4084 todo_wine ok(si.nPos == 0, "Position is incorrectly at %d\n", si.nPos);
4085 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
4086 ok(sel_start == 18, "Selection start incorrectly at %d\n", sel_start);
4087 ok(sel_end == 18, "Selection end incorrectly at %d\n", sel_end);
4088
4090
4091 /* Test without a parent window */
4092 hwndRichEdit = new_richedit(NULL);
4093 setText.codepage = CP_ACP;
4094 setText.flags = ST_SELECTION;
4095 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText,
4096 (LPARAM)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
4097 todo_wine ok(result == 18, "EM_SETTEXTEX returned %d, expected 18\n", result);
4098 si.cbSize = sizeof(si);
4099 si.fMask = SIF_ALL;
4100 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
4101 ok(si.nPos != 0, "Position is incorrectly at %d\n", si.nPos);
4102 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
4103 ok(sel_start == 18, "Selection start incorrectly at %d\n", sel_start);
4104 ok(sel_end == 18, "Selection end incorrectly at %d\n", sel_end);
4105
4106 /* The scroll position should also be 0 after EM_SETTEXTEX with ST_DEFAULT,
4107 * but this time it is because the selection is at the beginning. */
4108 setText.codepage = CP_ACP;
4109 setText.flags = ST_DEFAULT;
4110 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText,
4111 (LPARAM)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
4112 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4113 si.cbSize = sizeof(si);
4114 si.fMask = SIF_ALL;
4115 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
4116 ok(si.nPos == 0, "Position is incorrectly at %d\n", si.nPos);
4117 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
4118 ok(sel_start == 0, "Selection start incorrectly at %d\n", sel_start);
4119 ok(sel_end == 0, "Selection end incorrectly at %d\n", sel_end);
4120
4121 setText.codepage = 1200; /* no constant for unicode */
4122 getText.codepage = 1200; /* no constant for unicode */
4123 getText.cb = MAX_BUF_LEN;
4124 getText.flags = GT_DEFAULT;
4125 getText.lpDefaultChar = NULL;
4126 getText.lpUsedDefChar = NULL;
4127
4128 setText.flags = 0;
4129 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
4130 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4131 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4132 ok(lstrcmpW(buf, TestItem1) == 0,
4133 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
4134
4135 /* Unlike WM_SETTEXT/WM_GETTEXT pair, EM_SETTEXTEX/EM_GETTEXTEX does not
4136 convert \r to \r\n on return: !ST_SELECTION && Unicode && !\rtf
4137 */
4138 setText.codepage = 1200; /* no constant for unicode */
4139 getText.codepage = 1200; /* no constant for unicode */
4140 getText.cb = MAX_BUF_LEN;
4141 getText.flags = GT_DEFAULT;
4142 getText.lpDefaultChar = NULL;
4143 getText.lpUsedDefChar = NULL;
4144 setText.flags = 0;
4145 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem2);
4146 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4147 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4148 ok(lstrcmpW(buf, TestItem2) == 0,
4149 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
4150
4151 /* However, WM_GETTEXT *does* see \r\n where EM_GETTEXTEX would see \r */
4152 SendMessageA(hwndRichEdit, WM_GETTEXT, MAX_BUF_LEN, (LPARAM)buf);
4153 ok(strcmp((const char *)buf, TestItem2_after) == 0,
4154 "WM_GETTEXT did *not* see \\r converted to \\r\\n pairs.\n");
4155
4156 /* Baseline test for just-enough buffer space for string */
4157 getText.cb = (lstrlenW(TestItem2) + 1) * sizeof(WCHAR);
4158 getText.codepage = 1200; /* no constant for unicode */
4159 getText.flags = GT_DEFAULT;
4160 getText.lpDefaultChar = NULL;
4161 getText.lpUsedDefChar = NULL;
4162 memset(buf, 0, sizeof(buf));
4163 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4164 ok(lstrcmpW(buf, TestItem2) == 0,
4165 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
4166
4167 /* When there is enough space for one character, but not both, of the CRLF
4168 pair at the end of the string, the CR is not copied at all. That is,
4169 the caller must not see CRLF pairs truncated to CR at the end of the
4170 string.
4171 */
4172 getText.cb = (lstrlenW(TestItem2) + 1) * sizeof(WCHAR);
4173 getText.codepage = 1200; /* no constant for unicode */
4174 getText.flags = GT_USECRLF; /* <-- asking for CR -> CRLF conversion */
4175 getText.lpDefaultChar = NULL;
4176 getText.lpUsedDefChar = NULL;
4177 memset(buf, 0, sizeof(buf));
4178 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4179 ok(lstrcmpW(buf, TestItem1) == 0,
4180 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
4181
4182
4183 /* \r\n pairs get changed into \r: !ST_SELECTION && Unicode && !\rtf */
4184 setText.codepage = 1200; /* no constant for unicode */
4185 getText.codepage = 1200; /* no constant for unicode */
4186 getText.cb = MAX_BUF_LEN;
4187 getText.flags = GT_DEFAULT;
4188 getText.lpDefaultChar = NULL;
4189 getText.lpUsedDefChar = NULL;
4190 setText.flags = 0;
4191 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem3);
4192 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4193 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4194 ok(lstrcmpW(buf, TestItem3_after) == 0,
4195 "EM_SETTEXTEX did not convert properly\n");
4196
4197 /* \n also gets changed to \r: !ST_SELECTION && Unicode && !\rtf */
4198 setText.codepage = 1200; /* no constant for unicode */
4199 getText.codepage = 1200; /* no constant for unicode */
4200 getText.cb = MAX_BUF_LEN;
4201 getText.flags = GT_DEFAULT;
4202 getText.lpDefaultChar = NULL;
4203 getText.lpUsedDefChar = NULL;
4204 setText.flags = 0;
4205 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem3alt);
4206 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4207 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4208 ok(lstrcmpW(buf, TestItem3_after) == 0,
4209 "EM_SETTEXTEX did not convert properly\n");
4210
4211 /* \r\r\n gets changed into single space: !ST_SELECTION && Unicode && !\rtf */
4212 setText.codepage = 1200; /* no constant for unicode */
4213 getText.codepage = 1200; /* no constant for unicode */
4214 getText.cb = MAX_BUF_LEN;
4215 getText.flags = GT_DEFAULT;
4216 getText.lpDefaultChar = NULL;
4217 getText.lpUsedDefChar = NULL;
4218 setText.flags = 0;
4219 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem4);
4220 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4221 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4222 ok(lstrcmpW(buf, TestItem4_after) == 0,
4223 "EM_SETTEXTEX did not convert properly\n");
4224
4225 /* !ST_SELECTION && Unicode && !\rtf */
4226 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, 0);
4227 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4228
4229 ok (result == 1,
4230 "EM_SETTEXTEX returned %d, instead of 1\n",result);
4231 ok(!buf[0], "EM_SETTEXTEX with NULL lParam should clear rich edit.\n");
4232
4233 /* put some text back: !ST_SELECTION && Unicode && !\rtf */
4234 setText.flags = 0;
4235 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
4236 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4237 /* select some text */
4238 cr.cpMax = 1;
4239 cr.cpMin = 3;
4240 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
4241 /* replace current selection: ST_SELECTION && Unicode && !\rtf */
4242 setText.flags = ST_SELECTION;
4243 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, 0);
4244 ok(result == 0,
4245 "EM_SETTEXTEX with NULL lParam to replace selection"
4246 " with no text should return 0. Got %i\n",
4247 result);
4248
4249 /* put some text back: !ST_SELECTION && Unicode && !\rtf */
4250 setText.flags = 0;
4251 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
4252 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4253 /* select some text */
4254 cr.cpMax = 1;
4255 cr.cpMin = 3;
4256 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
4257 /* replace current selection: ST_SELECTION && Unicode && !\rtf */
4258 setText.flags = ST_SELECTION;
4259 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
4260 /* get text */
4261 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4262 ok(result == lstrlenW(TestItem1),
4263 "EM_SETTEXTEX with NULL lParam to replace selection"
4264 " with no text should return 0. Got %i\n",
4265 result);
4266 ok(lstrlenW(buf) == 22,
4267 "EM_SETTEXTEX to replace selection with more text failed: %i.\n",
4268 lstrlenW(buf) );
4269
4270 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings */
4271 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"TestSomeText"); /* TestItem1 */
4272 p = (char *)buf;
4273 es.dwCookie = (DWORD_PTR)&p;
4274 es.dwError = 0;
4275 es.pfnCallback = test_WM_SETTEXT_esCallback;
4276 memset(buf, 0, sizeof(buf));
4277 SendMessageA(hwndRichEdit, EM_STREAMOUT,
4278 (WPARAM)(SF_RTF), (LPARAM)&es);
4279 trace("EM_STREAMOUT produced:\n%s\n", (char *)buf);
4280
4281 /* !ST_SELECTION && !Unicode && \rtf */
4282 setText.codepage = CP_ACP;/* EM_STREAMOUT saved as ANSI string */
4283 getText.codepage = 1200; /* no constant for unicode */
4284 getText.cb = MAX_BUF_LEN;
4285 getText.flags = GT_DEFAULT;
4286 getText.lpDefaultChar = NULL;
4287 getText.lpUsedDefChar = NULL;
4288
4289 setText.flags = 0;
4290 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)buf);
4291 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4292 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4293 ok(lstrcmpW(buf, TestItem1) == 0,
4294 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
4295
4296 /* The following test demonstrates that EM_SETTEXTEX treats text as ASCII if it
4297 * starts with ASCII characters "{\rtf" even when the codepage is unicode. */
4298 setText.codepage = 1200; /* Lie about code page (actual ASCII) */
4299 getText.codepage = CP_ACP;
4300 getText.cb = MAX_BUF_LEN;
4301 getText.flags = GT_DEFAULT;
4302 getText.lpDefaultChar = NULL;
4303 getText.lpUsedDefChar = NULL;
4304
4305 setText.flags = ST_SELECTION;
4306 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
4307 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"{\\rtf not unicode}");
4308 todo_wine ok(result == 11, "EM_SETTEXTEX incorrectly returned %d\n", result);
4309 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)bufACP);
4310 ok(lstrcmpA(bufACP, "not unicode") == 0, "'%s' != 'not unicode'\n", bufACP);
4311
4312 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings with a selection */
4313 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"TestSomeText"); /* TestItem1 */
4314 p = (char *)buf;
4315 es.dwCookie = (DWORD_PTR)&p;
4316 es.dwError = 0;
4317 es.pfnCallback = test_WM_SETTEXT_esCallback;
4318 memset(buf, 0, sizeof(buf));
4319 SendMessageA(hwndRichEdit, EM_STREAMOUT,
4320 (WPARAM)(SF_RTF), (LPARAM)&es);
4321 trace("EM_STREAMOUT produced:\n%s\n", (char *)buf);
4322
4323 /* select some text */
4324 cr.cpMax = 1;
4325 cr.cpMin = 3;
4326 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
4327
4328 /* ST_SELECTION && !Unicode && \rtf */
4329 setText.codepage = CP_ACP;/* EM_STREAMOUT saved as ANSI string */
4330 getText.codepage = 1200; /* no constant for unicode */
4331 getText.cb = MAX_BUF_LEN;
4332 getText.flags = GT_DEFAULT;
4333 getText.lpDefaultChar = NULL;
4334 getText.lpUsedDefChar = NULL;
4335
4336 setText.flags = ST_SELECTION;
4337 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)buf);
4338 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4339 ok_w3("Expected \"%s\" or \"%s\", got \"%s\"\n", TestItem1alt, TestItem1altn, buf);
4340
4341 /* The following test demonstrates that EM_SETTEXTEX replacing a selection */
4342 setText.codepage = 1200; /* no constant for unicode */
4343 getText.codepage = CP_ACP;
4344 getText.cb = MAX_BUF_LEN;
4345
4346 setText.flags = 0;
4347 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1); /* TestItem1 */
4348 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)bufACP);
4349
4350 /* select some text */
4351 cr.cpMax = 1;
4352 cr.cpMin = 3;
4353 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
4354
4355 /* ST_SELECTION && !Unicode && !\rtf */
4356 setText.codepage = CP_ACP;
4357 getText.codepage = 1200; /* no constant for unicode */
4358 getText.cb = MAX_BUF_LEN;
4359 getText.flags = GT_DEFAULT;
4360 getText.lpDefaultChar = NULL;
4361 getText.lpUsedDefChar = NULL;
4362
4363 setText.flags = ST_SELECTION;
4364 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)bufACP);
4365 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4366 ok(lstrcmpW(buf, TestItem1alt) == 0,
4367 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX when"
4368 " using ST_SELECTION and non-Unicode\n");
4369
4370 /* Test setting text using rich text format */
4371 setText.flags = 0;
4372 setText.codepage = CP_ACP;
4373 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"{\\rtf richtext}");
4374 getText.codepage = CP_ACP;
4375 getText.cb = MAX_BUF_LEN;
4376 getText.flags = GT_DEFAULT;
4377 getText.lpDefaultChar = NULL;
4378 getText.lpUsedDefChar = NULL;
4379 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)bufACP);
4380 ok(!strcmp(bufACP, "richtext"), "expected 'richtext' but got '%s'\n", bufACP);
4381
4382 setText.flags = 0;
4383 setText.codepage = CP_ACP;
4384 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"{\\urtf morerichtext}");
4385 getText.codepage = CP_ACP;
4386 getText.cb = MAX_BUF_LEN;
4387 getText.flags = GT_DEFAULT;
4388 getText.lpDefaultChar = NULL;
4389 getText.lpUsedDefChar = NULL;
4390 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)bufACP);
4391 ok(!strcmp(bufACP, "morerichtext"), "expected 'morerichtext' but got '%s'\n", bufACP);
4392
4393 /* test for utf8 text with BOM */
4394 setText.flags = 0;
4395 setText.codepage = CP_ACP;
4396 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"\xef\xbb\xbfTestUTF8WithBOM");
4397 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP);
4398 ok(result == 15, "EM_SETTEXTEX: Test UTF8 with BOM returned %d, expected 15\n", result);
4399 result = strcmp(bufACP, "TestUTF8WithBOM");
4400 ok(result == 0, "EM_SETTEXTEX: Test UTF8 with BOM set wrong text: Result: %s\n", bufACP);
4401
4402 setText.flags = 0;
4403 setText.codepage = CP_UTF8;
4404 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"\xef\xbb\xbfTestUTF8WithBOM");
4405 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP);
4406 ok(result == 15, "EM_SETTEXTEX: Test UTF8 with BOM returned %d, expected 15\n", result);
4407 result = strcmp(bufACP, "TestUTF8WithBOM");
4408 ok(result == 0, "EM_SETTEXTEX: Test UTF8 with BOM set wrong text: Result: %s\n", bufACP);
4409
4410 /* Test multibyte character */
4411 if (!is_lang_japanese)
4412 skip("Skip multibyte character tests on non-Japanese platform\n");
4413 else
4414 {
4415 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
4416 setText.flags = ST_SELECTION;
4417 setText.codepage = CP_ACP;
4418 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"abc\x8e\xf0");
4419 todo_wine ok(result == 5, "EM_SETTEXTEX incorrectly returned %d, expected 5\n", result);
4420 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP);
4421 ok(result == 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result);
4422 ok(!strcmp(bufACP, "abc\x8e\xf0"),
4423 "EM_SETTEXTEX: Test multibyte character set wrong text: Result: %s\n", bufACP);
4424
4425 setText.flags = ST_DEFAULT;
4426 setText.codepage = CP_ACP;
4427 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"abc\x8e\xf0");
4428 ok(result == 1, "EM_SETTEXTEX incorrectly returned %d, expected 1\n", result);
4429 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP);
4430 ok(result == 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result);
4431 ok(!strcmp(bufACP, "abc\x8e\xf0"),
4432 "EM_SETTEXTEX: Test multibyte character set wrong text: Result: %s\n", bufACP);
4433
4434 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
4435 setText.flags = ST_SELECTION;
4436 setText.codepage = CP_ACP;
4437 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"{\\rtf abc\x8e\xf0}");
4438 todo_wine ok(result == 4, "EM_SETTEXTEX incorrectly returned %d, expected 4\n", result);
4439 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP);
4440 ok(result == 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result);
4441 todo_wine ok(!strcmp(bufACP, "abc\x8e\xf0"),
4442 "EM_SETTEXTEX: Test multibyte character set wrong text: Result: %s\n", bufACP);
4443 }
4444
4445 DestroyWindow(hwndRichEdit);
4446
4447 /* Single-line richedit */
4448 hwndRichEdit = new_richedit_with_style(NULL, 0);
4449 setText.flags = ST_DEFAULT;
4450 setText.codepage = CP_ACP;
4451 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"line1\r\nline2");
4452 ok(result == 1, "EM_SETTEXTEX incorrectly returned %d, expected 1\n", result);
4453 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP);
4454 ok(result == 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result);
4455 ok(!strcmp(bufACP, "line1"), "EM_SETTEXTEX: Test single-line text: Result: %s\n", bufACP);
4456 DestroyWindow(hwndRichEdit);
4457}
4458
4459static void test_EM_LIMITTEXT(void)
4460{
4461 int ret;
4462
4463 HWND hwndRichEdit = new_richedit(NULL);
4464
4465 /* The main purpose of this test is to demonstrate that the nonsense in MSDN
4466 * about setting the length to -1 for multiline edit controls doesn't happen.
4467 */
4468
4469 /* Don't check default gettextlimit case. That's done in other tests */
4470
4471 /* Set textlimit to 100 */
4472 SendMessageA(hwndRichEdit, EM_LIMITTEXT, 100, 0);
4473 ret = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4474 ok (ret == 100,
4475 "EM_LIMITTEXT: set to 100, returned: %d, expected: 100\n", ret);
4476
4477 /* Set textlimit to 0 */
4478 SendMessageA(hwndRichEdit, EM_LIMITTEXT, 0, 0);
4479 ret = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4480 ok (ret == 65536,
4481 "EM_LIMITTEXT: set to 0, returned: %d, expected: 65536\n", ret);
4482
4483 /* Set textlimit to -1 */
4484 SendMessageA(hwndRichEdit, EM_LIMITTEXT, -1, 0);
4485 ret = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4486 ok (ret == -1,
4487 "EM_LIMITTEXT: set to -1, returned: %d, expected: -1\n", ret);
4488
4489 /* Set textlimit to -2 */
4490 SendMessageA(hwndRichEdit, EM_LIMITTEXT, -2, 0);
4491 ret = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4492 ok (ret == -2,
4493 "EM_LIMITTEXT: set to -2, returned: %d, expected: -2\n", ret);
4494
4495 DestroyWindow (hwndRichEdit);
4496}
4497
4498
4499static void test_EM_EXLIMITTEXT(void)
4500{
4501 int i, selBegin, selEnd, len1, len2;
4502 int result;
4503 char text[1024 + 1];
4504 char buffer[1024 + 1];
4505 int textlimit = 0; /* multiple of 100 */
4506 HWND hwndRichEdit = new_richedit(NULL);
4507
4508 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4509 ok(32767 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 32767, i); /* default */
4510
4511 textlimit = 256000;
4512 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
4513 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4514 /* set higher */
4515 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i);
4516
4517 textlimit = 1000;
4518 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
4519 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4520 /* set lower */
4521 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i);
4522
4523 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, 0);
4524 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4525 /* default for WParam = 0 */
4526 ok(65536 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 65536, i);
4527
4528 textlimit = sizeof(text)-1;
4529 memset(text, 'W', textlimit);
4530 text[sizeof(text)-1] = 0;
4531 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
4532 /* maxed out text */
4533 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
4534
4535 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); /* select everything */
4536 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
4537 len1 = selEnd - selBegin;
4538
4539 SendMessageA(hwndRichEdit, WM_KEYDOWN, VK_BACK, 1);
4540 SendMessageA(hwndRichEdit, WM_CHAR, VK_BACK, 1);
4541 SendMessageA(hwndRichEdit, WM_KEYUP, VK_BACK, 1);
4542 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
4543 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
4544 len2 = selEnd - selBegin;
4545
4546 ok(len1 != len2,
4547 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4548 len1,len2,i);
4549
4550 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'A', 1);
4551 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 1);
4552 SendMessageA(hwndRichEdit, WM_KEYUP, 'A', 1);
4553 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
4554 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
4555 len1 = selEnd - selBegin;
4556
4557 ok(len1 != len2,
4558 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4559 len1,len2,i);
4560
4561 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'A', 1);
4562 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 1);
4563 SendMessageA(hwndRichEdit, WM_KEYUP, 'A', 1); /* full; should be no effect */
4564 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
4565 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
4566 len2 = selEnd - selBegin;
4567
4568 ok(len1 == len2,
4569 "EM_EXLIMITTEXT: No Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4570 len1,len2,i);
4571
4572 /* set text up to the limit, select all the text, then add a char */
4573 textlimit = 5;
4574 memset(text, 'W', textlimit);
4575 text[textlimit] = 0;
4576 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
4577 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
4578 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
4579 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 1);
4580 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
4581 result = strcmp(buffer, "A");
4582 ok(0 == result, "got string = \"%s\"\n", buffer);
4583
4584 /* WM_SETTEXT not limited */
4585 textlimit = 10;
4586 memset(text, 'W', textlimit);
4587 text[textlimit] = 0;
4588 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit-5);
4589 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
4590 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
4591 i = strlen(buffer);
4592 ok(10 == i, "expected 10 chars\n");
4593 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4594 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
4595
4596 /* try inserting more text at end */
4597 i = SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0);
4598 ok(0 == i, "WM_CHAR wasn't processed\n");
4599 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
4600 i = strlen(buffer);
4601 ok(10 == i, "expected 10 chars, got %i\n", i);
4602 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4603 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
4604
4605 /* try inserting text at beginning */
4606 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 0);
4607 i = SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0);
4608 ok(0 == i, "WM_CHAR wasn't processed\n");
4609 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
4610 i = strlen(buffer);
4611 ok(10 == i, "expected 10 chars, got %i\n", i);
4612 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4613 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
4614
4615 /* WM_CHAR is limited */
4616 textlimit = 1;
4617 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
4618 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); /* select everything */
4619 i = SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0);
4620 ok(0 == i, "WM_CHAR wasn't processed\n");
4621 i = SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0);
4622 ok(0 == i, "WM_CHAR wasn't processed\n");
4623 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
4624 i = strlen(buffer);
4625 ok(1 == i, "expected 1 chars, got %i instead\n", i);
4626
4627 DestroyWindow(hwndRichEdit);
4628}
4629
4630static void test_EM_GETLIMITTEXT(void)
4631{
4632 int i;
4633 HWND hwndRichEdit = new_richedit(NULL);
4634
4635 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4636 ok(32767 == i, "expected: %d, actual: %d\n", 32767, i); /* default value */
4637
4638 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, 50000);
4639 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4640 ok(50000 == i, "expected: %d, actual: %d\n", 50000, i);
4641
4642 DestroyWindow(hwndRichEdit);
4643}
4644
4645static void test_WM_SETFONT(void)
4646{
4647 /* There is no invalid input or error conditions for this function.
4648 * NULL wParam and lParam just fall back to their default values
4649 * It should be noted that even if you use a gibberish name for your fonts
4650 * here, it will still work because the name is stored. They will display as
4651 * System, but will report their name to be whatever they were created as */
4652
4653 HWND hwndRichEdit = new_richedit(NULL);
4654 HFONT testFont1 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
4656 FF_DONTCARE, "Marlett");
4657 HFONT testFont2 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
4659 FF_DONTCARE, "MS Sans Serif");
4660 HFONT testFont3 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
4662 FF_DONTCARE, "Courier");
4663 LOGFONTA sentLogFont;
4664 CHARFORMAT2A returnedCF2A;
4665
4666 returnedCF2A.cbSize = sizeof(returnedCF2A);
4667
4668 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"x");
4669 SendMessageA(hwndRichEdit, WM_SETFONT, (WPARAM)testFont1, MAKELPARAM(TRUE, 0));
4670 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&returnedCF2A);
4671
4672 GetObjectA(testFont1, sizeof(LOGFONTA), &sentLogFont);
4673 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
4674 "EM_GETCHARFORMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n",
4675 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
4676
4677 SendMessageA(hwndRichEdit, WM_SETFONT, (WPARAM)testFont2, MAKELPARAM(TRUE, 0));
4678 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&returnedCF2A);
4679 GetObjectA(testFont2, sizeof(LOGFONTA), &sentLogFont);
4680 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
4681 "EM_GETCHARFORMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n",
4682 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
4683
4684 SendMessageA(hwndRichEdit, WM_SETFONT, (WPARAM)testFont3, MAKELPARAM(TRUE, 0));
4685 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&returnedCF2A);
4686 GetObjectA(testFont3, sizeof(LOGFONTA), &sentLogFont);
4687 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
4688 "EM_GETCHARFORMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n",
4689 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
4690
4691 /* This last test is special since we send in NULL. We clear the variables
4692 * and just compare to "System" instead of the sent in font name. */
4693 ZeroMemory(&returnedCF2A,sizeof(returnedCF2A));
4694 ZeroMemory(&sentLogFont,sizeof(sentLogFont));
4695 returnedCF2A.cbSize = sizeof(returnedCF2A);
4696
4697 SendMessageA(hwndRichEdit, WM_SETFONT, 0, MAKELPARAM((WORD) TRUE, 0));
4698 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&returnedCF2A);
4699 GetObjectA(NULL, sizeof(LOGFONTA), &sentLogFont);
4700 ok (!strcmp("System",returnedCF2A.szFaceName),
4701 "EM_GETCHARFORMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A.szFaceName);
4702
4703 DestroyWindow(hwndRichEdit);
4704}
4705
4706
4708 LPBYTE pbBuff,
4709 LONG cb,
4710 LONG *pcb)
4711{
4712 const char** str = (const char**)dwCookie;
4713 int size = strlen(*str);
4714 if(size > 3) /* let's make it piecemeal for fun */
4715 size = 3;
4716 *pcb = cb;
4717 if (*pcb > size) {
4718 *pcb = size;
4719 }
4720 if (*pcb > 0) {
4721 memcpy(pbBuff, *str, *pcb);
4722 *str += *pcb;
4723 }
4724 return 0;
4725}
4726
4727static void test_EM_GETMODIFY(void)
4728{
4729 HWND hwndRichEdit = new_richedit(NULL);
4731 SETTEXTEX setText;
4732 WCHAR TestItem1[] = {'T', 'e', 's', 't',
4733 'S', 'o', 'm', 'e',
4734 'T', 'e', 'x', 't', 0};
4735 WCHAR TestItem2[] = {'T', 'e', 's', 't',
4736 'S', 'o', 'm', 'e',
4737 'O', 't', 'h', 'e', 'r',
4738 'T', 'e', 'x', 't', 0};
4739 const char* streamText = "hello world";
4740 CHARFORMAT2A cf2;
4741 PARAFORMAT2 pf2;
4742 EDITSTREAM es;
4743
4744 HFONT testFont = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
4746 FF_DONTCARE, "Courier");
4747
4748 setText.codepage = 1200; /* no constant for unicode */
4749 setText.flags = ST_KEEPUNDO;
4750
4751
4752 /* modify flag shouldn't be set when richedit is first created */
4753 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4754 ok (result == 0,
4755 "EM_GETMODIFY returned non-zero, instead of zero on create\n");
4756
4757 /* setting modify flag should actually set it */
4758 SendMessageA(hwndRichEdit, EM_SETMODIFY, TRUE, 0);
4759 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4760 ok (result != 0,
4761 "EM_GETMODIFY returned zero, instead of non-zero on EM_SETMODIFY\n");
4762
4763 /* clearing modify flag should actually clear it */
4764 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4765 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4766 ok (result == 0,
4767 "EM_GETMODIFY returned non-zero, instead of zero on EM_SETMODIFY\n");
4768
4769 /* setting font doesn't change modify flag */
4770 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4771 SendMessageA(hwndRichEdit, WM_SETFONT, (WPARAM)testFont, MAKELPARAM(TRUE, 0));
4772 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4773 ok (result == 0,
4774 "EM_GETMODIFY returned non-zero, instead of zero on setting font\n");
4775
4776 /* setting text should set modify flag */
4777 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4778 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
4779 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4780 ok (result != 0,
4781 "EM_GETMODIFY returned zero, instead of non-zero on setting text\n");
4782
4783 /* undo previous text doesn't reset modify flag */
4784 SendMessageA(hwndRichEdit, WM_UNDO, 0, 0);
4785 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4786 ok (result != 0,
4787 "EM_GETMODIFY returned zero, instead of non-zero on undo after setting text\n");
4788
4789 /* set text with no flag to keep undo stack should not set modify flag */
4790 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4791 setText.flags = 0;
4792 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
4793 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4794 ok (result == 0,
4795 "EM_GETMODIFY returned non-zero, instead of zero when setting text while not keeping undo stack\n");
4796
4797 /* WM_SETTEXT doesn't modify */
4798 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4799 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem2);
4800 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4801 ok (result == 0,
4802 "EM_GETMODIFY returned non-zero for WM_SETTEXT\n");
4803
4804 /* clear the text */
4805 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4806 SendMessageA(hwndRichEdit, WM_CLEAR, 0, 0);
4807 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4808 ok (result == 0,
4809 "EM_GETMODIFY returned non-zero, instead of zero for WM_CLEAR\n");
4810
4811 /* replace text */
4812 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4813 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
4814 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2);
4815 SendMessageA(hwndRichEdit, EM_REPLACESEL, TRUE, (LPARAM)TestItem2);
4816 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4817 ok (result != 0,
4818 "EM_GETMODIFY returned zero, instead of non-zero when replacing text\n");
4819
4820 /* copy/paste text 1 */
4821 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4822 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2);
4823 SendMessageA(hwndRichEdit, WM_COPY, 0, 0);
4824 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
4825 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4826 ok (result != 0,
4827 "EM_GETMODIFY returned zero, instead of non-zero when pasting identical text\n");
4828
4829 /* copy/paste text 2 */
4830 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4831 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2);
4832 SendMessageA(hwndRichEdit, WM_COPY, 0, 0);
4833 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 3);
4834 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
4835 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4836 ok (result != 0,
4837 "EM_GETMODIFY returned zero, instead of non-zero when pasting different text\n");
4838
4839 /* press char */
4840 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4841 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 1);
4842 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0);
4843 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4844 ok (result != 0,
4845 "EM_GETMODIFY returned zero, instead of non-zero for WM_CHAR\n");
4846
4847 /* press del */
4848 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0);
4849 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4850 SendMessageA(hwndRichEdit, WM_KEYDOWN, VK_BACK, 0);
4851 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4852 ok (result != 0,
4853 "EM_GETMODIFY returned zero, instead of non-zero for backspace\n");
4854
4855 /* set char format */
4856 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4857 cf2.cbSize = sizeof(CHARFORMAT2A);
4858 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2);
4859 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
4860 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
4861 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2);
4862 result = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2);
4863 ok(result == 1, "EM_SETCHARFORMAT returned %ld instead of 1\n", result);
4864 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4865 ok (result != 0,
4866 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETCHARFORMAT\n");
4867
4868 /* set para format */
4869 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4870 pf2.cbSize = sizeof(PARAFORMAT2);
4871 SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&pf2);
4872 pf2.dwMask = PFM_ALIGNMENT | pf2.dwMask;
4873 pf2.wAlignment = PFA_RIGHT;
4874 SendMessageA(hwndRichEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
4875 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4876 ok (result == 0,
4877 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETPARAFORMAT\n");
4878
4879 /* EM_STREAM */
4880 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4881 es.dwCookie = (DWORD_PTR)&streamText;
4882 es.dwError = 0;
4883 es.pfnCallback = test_EM_GETMODIFY_esCallback;
4884 SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es);
4885 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4886 ok (result != 0,
4887 "EM_GETMODIFY returned zero, instead of non-zero for EM_STREAM\n");
4888
4889 DestroyWindow(hwndRichEdit);
4890}
4891
4899};
4900
4901static const struct exsetsel_s exsetsel_tests[] = {
4902 /* sanity tests */
4903 {5, 10, 10, 5, 10 },
4904 {15, 17, 17, 15, 17 },
4905 /* test cpMax > strlen() */
4906 {0, 100, 18, 0, 18 },
4907 /* test cpMin < 0 && cpMax >= 0 after cpMax > strlen() */
4908 {-1, 1, 17, 17, 17 },
4909 /* test cpMin == cpMax */
4910 {5, 5, 5, 5, 5 },
4911 /* test cpMin < 0 && cpMax >= 0 (bug 4462) */
4912 {-1, 0, 5, 5, 5 },
4913 {-1, 17, 5, 5, 5 },
4914 {-1, 18, 5, 5, 5 },
4915 /* test cpMin < 0 && cpMax < 0 */
4916 {-1, -1, 17, 17, 17 },
4917 {-4, -5, 17, 17, 17 },
4918 /* test cpMin >=0 && cpMax < 0 (bug 6814) */
4919 {0, -1, 18, 0, 18 },
4920 {17, -5, 18, 17, 18 },
4921 {18, -3, 17, 17, 17 },
4922 /* test if cpMin > cpMax */
4923 {15, 19, 18, 15, 18 },
4924 {19, 15, 18, 15, 18 },
4925 /* cpMin == strlen() && cpMax > cpMin */
4926 {17, 18, 18, 17, 18 },
4927 {17, 50, 18, 17, 18 },
4928};
4929
4930static void check_EM_EXSETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) {
4931 CHARRANGE cr;
4933 int start, end;
4934
4935 cr.cpMin = setsel->min;
4936 cr.cpMax = setsel->max;
4938
4939 ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
4940
4942
4943 todo_wine_if (setsel->todo)
4944 ok(start == setsel->expected_getsel_start && end == setsel->expected_getsel_end, "EM_EXSETSEL(%d): expected (%d,%d) actual:(%d,%d)\n",
4945 id, setsel->expected_getsel_start, setsel->expected_getsel_end, start, end);
4946}
4947
4948static void test_EM_EXSETSEL(void)
4949{
4950 HWND hwndRichEdit = new_richedit(NULL);
4951 int i;
4952 const int num_tests = ARRAY_SIZE(exsetsel_tests);
4953
4954 /* sending some text to the window */
4955 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection");
4956 /* 01234567890123456*/
4957 /* 10 */
4958
4959 for (i = 0; i < num_tests; i++) {
4960 check_EM_EXSETSEL(hwndRichEdit, &exsetsel_tests[i], i);
4961 }
4962
4963 if (!is_lang_japanese)
4964 skip("Skip multibyte character tests on non-Japanese platform\n");
4965 else
4966 {
4967 CHARRANGE cr;
4968 char bufA[MAX_BUF_LEN] = {0};
4970
4971 /* Test with multibyte character */
4972 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk");
4973 /* 012345 6 78901 */
4974 cr.cpMin = 4; cr.cpMax = 8;
4975 result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
4976 ok(result == 8, "EM_EXSETSEL return %ld expected 8\n", result);
4977 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, sizeof(bufA), (LPARAM)bufA);
4978 ok(!strcmp(bufA, "ef\x8e\xf0g"), "EM_GETSELTEXT return incorrect string\n");
4979 SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
4980 ok(cr.cpMin == 4, "Selection start incorrectly: %d expected 4\n", cr.cpMin);
4981 ok(cr.cpMax == 8, "Selection end incorrectly: %d expected 8\n", cr.cpMax);
4982 }
4983
4984 DestroyWindow(hwndRichEdit);
4985}
4986
4987static void check_EM_SETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) {
4989 int start, end;
4990
4991 result = SendMessageA(hwnd, EM_SETSEL, setsel->min, setsel->max);
4992
4993 ok(result == setsel->expected_retval, "EM_SETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
4994
4996
4997 todo_wine_if (setsel->todo)
4998 ok(start == setsel->expected_getsel_start && end == setsel->expected_getsel_end, "EM_SETSEL(%d): expected (%d,%d) actual:(%d,%d)\n",
4999 id, setsel->expected_getsel_start, setsel->expected_getsel_end, start, end);
5000}
5001
5002static void test_EM_SETSEL(void)
5003{
5004 char buffA[32] = {0};
5005 HWND hwndRichEdit = new_richedit(NULL);
5006 int i;
5007 const int num_tests = ARRAY_SIZE(exsetsel_tests);
5008
5009 /* sending some text to the window */
5010 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection");
5011 /* 01234567890123456*/
5012 /* 10 */
5013
5014 for (i = 0; i < num_tests; i++) {
5015 check_EM_SETSEL(hwndRichEdit, &exsetsel_tests[i], i);
5016 }
5017
5018 SendMessageA(hwndRichEdit, EM_SETSEL, 17, 18);
5019 buffA[0] = 123;
5020 SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffA);
5021 ok(buffA[0] == 0, "selection text %s\n", buffA);
5022
5023 if (!is_lang_japanese)
5024 skip("Skip multibyte character tests on non-Japanese platform\n");
5025 else
5026 {
5027 int sel_start, sel_end;
5029
5030 /* Test with multibyte character */
5031 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk");
5032 /* 012345 6 78901 */
5033 result = SendMessageA(hwndRichEdit, EM_SETSEL, 4, 8);
5034 ok(result == 8, "EM_SETSEL return %ld expected 8\n", result);
5035 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, sizeof(buffA), (LPARAM)buffA);
5036 ok(!strcmp(buffA, "ef\x8e\xf0g"), "EM_GETSELTEXT return incorrect string\n");
5037 result = SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
5038 ok(sel_start == 4, "Selection start incorrectly: %d expected 4\n", sel_start);
5039 ok(sel_end == 8, "Selection end incorrectly: %d expected 8\n", sel_end);
5040 }
5041
5042 DestroyWindow(hwndRichEdit);
5043}
5044
5046{
5047 HWND hwndRichEdit = new_richedit(NULL);
5048 char buffer[1024] = {0};
5049 int r;
5050 GETTEXTEX getText;
5051 CHARRANGE cr;
5052 CHAR rtfstream[] = "{\\rtf1 TestSomeText}";
5053 CHAR urtfstream[] = "{\\urtf1 TestSomeText}";
5054
5055 /* sending some text to the window */
5056 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection");
5057 /* 01234567890123456*/
5058 /* 10 */
5059
5060 /* FIXME add more tests */
5061 SendMessageA(hwndRichEdit, EM_SETSEL, 7, 17);
5062 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, 0);
5063 ok(0 == r, "EM_REPLACESEL returned %d, expected 0\n", r);
5064 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5065 r = strcmp(buffer, "testing");
5066 ok(0 == r, "expected %d, got %d\n", 0, r);
5067
5068 DestroyWindow(hwndRichEdit);
5069
5070 hwndRichEdit = new_richedit(NULL);
5071
5072 trace("Testing EM_REPLACESEL behavior with redraw=%d\n", redraw);
5073 SendMessageA(hwndRichEdit, WM_SETREDRAW, redraw, 0);
5074
5075 /* Test behavior with carriage returns and newlines */
5076 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5077 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"RichEdit1");
5078 ok(9 == r, "EM_REPLACESEL returned %d, expected 9\n", r);
5079 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5080 r = strcmp(buffer, "RichEdit1");
5081 ok(0 == r, "expected %d, got %d\n", 0, r);
5082 getText.cb = 1024;
5083 getText.codepage = CP_ACP;
5084 getText.flags = GT_DEFAULT;
5085 getText.lpDefaultChar = NULL;
5086 getText.lpUsedDefChar = NULL;
5087 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5088 ok(strcmp(buffer, "RichEdit1") == 0,
5089 "EM_GETTEXTEX results not what was set by EM_REPLACESEL\n");
5090
5091 /* Test number of lines reported after EM_REPLACESEL */
5092 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5093 ok(r == 1, "EM_GETLINECOUNT returned %d, expected 1\n", r);
5094
5095 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5096 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"RichEdit1\r");
5097 ok(10 == r, "EM_REPLACESEL returned %d, expected 10\n", r);
5098 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5099 r = strcmp(buffer, "RichEdit1\r\n");
5100 ok(0 == r, "expected %d, got %d\n", 0, r);
5101 getText.cb = 1024;
5102 getText.codepage = CP_ACP;
5103 getText.flags = GT_DEFAULT;
5104 getText.lpDefaultChar = NULL;
5105 getText.lpUsedDefChar = NULL;
5106 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5107 ok(strcmp(buffer, "RichEdit1\r") == 0,
5108 "EM_GETTEXTEX returned incorrect string\n");
5109
5110 /* Test number of lines reported after EM_REPLACESEL */
5111 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5112 ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r);
5113
5114 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5115 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"RichEdit1\r\n");
5116 ok(r == 11, "EM_REPLACESEL returned %d, expected 11\n", r);
5117
5118 /* Test number of lines reported after EM_REPLACESEL */
5119 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5120 ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r);
5121
5122 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5123 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5124 ok(cr.cpMin == 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr.cpMin);
5125 ok(cr.cpMax == 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr.cpMax);
5126
5127 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5128 r = strcmp(buffer, "RichEdit1\r\n");
5129 ok(0 == r, "expected %d, got %d\n", 0, r);
5130 getText.cb = 1024;
5131 getText.codepage = CP_ACP;
5132 getText.flags = GT_DEFAULT;
5133 getText.lpDefaultChar = NULL;
5134 getText.lpUsedDefChar = NULL;
5135 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5136 ok(strcmp(buffer, "RichEdit1\r") == 0,
5137 "EM_GETTEXTEX returned incorrect string\n");
5138
5139 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5140 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5141 ok(cr.cpMin == 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr.cpMin);
5142 ok(cr.cpMax == 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr.cpMax);
5143
5144 /* The following tests show that richedit should handle the special \r\r\n
5145 sequence by turning it into a single space on insertion. However,
5146 EM_REPLACESEL on WinXP returns the number of characters in the original
5147 string.
5148 */
5149
5150 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5151 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r");
5152 ok(2 == r, "EM_REPLACESEL returned %d, expected 4\n", r);
5153 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5154 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5155 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin);
5156 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax);
5157
5158 /* Test the actual string */
5159 getText.cb = 1024;
5160 getText.codepage = CP_ACP;
5161 getText.flags = GT_DEFAULT;
5162 getText.lpDefaultChar = NULL;
5163 getText.lpUsedDefChar = NULL;
5164 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5165 ok(strcmp(buffer, "\r\r") == 0,
5166 "EM_GETTEXTEX returned incorrect string\n");
5167
5168 /* Test number of lines reported after EM_REPLACESEL */
5169 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5170 ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r);
5171
5172 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5173 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r\n");
5174 ok(r == 3, "EM_REPLACESEL returned %d, expected 3\n", r);
5175 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5176 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5177 ok(cr.cpMin == 1, "EM_EXGETSEL returned cpMin=%d, expected 1\n", cr.cpMin);
5178 ok(cr.cpMax == 1, "EM_EXGETSEL returned cpMax=%d, expected 1\n", cr.cpMax);
5179
5180 /* Test the actual string */
5181 getText.cb = 1024;
5182 getText.codepage = CP_ACP;
5183 getText.flags = GT_DEFAULT;
5184 getText.lpDefaultChar = NULL;
5185 getText.lpUsedDefChar = NULL;
5186 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5187 ok(strcmp(buffer, " ") == 0,
5188 "EM_GETTEXTEX returned incorrect string\n");
5189
5190 /* Test number of lines reported after EM_REPLACESEL */
5191 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5192 ok(r == 1, "EM_GETLINECOUNT returned %d, expected 1\n", r);
5193
5194 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5195 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r\r\r\r\n\r\r\r");
5196 ok(r == 9, "EM_REPLACESEL returned %d, expected 9\n", r);
5197 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5198 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5199 ok(cr.cpMin == 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr.cpMin);
5200 ok(cr.cpMax == 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr.cpMax);
5201
5202 /* Test the actual string */
5203 getText.cb = 1024;
5204 getText.codepage = CP_ACP;
5205 getText.flags = GT_DEFAULT;
5206 getText.lpDefaultChar = NULL;
5207 getText.lpUsedDefChar = NULL;
5208 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5209 ok(strcmp(buffer, "\r\r\r \r\r\r") == 0,
5210 "EM_GETTEXTEX returned incorrect string\n");
5211
5212 /* Test number of lines reported after EM_REPLACESEL */
5213 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5214 ok(r == 7, "EM_GETLINECOUNT returned %d, expected 7\n", r);
5215
5216 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5217 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r\n\r\n");
5218 ok(r == 5, "EM_REPLACESEL returned %d, expected 5\n", r);
5219 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5220 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5221 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin);
5222 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax);
5223
5224 /* Test the actual string */
5225 getText.cb = 1024;
5226 getText.codepage = CP_ACP;
5227 getText.flags = GT_DEFAULT;
5228 getText.lpDefaultChar = NULL;
5229 getText.lpUsedDefChar = NULL;
5230 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5231 ok(strcmp(buffer, " \r") == 0,
5232 "EM_GETTEXTEX returned incorrect string\n");
5233
5234 /* Test number of lines reported after EM_REPLACESEL */
5235 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5236 ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r);
5237
5238 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5239 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r\n\r\r");
5240 ok(r == 5, "EM_REPLACESEL returned %d, expected 5\n", r);
5241 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5242 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5243 ok(cr.cpMin == 3, "EM_EXGETSEL returned cpMin=%d, expected 3\n", cr.cpMin);
5244 ok(cr.cpMax == 3, "EM_EXGETSEL returned cpMax=%d, expected 3\n", cr.cpMax);
5245
5246 /* Test the actual string */
5247 getText.cb = 1024;
5248 getText.codepage = CP_ACP;
5249 getText.flags = GT_DEFAULT;
5250 getText.lpDefaultChar = NULL;
5251 getText.lpUsedDefChar = NULL;
5252 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5253 ok(strcmp(buffer, " \r\r") == 0,
5254 "EM_GETTEXTEX returned incorrect string\n");
5255
5256 /* Test number of lines reported after EM_REPLACESEL */
5257 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5258 ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r);
5259
5260 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5261 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\rX\r\n\r\r");
5262 ok(r == 6, "EM_REPLACESEL returned %d, expected 6\n", r);
5263 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5264 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5265 ok(cr.cpMin == 5, "EM_EXGETSEL returned cpMin=%d, expected 5\n", cr.cpMin);
5266 ok(cr.cpMax == 5, "EM_EXGETSEL returned cpMax=%d, expected 5\n", cr.cpMax);
5267
5268 /* Test the actual string */
5269 getText.cb = 1024;
5270 getText.codepage = CP_ACP;
5271 getText.flags = GT_DEFAULT;
5272 getText.lpDefaultChar = NULL;
5273 getText.lpUsedDefChar = NULL;
5274 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5275 ok(strcmp(buffer, "\rX\r\r\r") == 0,
5276 "EM_GETTEXTEX returned incorrect string\n");
5277
5278 /* Test number of lines reported after EM_REPLACESEL */
5279 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5280 ok(r == 5, "EM_GETLINECOUNT returned %d, expected 5\n", r);
5281
5282 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5283 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\n\n");
5284 ok(2 == r, "EM_REPLACESEL returned %d, expected 2\n", r);
5285 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5286 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5287 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin);
5288 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax);
5289
5290 /* Test the actual string */
5291 getText.cb = 1024;
5292 getText.codepage = CP_ACP;
5293 getText.flags = GT_DEFAULT;
5294 getText.lpDefaultChar = NULL;
5295 getText.lpUsedDefChar = NULL;
5296 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5297 ok(strcmp(buffer, "\r\r") == 0,
5298 "EM_GETTEXTEX returned incorrect string\n");
5299
5300 /* Test number of lines reported after EM_REPLACESEL */
5301 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5302 ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r);
5303
5304 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5305 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\n\n\n\n\r\r\r\r\n");
5306 ok(r == 9, "EM_REPLACESEL returned %d, expected 9\n", r);
5307 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5308 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5309 ok(cr.cpMin == 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr.cpMin);
5310 ok(cr.cpMax == 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr.cpMax);
5311
5312 /* Test the actual string */
5313 getText.cb = 1024;
5314 getText.codepage = CP_ACP;
5315 getText.flags = GT_DEFAULT;
5316 getText.lpDefaultChar = NULL;
5317 getText.lpUsedDefChar = NULL;
5318 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5319 ok(strcmp(buffer, "\r\r\r\r\r\r ") == 0,
5320 "EM_GETTEXTEX returned incorrect string\n");
5321
5322 /* Test number of lines reported after EM_REPLACESEL */
5323 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5324 ok(r == 7, "EM_GETLINECOUNT returned %d, expected 7\n", r);
5325
5326 /* Test with multibyte character */
5327 if (!is_lang_japanese)
5328 skip("Skip multibyte character tests on non-Japanese platform\n");
5329 else
5330 {
5331 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5332 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"abc\x8e\xf0");
5333 todo_wine ok(r == 5, "EM_REPLACESEL returned %d, expected 5\n", r);
5334 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5335 ok(r == 0, "EM_EXGETSEL returned %d, expected 0\n", r);
5336 ok(cr.cpMin == 4, "EM_EXGETSEL returned cpMin=%d, expected 4\n", cr.cpMin);
5337 ok(cr.cpMax == 4, "EM_EXGETSEL returned cpMax=%d, expected 4\n", cr.cpMax);
5338 r = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5339 ok(!strcmp(buffer, "abc\x8e\xf0"), "WM_GETTEXT returned incorrect string\n");
5340 ok(r == 5, "WM_GETTEXT returned %d, expected 5\n", r);
5341
5342 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5343 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"{\\rtf abc\x8e\xf0}");
5344 todo_wine ok(r == 4, "EM_REPLACESEL returned %d, expected 4\n", r);
5345 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5346 ok(r == 0, "EM_EXGETSEL returned %d, expected 0\n", r);
5347 todo_wine ok(cr.cpMin == 4, "EM_EXGETSEL returned cpMin=%d, expected 4\n", cr.cpMin);
5348 todo_wine ok(cr.cpMax == 4, "EM_EXGETSEL returned cpMax=%d, expected 4\n", cr.cpMax);
5349 r = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5350 todo_wine ok(!strcmp(buffer, "abc\x8e\xf0"), "WM_GETTEXT returned incorrect string\n");
5351 todo_wine ok(r == 5, "WM_GETTEXT returned %d, expected 5\n", r);
5352 }
5353
5354 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5355 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)rtfstream);
5356 todo_wine ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r);
5357 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5358 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5359 todo_wine ok(cr.cpMin == 12, "EM_EXGETSEL returned cpMin=%d, expected 12\n", cr.cpMin);
5360 todo_wine ok(cr.cpMax == 12, "EM_EXGETSEL returned cpMax=%d, expected 12\n", cr.cpMax);
5361 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5362 todo_wine ok(!strcmp(buffer, "TestSomeText"), "WM_GETTEXT returned incorrect string\n");
5363
5364 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5365 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)urtfstream);
5366 todo_wine ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r);
5367 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5368 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5369 todo_wine ok(cr.cpMin == 12, "EM_EXGETSEL returned cpMin=%d, expected 12\n", cr.cpMin);
5370 todo_wine ok(cr.cpMax == 12, "EM_EXGETSEL returned cpMax=%d, expected 12\n", cr.cpMax);
5371 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5372 todo_wine ok(!strcmp(buffer, "TestSomeText"), "WM_GETTEXT returned incorrect string\n");
5373
5374 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"Wine");
5375 SendMessageA(hwndRichEdit, EM_SETSEL, 1, 2);
5376 todo_wine r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)rtfstream);
5377 todo_wine ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r);
5378 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5379 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5380 todo_wine ok(cr.cpMin == 13, "EM_EXGETSEL returned cpMin=%d, expected 13\n", cr.cpMin);
5381 todo_wine ok(cr.cpMax == 13, "EM_EXGETSEL returned cpMax=%d, expected 13\n", cr.cpMax);
5382 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5383 todo_wine ok(!strcmp(buffer, "WTestSomeTextne"), "WM_GETTEXT returned incorrect string\n");
5384
5385 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"{\\rtf1 Wine}");
5386 SendMessageA(hwndRichEdit, EM_SETSEL, 1, 2);
5387 todo_wine r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)rtfstream);
5388 todo_wine ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r);
5389 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5390 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5391 todo_wine ok(cr.cpMin == 13, "EM_EXGETSEL returned cpMin=%d, expected 13\n", cr.cpMin);
5392 todo_wine ok(cr.cpMax == 13, "EM_EXGETSEL returned cpMax=%d, expected 13\n", cr.cpMax);
5393 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5394 todo_wine ok(!strcmp(buffer, "WTestSomeTextne"), "WM_GETTEXT returned incorrect string\n");
5395
5396 if (!redraw)
5397 /* This is needed to avoid interfering with keybd_event calls
5398 * on other tests that simulate keyboard events. */
5399 SendMessageA(hwndRichEdit, WM_SETREDRAW, TRUE, 0);
5400
5401 DestroyWindow(hwndRichEdit);
5402
5403 /* Single-line richedit */
5404 hwndRichEdit = new_richedit_with_style(NULL, 0);
5405 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"line1\r\nline2");
5406 ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r);
5407 r = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5408 ok(r == 5, "WM_GETTEXT returned %d, expected 5\n", r);
5409 ok(!strcmp(buffer, "line1"), "WM_GETTEXT returned incorrect string '%s'\n", buffer);
5410 DestroyWindow(hwndRichEdit);
5411}
5412
5413/* Native riched20 inspects the keyboard state (e.g. GetKeyState)
5414 * to test the state of the modifiers (Ctrl/Alt/Shift).
5415 *
5416 * Therefore Ctrl-<key> keystrokes need to be simulated with
5417 * keybd_event or by using SetKeyboardState to set the modifiers
5418 * and SendMessage to simulate the keystrokes.
5419 */
5421{
5426 return result;
5427}
5428
5429static void test_WM_PASTE(void)
5430{
5431 int result;
5432 char buffer[1024] = {0};
5433 const char* text1 = "testing paste\r";
5434 const char* text1_step1 = "testing paste\r\ntesting paste\r\n";
5435 const char* text1_after = "testing paste\r\n";
5436 const char* text2 = "testing paste\r\rtesting paste";
5437 const char* text2_after = "testing paste\r\n\r\ntesting paste";
5438 const char* text3 = "testing paste\r\npaste\r\ntesting paste";
5439 HWND hwndRichEdit = new_richedit(NULL);
5440
5441 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
5442 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 14);
5443
5444 send_ctrl_key(hwndRichEdit, 'C'); /* Copy */
5445 SendMessageA(hwndRichEdit, EM_SETSEL, 14, 14);
5446 send_ctrl_key(hwndRichEdit, 'V'); /* Paste */
5447 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5448 /* Pasted text should be visible at this step */
5449 result = strcmp(text1_step1, buffer);
5450 ok(result == 0,
5451 "test paste: strcmp = %i, text='%s'\n", result, buffer);
5452
5453 send_ctrl_key(hwndRichEdit, 'Z'); /* Undo */
5454 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5455 /* Text should be the same as before (except for \r -> \r\n conversion) */
5456 result = strcmp(text1_after, buffer);
5457 ok(result == 0,
5458 "test paste: strcmp = %i, text='%s'\n", result, buffer);
5459
5460 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
5461 SendMessageA(hwndRichEdit, EM_SETSEL, 8, 13);
5462 send_ctrl_key(hwndRichEdit, 'C'); /* Copy */
5463 SendMessageA(hwndRichEdit, EM_SETSEL, 14, 14);
5464 send_ctrl_key(hwndRichEdit, 'V'); /* Paste */
5465 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5466 /* Pasted text should be visible at this step */
5467 result = strcmp(text3, buffer);
5468 ok(result == 0,
5469 "test paste: strcmp = %i\n", result);
5470 send_ctrl_key(hwndRichEdit, 'Z'); /* Undo */
5471 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5472 /* Text should be the same as before (except for \r -> \r\n conversion) */
5473 result = strcmp(text2_after, buffer);
5474 ok(result == 0,
5475 "test paste: strcmp = %i\n", result);
5476 send_ctrl_key(hwndRichEdit, 'Y'); /* Redo */
5477 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5478 /* Text should revert to post-paste state */
5479 result = strcmp(buffer,text3);
5480 ok(result == 0,
5481 "test paste: strcmp = %i\n", result);
5482
5483 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5484 /* Send WM_CHAR to simulate Ctrl-V */
5485 SendMessageA(hwndRichEdit, WM_CHAR, 22,
5486 (MapVirtualKeyA('V', MAPVK_VK_TO_VSC) << 16) | 1);
5487 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5488 /* Shouldn't paste because pasting is handled by WM_KEYDOWN */
5489 result = strcmp(buffer,"");
5490 ok(result == 0,
5491 "test paste: strcmp = %i, actual = '%s'\n", result, buffer);
5492
5493 /* Send keystrokes with WM_KEYDOWN after setting the modifiers
5494 * with SetKeyboard state. */
5495
5496 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5497 /* Simulates paste (Ctrl-V) */
5499 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'V',
5500 (MapVirtualKeyA('V', MAPVK_VK_TO_VSC) << 16) | 1);
5502 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5503 result = strcmp(buffer,"paste");
5504 ok(result == 0,
5505 "test paste: strcmp = %i, actual = '%s'\n", result, buffer);
5506
5507 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
5508 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 7);
5509 /* Simulates copy (Ctrl-C) */
5511 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'C',
5512 (MapVirtualKeyA('C', MAPVK_VK_TO_VSC) << 16) | 1);
5514 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5515 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
5516 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5517 result = strcmp(buffer,"testing");
5518 ok(result == 0,
5519 "test paste: strcmp = %i, actual = '%s'\n", result, buffer);
5520
5521 /* Cut with WM_KEYDOWN to simulate Ctrl-X */
5522 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"cut");
5523 /* Simulates select all (Ctrl-A) */
5525 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'A',
5526 (MapVirtualKeyA('A', MAPVK_VK_TO_VSC) << 16) | 1);
5527 /* Simulates select cut (Ctrl-X) */
5528 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'X',
5529 (MapVirtualKeyA('X', MAPVK_VK_TO_VSC) << 16) | 1);
5531 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5532 result = strcmp(buffer,"");
5533 ok(result == 0,
5534 "test paste: strcmp = %i, actual = '%s'\n", result, buffer);
5535 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5536 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
5537 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5538 result = strcmp(buffer,"cut\r\n");
5539 ok(result == 0,
5540 "test paste: strcmp = %i, actual = '%s'\n", result, buffer);
5541 /* Simulates undo (Ctrl-Z) */
5543 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'Z',
5544 (MapVirtualKeyA('Z', MAPVK_VK_TO_VSC) << 16) | 1);
5545 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5546 result = strcmp(buffer,"");
5547 ok(result == 0,
5548 "test paste: strcmp = %i, actual = '%s'\n", result, buffer);
5549 /* Simulates redo (Ctrl-Y) */
5550 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'Y',
5551 (MapVirtualKeyA('Y', MAPVK_VK_TO_VSC) << 16) | 1);
5552 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5553 result = strcmp(buffer,"cut\r\n");
5554 ok(result == 0,
5555 "test paste: strcmp = %i, actual = '%s'\n", result, buffer);
5557
5558 /* Copy multiline text to clipboard for future use */
5559 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text3);
5560 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
5561 SendMessageA(hwndRichEdit, WM_COPY, 0, 0);
5562 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 0);
5563
5564 /* Paste into read-only control */
5565 result = SendMessageA(hwndRichEdit, EM_SETREADONLY, TRUE, 0);
5566 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
5567 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5568 result = strcmp(buffer, text3);
5569 ok(result == 0,
5570 "test paste: strcmp = %i, actual = '%s'\n", result, buffer);
5571
5572 /* Cut from read-only control */
5573 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
5574 SendMessageA(hwndRichEdit, WM_CUT, 0, 0);
5575 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5576 result = strcmp(buffer, text3);
5577 ok(result == 0,
5578 "test paste: strcmp = %i, actual = '%s'\n", result, buffer);
5579
5580 /* FIXME: Wine doesn't flush Ole clipboard when window is destroyed so do it manually */
5582 DestroyWindow(hwndRichEdit);
5583
5584 /* Paste multi-line text into single-line control */
5585 hwndRichEdit = new_richedit_with_style(NULL, 0);
5586 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
5587 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5588 result = strcmp(buffer, "testing paste");
5589 ok(result == 0,
5590 "test paste: strcmp = %i, actual = '%s'\n", result, buffer);
5591 DestroyWindow(hwndRichEdit);
5592}
5593
5594static void test_EM_FORMATRANGE(void)
5595{
5596 int r, i, tpp_x, tpp_y;
5597 HDC hdc;
5598 HWND hwndRichEdit = new_richedit(NULL);
5599 FORMATRANGE fr;
5600 BOOL skip_non_english;
5601 static const struct {
5602 const char *string; /* The string */
5603 int first; /* First 'pagebreak', 0 for don't care */
5604 int second; /* Second 'pagebreak', 0 for don't care */
5605 } fmtstrings[] = {
5606 {"WINE wine", 0, 0},
5607 {"WINE wineWine", 0, 0},
5608 {"WINE\r\nwine\r\nwine", 5, 10},
5609 {"WINE\r\nWINEwine\r\nWINEwine", 5, 14},
5610 {"WINE\r\n\r\nwine\r\nwine", 5, 6}
5611 };
5612
5613 skip_non_english = (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH);
5614 if (skip_non_english)
5615 skip("Skipping some tests on non-English platform\n");
5616
5617 hdc = GetDC(hwndRichEdit);
5618 ok(hdc != NULL, "Could not get HDC\n");
5619
5620 /* Calculate the twips per pixel */
5621 tpp_x = 1440 / GetDeviceCaps(hdc, LOGPIXELSX);
5622 tpp_y = 1440 / GetDeviceCaps(hdc, LOGPIXELSY);
5623
5624 /* Test the simple case where all the text fits in the page rect. */
5625 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
5626 fr.hdc = fr.hdcTarget = hdc;
5627 fr.rc.top = fr.rcPage.top = fr.rc.left = fr.rcPage.left = 0;
5628 fr.rc.right = fr.rcPage.right = 500 * tpp_x;
5629 fr.rc.bottom = fr.rcPage.bottom = 500 * tpp_y;
5630 fr.chrg.cpMin = 0;
5631 fr.chrg.cpMax = -1;
5632 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, FALSE, (LPARAM)&fr);
5633 todo_wine ok(r == 2, "r=%d expected r=2\n", r);
5634
5635 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"ab");
5636 fr.rc.bottom = fr.rcPage.bottom;
5637 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, FALSE, (LPARAM)&fr);
5638 todo_wine ok(r == 3, "r=%d expected r=3\n", r);
5639
5640 SendMessageA(hwndRichEdit, EM_FORMATRANGE, FALSE, 0);
5641
5642 for (i = 0; i < ARRAY_SIZE(fmtstrings); i++)
5643 {
5644 GETTEXTLENGTHEX gtl;
5645 SIZE stringsize;
5646 int len;
5647
5648 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)fmtstrings[i].string);
5649
5651 gtl.codepage = CP_ACP;
5652 len = SendMessageA(hwndRichEdit, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
5653
5654 /* Get some size information for the string */
5655 GetTextExtentPoint32A(hdc, fmtstrings[i].string, strlen(fmtstrings[i].string), &stringsize);
5656
5657 /* Define the box to be half the width needed and a bit larger than the height.
5658 * Changes to the width means we have at least 2 pages. Changes to the height
5659 * is done so we can check the changing of fr.rc.bottom.
5660 */
5661 fr.hdc = fr.hdcTarget = hdc;
5662 fr.rc.top = fr.rcPage.top = fr.rc.left = fr.rcPage.left = 0;
5663 fr.rc.right = fr.rcPage.right = (stringsize.cx / 2) * tpp_x;
5664 fr.rc.bottom = fr.rcPage.bottom = (stringsize.cy + 10) * tpp_y;
5665
5666 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, TRUE, 0);
5667 todo_wine {
5668 ok(r == len, "Expected %d, got %d\n", len, r);
5669 }
5670
5671 /* We know that the page can't hold the full string. See how many characters
5672 * are on the first one
5673 */
5674 fr.chrg.cpMin = 0;
5675 fr.chrg.cpMax = -1;
5676 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM)&fr);
5677 todo_wine {
5678 if (! skip_non_english)
5679 ok(fr.rc.bottom == (stringsize.cy * tpp_y), "Expected bottom to be %d, got %d\n", (stringsize.cy * tpp_y), fr.rc.bottom);
5680 }
5681 if (fmtstrings[i].first)
5682 todo_wine {
5683 ok(r == fmtstrings[i].first, "Expected %d, got %d\n", fmtstrings[i].first, r);
5684 }
5685 else
5686 ok(r < len, "Expected < %d, got %d\n", len, r);
5687
5688 /* Do another page */
5689 fr.chrg.cpMin = r;
5690 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM)&fr);
5691 if (fmtstrings[i].second)
5692 todo_wine {
5693 ok(r == fmtstrings[i].second, "Expected %d, got %d\n", fmtstrings[i].second, r);
5694 }
5695 else if (! skip_non_english)
5696 ok (r < len, "Expected < %d, got %d\n", len, r);
5697
5698 /* There is at least on more page, but we don't care */
5699
5700 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, TRUE, 0);
5701 todo_wine {
5702 ok(r == len, "Expected %d, got %d\n", len, r);
5703 }
5704 }
5705
5706 ReleaseDC(NULL, hdc);
5707 DestroyWindow(hwndRichEdit);
5708}
5709
5710static int nCallbackCount = 0;
5711
5713 LONG cb, LONG* pcb)
5714{
5715 const char text[] = {'t','e','s','t'};
5716
5717 if (sizeof(text) <= cb)
5718 {
5719 if ((int)dwCookie != nCallbackCount)
5720 {
5721 *pcb = 0;
5722 return 0;
5723 }
5724
5725 memcpy (pbBuff, text, sizeof(text));
5726 *pcb = sizeof(text);
5727
5729
5730 return 0;
5731 }
5732 else
5733 return 1; /* indicates callback failed */
5734}
5735
5737 LPBYTE pbBuff,
5738 LONG cb,
5739 LONG *pcb)
5740{
5741 const char** str = (const char**)dwCookie;
5742 int size = strlen(*str);
5743 *pcb = cb;
5744 if (*pcb > size) {
5745 *pcb = size;
5746 }
5747 if (*pcb > 0) {
5748 memcpy(pbBuff, *str, *pcb);
5749 *str += *pcb;
5750 }
5751 return 0;
5752}
5753
5755 LPBYTE pbBuff,
5756 LONG cb,
5757 LONG *pcb)
5758{
5759 DWORD *phase = (DWORD *)dwCookie;
5760
5761 if(*phase == 0){
5762 static const char first[] = "\xef\xbb\xbf\xc3\x96\xc3";
5763 *pcb = sizeof(first) - 1;
5764 memcpy(pbBuff, first, *pcb);
5765 }else if(*phase == 1){
5766 static const char second[] = "\x8f\xc3\x8b";
5767 *pcb = sizeof(second) - 1;
5768 memcpy(pbBuff, second, *pcb);
5769 }else
5770 *pcb = 0;
5771
5772 ++*phase;
5773
5774 return 0;
5775}
5776
5778{
5779 DWORD *phase = (DWORD *)cookie;
5780
5781 if (*phase == 0)
5782 {
5783 static const char first[] = "{\\rtf1\\ansi{Th\0is";
5784 *written = sizeof(first);
5785 memcpy(buf, first, *written);
5786 }
5787 else if (*phase == 1)
5788 {
5789 static const char second[] = " is a test}}";
5790 *written = sizeof(second);
5791 memcpy(buf, second, *written);
5792 }
5793 else
5794 *written = 0;
5795
5796 ++*phase;
5797
5798 return 0;
5799}
5800
5803 char *buffer;
5804};
5805
5806/* This callback is used to handled the null characters in a string. */
5808 LPBYTE pbBuff,
5809 LONG cb,
5810 LONG *pcb)
5811{
5812 struct StringWithLength* str = (struct StringWithLength*)dwCookie;
5813 int size = str->length;
5814 *pcb = cb;
5815 if (*pcb > size) {
5816 *pcb = size;
5817 }
5818 if (*pcb > 0) {
5819 memcpy(pbBuff, str->buffer, *pcb);
5820 str->buffer += *pcb;
5821 str->length -= *pcb;
5822 }
5823 return 0;
5824}
5825
5826static void test_EM_STREAMIN(void)
5827{
5828 HWND hwndRichEdit = new_richedit(NULL);
5829 DWORD phase;
5831 EDITSTREAM es;
5832 char buffer[1024] = {0}, tmp[16];
5835
5836 const char * streamText0 = "{\\rtf1\\fi100\\li200\\rtlpar\\qr TestSomeText}";
5837 const char * streamText0a = "{\\rtf1\\fi100\\li200\\rtlpar\\qr TestSomeText\\par}";
5838 const char * streamText0b = "{\\rtf1 TestSomeText\\par\\par}";
5839 const char * ptr;
5840
5841 const char * streamText1 =
5842 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n"
5843 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n"
5844 "}\r\n";
5845
5846 /* In richedit 2.0 mode, this should NOT be accepted, unlike 1.0 */
5847 const char * streamText2 =
5848 "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;"
5849 "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255"
5850 "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 "
5851 "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 "
5852 "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 "
5853 "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 "
5854 "\\tx11448 \\tx11872 \\tx12296 \\tx12720 \\tx13144 \\cf2 RichEdit1\\line }";
5855
5856 const char * streamText3 = "RichEdit1";
5857
5858 const char * streamTextUTF8BOM = "\xef\xbb\xbfTestUTF8WithBOM";
5859
5860 const char * streamText4 =
5861 "This text just needs to be long enough to cause run to be split onto "
5862 "two separate lines and make sure the null terminating character is "
5863 "handled properly.\0";
5864
5865 const WCHAR UTF8Split_exp[4] = {0xd6, 0xcf, 0xcb, 0};
5866
5867 int length4 = strlen(streamText4) + 1;
5868 struct StringWithLength cookieForStream4 = {
5869 length4,
5870 (char *)streamText4,
5871 };
5872
5873 const WCHAR streamText5[] = { 'T', 'e', 's', 't', 'S', 'o', 'm', 'e', 'T', 'e', 'x', 't' };
5874 int length5 = ARRAY_SIZE(streamText5);
5875 struct StringWithLength cookieForStream5 = {
5876 sizeof(streamText5),
5877 (char *)streamText5,
5878 };
5879
5880 /* Minimal test without \par at the end */
5881 es.dwCookie = (DWORD_PTR)&streamText0;
5882 es.dwError = 0;
5883 es.pfnCallback = test_EM_STREAMIN_esCallback;
5884 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
5885 ok(result == 12, "got %ld, expected %d\n", result, 12);
5886
5887 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5888 ok (result == 12,
5889 "EM_STREAMIN: Test 0 returned %ld, expected 12\n", result);
5890 result = strcmp (buffer,"TestSomeText");
5891 ok (result == 0,
5892 "EM_STREAMIN: Test 0 set wrong text: Result: %s\n",buffer);
5893 ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0);
5894 /* Show that para fmts are ignored */
5895 range.cpMin = 2;
5896 range.cpMax = 2;
5897 result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&range);
5898 memset(&fmt, 0xcc, sizeof(fmt));
5899 fmt.cbSize = sizeof(fmt);
5900 result = SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt);
5901 ok(fmt.dxStartIndent == 0, "got %d\n", fmt.dxStartIndent);
5902 ok(fmt.dxOffset == 0, "got %d\n", fmt.dxOffset);
5903 ok(fmt.wAlignment == PFA_LEFT, "got %d\n", fmt.wAlignment);
5904 ok((fmt.wEffects & PFE_RTLPARA) == 0, "got %x\n", fmt.wEffects);
5905
5906 /* Native richedit 2.0 ignores last \par */
5907 ptr = streamText0a;
5908 es.dwCookie = (DWORD_PTR)&ptr;
5909 es.dwError = 0;
5910 es.pfnCallback = test_EM_STREAMIN_esCallback;
5911 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
5912 ok(result == 12, "got %ld, expected %d\n", result, 12);
5913
5914 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5915 ok (result == 12,
5916 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result);
5917 result = strcmp (buffer,"TestSomeText");
5918 ok (result == 0,
5919 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer);
5920 ok(es.dwError == 0, "EM_STREAMIN: Test 0-a set error %d, expected %d\n", es.dwError, 0);
5921 /* This time para fmts are processed */
5922 range.cpMin = 2;
5923 range.cpMax = 2;
5924 result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&range);
5925 memset(&fmt, 0xcc, sizeof(fmt));
5926 fmt.cbSize = sizeof(fmt);
5927 result = SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt);
5928 ok(fmt.dxStartIndent == 300, "got %d\n", fmt.dxStartIndent);
5929 ok(fmt.dxOffset == -100, "got %d\n", fmt.dxOffset);
5930 ok(fmt.wAlignment == PFA_RIGHT, "got %d\n", fmt.wAlignment);
5931 ok((fmt.wEffects & PFE_RTLPARA) == PFE_RTLPARA, "got %x\n", fmt.wEffects);
5932
5933 /* Native richedit 2.0 ignores last \par, next-to-last \par appears */
5934 es.dwCookie = (DWORD_PTR)&streamText0b;
5935 es.dwError = 0;
5936 es.pfnCallback = test_EM_STREAMIN_esCallback;
5937 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
5938 ok(result == 13, "got %ld, expected %d\n", result, 13);
5939
5940 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5941 ok (result == 14,
5942 "EM_STREAMIN: Test 0-b returned %ld, expected 14\n", result);
5943 result = strcmp (buffer,"TestSomeText\r\n");
5944 ok (result == 0,
5945 "EM_STREAMIN: Test 0-b set wrong text: Result: %s\n",buffer);
5946 ok(es.dwError == 0, "EM_STREAMIN: Test 0-b set error %d, expected %d\n", es.dwError, 0);
5947
5948 /* Show that when using SFF_SELECTION the last \par is not ignored. */
5949 ptr = streamText0a;
5950 es.dwCookie = (DWORD_PTR)&ptr;
5951 es.dwError = 0;
5952 es.pfnCallback = test_EM_STREAMIN_esCallback;
5953 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
5954 ok(result == 12, "got %ld, expected %d\n", result, 12);
5955
5956 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5957 ok (result == 12,
5958 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result);
5959 result = strcmp (buffer,"TestSomeText");
5960 ok (result == 0,
5961 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer);
5962 ok(es.dwError == 0, "EM_STREAMIN: Test 0-a set error %d, expected %d\n", es.dwError, 0);
5963
5964 range.cpMin = 0;
5965 range.cpMax = -1;
5966 result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&range);
5967 ok (result == 13, "got %ld\n", result);
5968
5969 ptr = streamText0a;
5970 es.dwCookie = (DWORD_PTR)&ptr;
5971 es.dwError = 0;
5972 es.pfnCallback = test_EM_STREAMIN_esCallback;
5973
5975 ok(result == 13, "got %ld, expected 13\n", result);
5976
5977 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5978 ok (result == 14,
5979 "EM_STREAMIN: Test SFF_SELECTION 0-a returned %ld, expected 14\n", result);
5980 result = strcmp (buffer,"TestSomeText\r\n");
5981 ok (result == 0,
5982 "EM_STREAMIN: Test SFF_SELECTION 0-a set wrong text: Result: %s\n",buffer);
5983 ok(es.dwError == 0, "EM_STREAMIN: Test SFF_SELECTION 0-a set error %d, expected %d\n", es.dwError, 0);
5984
5985 es.dwCookie = (DWORD_PTR)&streamText1;
5986 es.dwError = 0;
5987 es.pfnCallback = test_EM_STREAMIN_esCallback;
5988 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
5989 ok(result == 12, "got %ld, expected %d\n", result, 12);
5990
5991 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5992 ok (result == 12,
5993 "EM_STREAMIN: Test 1 returned %ld, expected 12\n", result);
5994 result = strcmp (buffer,"TestSomeText");
5995 ok (result == 0,
5996 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer);
5997 ok(es.dwError == 0, "EM_STREAMIN: Test 1 set error %d, expected %d\n", es.dwError, 0);
5998
5999 es.dwCookie = (DWORD_PTR)&streamText2;
6000 es.dwError = 0;
6001 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
6002 ok(result == 0, "got %ld, expected %d\n", result, 0);
6003
6004 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6005 ok (result == 0,
6006 "EM_STREAMIN: Test 2 returned %ld, expected 0\n", result);
6007 ok(!buffer[0], "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
6008 ok(es.dwError == -16, "EM_STREAMIN: Test 2 set error %d, expected %d\n", es.dwError, -16);
6009
6010 es.dwCookie = (DWORD_PTR)&streamText3;
6011 es.dwError = 0;
6012 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
6013 ok(result == 0, "got %ld, expected %d\n", result, 0);
6014
6015 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6016 ok (result == 0,
6017 "EM_STREAMIN: Test 3 returned %ld, expected 0\n", result);
6018 ok(!buffer[0], "EM_STREAMIN: Test 3 set wrong text: Result: %s\n",buffer);
6019 ok(es.dwError == -16, "EM_STREAMIN: Test 3 set error %d, expected %d\n", es.dwError, -16);
6020
6021 es.dwCookie = (DWORD_PTR)&streamTextUTF8BOM;
6022 es.dwError = 0;
6023 es.pfnCallback = test_EM_STREAMIN_esCallback;
6024 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es);
6025 ok(result == 18, "got %ld, expected %d\n", result, 18);
6026
6027 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6028 ok(result == 15,
6029 "EM_STREAMIN: Test UTF8WithBOM returned %ld, expected 15\n", result);
6030 result = strcmp (buffer,"TestUTF8WithBOM");
6031 ok(result == 0,
6032 "EM_STREAMIN: Test UTF8WithBOM set wrong text: Result: %s\n",buffer);
6033 ok(es.dwError == 0, "EM_STREAMIN: Test UTF8WithBOM set error %d, expected %d\n", es.dwError, 0);
6034
6035 phase = 0;
6036 es.dwCookie = (DWORD_PTR)&phase;
6037 es.dwError = 0;
6039 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es);
6040 ok(result == 8, "got %ld\n", result);
6041
6042 WideCharToMultiByte(CP_ACP, 0, UTF8Split_exp, -1, tmp, sizeof(tmp), NULL, NULL);
6043
6044 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6045 ok(result == 3,
6046 "EM_STREAMIN: Test UTF8Split returned %ld\n", result);
6047 result = memcmp (buffer, tmp, 3);
6048 ok(result == 0,
6049 "EM_STREAMIN: Test UTF8Split set wrong text: Result: %s\n",buffer);
6050 ok(es.dwError == 0, "EM_STREAMIN: Test UTF8Split set error %d, expected %d\n", es.dwError, 0);
6051
6052 es.dwCookie = (DWORD_PTR)&cookieForStream4;
6053 es.dwError = 0;
6054 es.pfnCallback = test_EM_STREAMIN_esCallback2;
6055 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es);
6056 ok(result == length4, "got %ld, expected %d\n", result, length4);
6057
6058 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6059 ok (result == length4,
6060 "EM_STREAMIN: Test 4 returned %ld, expected %d\n", result, length4);
6061 ok(es.dwError == 0, "EM_STREAMIN: Test 4 set error %d, expected %d\n", es.dwError, 0);
6062
6063 es.dwCookie = (DWORD_PTR)&cookieForStream5;
6064 es.dwError = 0;
6065 es.pfnCallback = test_EM_STREAMIN_esCallback2;
6066 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT | SF_UNICODE, (LPARAM)&es);
6067 ok(result == sizeof(streamText5), "got %ld, expected %u\n", result, (UINT)sizeof(streamText5));
6068
6069 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6070 ok (result == length5,
6071 "EM_STREAMIN: Test 5 returned %ld, expected %d\n", result, length5);
6072 ok(es.dwError == 0, "EM_STREAMIN: Test 5 set error %d, expected %d\n", es.dwError, 0);
6073
6074 DestroyWindow(hwndRichEdit);
6075
6076 /* Single-line richedit */
6077 hwndRichEdit = new_richedit_with_style(NULL, 0);
6078 ptr = "line1\r\nline2";
6079 es.dwCookie = (DWORD_PTR)&ptr;
6080 es.dwError = 0;
6081 es.pfnCallback = test_EM_STREAMIN_esCallback;
6082 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es);
6083 ok(result == 12, "got %ld, expected %d\n", result, 12);
6084 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6085 ok (!strcmp(buffer, "line1"),
6086 "EM_STREAMIN: Unexpected text '%s'\n", buffer);
6087
6088 /* Test 0-bytes inside text */
6089 hwndRichEdit = new_richedit_with_style(NULL, 0);
6090 phase = 0;
6091 es.dwCookie = (DWORD_PTR)&phase;
6092 es.dwError = 0;
6093 es.pfnCallback = test_EM_STREAMIN_null_bytes;
6094 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
6095 ok(result == 16, "got %ld, expected %d\n", result, 16);
6096 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6097 ok (!strcmp(buffer, "Th is is a test"), "EM_STREAMIN: Unexpected text '%s'\n", buffer);
6098}
6099
6100static void test_EM_StreamIn_Undo(void)
6101{
6102 /* The purpose of this test is to determine when a EM_StreamIn should be
6103 * undoable. This is important because WM_PASTE currently uses StreamIn and
6104 * pasting should always be undoable but streaming isn't always.
6105 *
6106 * cases to test:
6107 * StreamIn plain text without SFF_SELECTION.
6108 * StreamIn plain text with SFF_SELECTION set but a zero-length selection
6109 * StreamIn plain text with SFF_SELECTION and a valid, normal selection
6110 * StreamIn plain text with SFF_SELECTION and a backwards-selection (from>to)
6111 * Feel free to add tests for other text modes or StreamIn things.
6112 */
6113
6114
6115 HWND hwndRichEdit = new_richedit(NULL);
6117 EDITSTREAM es;
6118 char buffer[1024] = {0};
6119 const char randomtext[] = "Some text";
6120
6121 es.pfnCallback = EditStreamCallback;
6122
6123 /* StreamIn, no SFF_SELECTION */
6124 es.dwCookie = nCallbackCount;
6125 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
6126 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)randomtext);
6127 SendMessageA(hwndRichEdit, EM_SETSEL,0,0);
6128 SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es);
6129 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6130 result = strcmp (buffer,"test");
6131 ok (result == 0,
6132 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer);
6133
6134 result = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
6135 ok (result == FALSE,
6136 "EM_STREAMIN without SFF_SELECTION wrongly allows undo\n");
6137
6138 /* StreamIn, SFF_SELECTION, but nothing selected */
6139 es.dwCookie = nCallbackCount;
6140 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
6141 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)randomtext);
6142 SendMessageA(hwndRichEdit, EM_SETSEL,0,0);
6144 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6145 result = strcmp (buffer,"testSome text");
6146 ok (result == 0,
6147 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
6148
6149 result = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
6150 ok (result == TRUE,
6151 "EM_STREAMIN with SFF_SELECTION but no selection set "
6152 "should create an undo\n");
6153
6154 /* StreamIn, SFF_SELECTION, with a selection */
6155 es.dwCookie = nCallbackCount;
6156 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
6157 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)randomtext);
6158 SendMessageA(hwndRichEdit, EM_SETSEL,4,5);
6160 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6161 result = strcmp (buffer,"Sometesttext");
6162 ok (result == 0,
6163 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
6164
6165 result = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
6166 ok (result == TRUE,
6167 "EM_STREAMIN with SFF_SELECTION and selection set "
6168 "should create an undo\n");
6169
6170 DestroyWindow(hwndRichEdit);
6171}
6172
6174{
6175 SETTEXTEX stex = { ST_DEFAULT, CP_ACP };
6176 return SendMessageA(hwnd, EM_SETTEXTEX, (WPARAM)&stex, 0) != 0;
6177}
6178
6180{
6181 static const WCHAR tW[] = {'t',0};
6182 static const WCHAR teW[] = {'t','e',0};
6183 static const WCHAR textW[] = {'t','e','s','t',0};
6184 static const char textA[] = "test";
6185 char bufA[64];
6186 WCHAR bufW[64];
6187 HWND hwnd;
6188 int em_settextex_supported, ret;
6189
6190#define set_textA(hwnd, wm_set_text, txt) \
6191 do { \
6192 SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; \
6193 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
6194 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
6195 ret = SendMessageA(hwnd, wm_set_text, wparam, (LPARAM)txt); \
6196 ok(ret, "SendMessageA(%02x) error %u\n", wm_set_text, GetLastError()); \
6197 } while(0)
6198#define expect_textA(hwnd, wm_get_text, txt) \
6199 do { \
6200 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
6201 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)&gtex; \
6202 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
6203 memset(bufA, 0xAA, sizeof(bufA)); \
6204 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
6205 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
6206 ret = lstrcmpA(bufA, txt); \
6207 ok(!ret, "%02x: strings do not match: expected %s got %s\n", wm_get_text, txt, bufA); \
6208 } while(0)
6209
6210#define set_textW(hwnd, wm_set_text, txt) \
6211 do { \
6212 SETTEXTEX stex = { ST_DEFAULT, 1200 }; \
6213 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
6214 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
6215 ret = SendMessageW(hwnd, wm_set_text, wparam, (LPARAM)txt); \
6216 ok(ret, "SendMessageW(%02x) error %u\n", wm_set_text, GetLastError()); \
6217 } while(0)
6218#define expect_textW(hwnd, wm_get_text, txt) \
6219 do { \
6220 GETTEXTEX gtex = { 64, GT_DEFAULT, 1200, NULL, NULL }; \
6221 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)&gtex; \
6222 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
6223 memset(bufW, 0xAA, sizeof(bufW)); \
6224 ret = SendMessageW(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
6225 ok(ret, "SendMessageW(%02x) error %u\n", wm_get_text, GetLastError()); \
6226 ret = lstrcmpW(bufW, txt); \
6227 ok(!ret, "%02x: strings do not match: expected[0] %x got[0] %x\n", wm_get_text, txt[0], bufW[0]); \
6228 } while(0)
6229#define expect_empty(hwnd, wm_get_text) \
6230 do { \
6231 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
6232 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)&gtex; \
6233 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
6234 memset(bufA, 0xAA, sizeof(bufA)); \
6235 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
6236 ok(!ret, "empty richedit should return 0, got %d\n", ret); \
6237 ok(!*bufA, "empty richedit should return empty string, got %s\n", bufA); \
6238 } while(0)
6239
6240 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
6241 0, 0, 200, 60, 0, 0, 0, 0);
6242 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
6243
6245 ok(ret, "RichEdit20W should be unicode under NT\n");
6246
6247 /* EM_SETTEXTEX is supported starting from version 3.0 */
6248 em_settextex_supported = is_em_settextex_supported(hwnd);
6249 trace("EM_SETTEXTEX is %ssupported on this platform\n",
6250 em_settextex_supported ? "" : "NOT ");
6251
6254
6255 ret = SendMessageA(hwnd, WM_CHAR, textW[0], 0);
6256 ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret);
6260
6261 ret = SendMessageA(hwnd, WM_CHAR, textA[1], 0);
6262 ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret);
6266
6270
6275
6276 if (em_settextex_supported)
6277 {
6282 }
6283
6289
6290 if (em_settextex_supported)
6291 {
6297 }
6299
6300 hwnd = CreateWindowExA(0, "RichEdit20A", NULL, WS_POPUP,
6301 0, 0, 200, 60, 0, 0, 0, 0);
6302 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
6303
6305 ok(!ret, "RichEdit20A should NOT be unicode\n");
6306
6311
6312 if (em_settextex_supported)
6313 {
6318 }
6319
6325
6326 if (em_settextex_supported)
6327 {
6333 }
6335}
6336
6337static void test_WM_CHAR(void)
6338{
6339 HWND hwnd;
6340 int ret;
6341 const char * char_list = "abc\rabc\r";
6342 const char * expected_content_single = "abcabc";
6343 const char * expected_content_multi = "abc\r\nabc\r\n";
6344 char buffer[64] = {0};
6345 const char * p;
6346
6347 /* single-line control must IGNORE carriage returns */
6348 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
6349 0, 0, 200, 60, 0, 0, 0, 0);
6350 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
6351
6352 p = char_list;
6353 while (*p != '\0') {
6355 ret = SendMessageA(hwnd, WM_CHAR, *p, 1);
6356 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *p, ret);
6357 SendMessageA(hwnd, WM_KEYUP, *p, 1);
6358 p++;
6359 }
6360
6362 ret = strcmp(buffer, expected_content_single);
6363 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n");
6364
6366
6367 /* multi-line control inserts CR normally */
6368 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP|ES_MULTILINE,
6369 0, 0, 200, 60, 0, 0, 0, 0);
6370 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
6371
6372 p = char_list;
6373 while (*p != '\0') {
6375 ret = SendMessageA(hwnd, WM_CHAR, *p, 1);
6376 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *p, ret);
6377 SendMessageA(hwnd, WM_KEYUP, *p, 1);
6378 p++;
6379 }
6380
6382 ret = strcmp(buffer, expected_content_multi);
6383 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n");
6384
6386}
6387
6389{
6390 HWND hwnd;
6391 GETTEXTLENGTHEX gtl;
6392 int ret;
6393 const char * base_string = "base string";
6394 const char * test_string = "a\nb\n\n\r\n";
6395 const char * test_string_after = "a";
6396 const char * test_string_2 = "a\rtest\rstring";
6397 char buffer[64] = {0};
6398
6399 /* single line */
6400 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
6401 0, 0, 200, 60, 0, 0, 0, 0);
6402 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
6403
6405 gtl.codepage = CP_ACP;
6407 ok(ret == 0, "ret %d\n",ret);
6408
6410 gtl.codepage = CP_ACP;
6412 ok(ret == 0, "ret %d\n",ret);
6413
6414 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)base_string);
6415
6417 gtl.codepage = CP_ACP;
6419 ok(ret == strlen(base_string), "ret %d\n",ret);
6420
6422 gtl.codepage = CP_ACP;
6424 ok(ret == strlen(base_string), "ret %d\n",ret);
6425
6427
6429 gtl.codepage = CP_ACP;
6431 ok(ret == 1, "ret %d\n",ret);
6432
6434 gtl.codepage = CP_ACP;
6436 ok(ret == 1, "ret %d\n",ret);
6437
6439 ret = strcmp(buffer, test_string_after);
6440 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n");
6441
6443
6444 /* multi line */
6445 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP | ES_MULTILINE,
6446 0, 0, 200, 60, 0, 0, 0, 0);
6447 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
6448
6450 gtl.codepage = CP_ACP;
6452 ok(ret == 0, "ret %d\n",ret);
6453
6455 gtl.codepage = CP_ACP;
6457 ok(ret == 0, "ret %d\n",ret);
6458
6459 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)base_string);
6460
6462 gtl.codepage = CP_ACP;
6464 ok(ret == strlen(base_string), "ret %d\n",ret);
6465
6467 gtl.codepage = CP_ACP;
6469 ok(ret == strlen(base_string), "ret %d\n",ret);
6470
6471 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)test_string_2);
6472
6474 gtl.codepage = CP_ACP;
6476 ok(ret == strlen(test_string_2) + 2, "ret %d\n",ret);
6477
6479 gtl.codepage = CP_ACP;
6481 ok(ret == strlen(test_string_2), "ret %d\n",ret);
6482
6484
6486 gtl.codepage = CP_ACP;
6488 ok(ret == 10, "ret %d\n",ret);
6489
6491 gtl.codepage = CP_ACP;
6493 ok(ret == 6, "ret %d\n",ret);
6494
6495 /* Unicode/NUMCHARS/NUMBYTES */
6496 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)test_string_2);
6497
6498 gtl.flags = GTL_DEFAULT;
6499 gtl.codepage = 1200;
6501 ok(ret == lstrlenA(test_string_2),
6502 "GTL_DEFAULT gave %i, expected %i\n", ret, lstrlenA(test_string_2));
6503
6504 gtl.flags = GTL_NUMCHARS;
6505 gtl.codepage = 1200;
6507 ok(ret == lstrlenA(test_string_2),
6508 "GTL_NUMCHARS gave %i, expected %i\n", ret, lstrlenA(test_string_2));
6509
6510 gtl.flags = GTL_NUMBYTES;
6511 gtl.codepage = 1200;
6513 ok(ret == lstrlenA(test_string_2)*2,
6514 "GTL_NUMBYTES gave %i, expected %i\n", ret, lstrlenA(test_string_2)*2);
6515
6516 gtl.flags = GTL_PRECISE;
6517 gtl.codepage = 1200;
6519 ok(ret == lstrlenA(test_string_2)*2,
6520 "GTL_PRECISE gave %i, expected %i\n", ret, lstrlenA(test_string_2)*2);
6521
6523 gtl.codepage = 1200;
6525 ok(ret == lstrlenA(test_string_2),
6526 "GTL_NUMCHAR | GTL_PRECISE gave %i, expected %i\n", ret, lstrlenA(test_string_2));
6527
6529 gtl.codepage = 1200;
6531 ok(ret == E_INVALIDARG,
6532 "GTL_NUMCHARS | GTL_NUMBYTES gave %i, expected %i\n", ret, E_INVALIDARG);
6533
6535}
6536
6537
6538/* globals that parent and child access when checking event masks & notifications */
6541static int watchForEventMask = 0;
6542
6543/* parent proc that queries the edit's event mask when it gets a WM_COMMAND */
6545{
6546 if(message == WM_COMMAND && (watchForEventMask & (wParam >> 16)))
6547 {
6549 }
6551}
6552
6553/* test event masks in combination with WM_COMMAND */
6554static void test_eventMask(void)
6555{
6556 HWND parent;
6557 int ret, style;
6558 WNDCLASSA cls;
6559 const char text[] = "foo bar\n";
6560 int eventMask;
6561
6562 /* register class to capture WM_COMMAND */
6563 cls.style = 0;
6565 cls.cbClsExtra = 0;
6566 cls.cbWndExtra = 0;
6567 cls.hInstance = GetModuleHandleA(0);
6568 cls.hIcon = 0;
6571 cls.lpszMenuName = NULL;
6572 cls.lpszClassName = "EventMaskParentClass";
6573 if(!RegisterClassA(&cls)) assert(0);
6574
6576 0, 0, 200, 60, NULL, NULL, NULL, NULL);
6577 ok (parent != 0, "Failed to create parent window\n");
6578
6580 ok(eventMaskEditHwnd != 0, "Failed to create edit window\n");
6581
6582 eventMask = ENM_CHANGE | ENM_UPDATE;
6584 ok(ret == ENM_NONE, "wrong event mask\n");
6586 ok(ret == eventMask, "failed to set event mask\n");
6587
6588 /* check what happens when we ask for EN_CHANGE and send WM_SETTEXT */
6589 queriedEventMask = 0; /* initialize to something other than we expect */
6592 ok(ret == TRUE, "failed to set text\n");
6593 /* richedit should mask off ENM_CHANGE when it sends an EN_CHANGE
6594 notification in response to WM_SETTEXT */
6595 ok(queriedEventMask == (eventMask & ~ENM_CHANGE),
6596 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask);
6597
6598 /* check to see if EN_CHANGE is sent when redraw is turned off */
6600 ok(IsWindowVisible(eventMaskEditHwnd), "Window should be visible.\n");
6602 /* redraw is disabled by making the window invisible. */
6603 ok(!IsWindowVisible(eventMaskEditHwnd), "Window shouldn't be visible.\n");
6604 queriedEventMask = 0; /* initialize to something other than we expect */
6606 ok(queriedEventMask == (eventMask & ~ENM_CHANGE),
6607 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask);
6609 ok(IsWindowVisible(eventMaskEditHwnd), "Window should be visible.\n");
6610
6611 /* check to see if EN_UPDATE is sent when the editor isn't visible */
6615 ok(!IsWindowVisible(eventMaskEditHwnd), "Window shouldn't be visible.\n");
6617 queriedEventMask = 0; /* initialize to something other than we expect */
6619 ok(queriedEventMask == 0,
6620 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask);
6622 ok(IsWindowVisible(eventMaskEditHwnd), "Window should be visible.\n");
6623 queriedEventMask = 0; /* initialize to something other than we expect */
6625 ok(queriedEventMask == eventMask,
6626 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask);
6627
6628
6630}
6631
6632static int received_WM_NOTIFY = 0;
6633static int modify_at_WM_NOTIFY = 0;
6636
6638{
6639 if(message == WM_NOTIFY)
6640 {
6643 if (filter_on_WM_NOTIFY) return TRUE;
6644 }
6646}
6647
6648static void test_WM_NOTIFY(void)
6649{
6650 HWND parent;
6651 WNDCLASSA cls;
6652 CHARFORMAT2A cf2;
6653 int sel_start, sel_end;
6654
6655 /* register class to capture WM_NOTIFY */
6656 cls.style = 0;
6658 cls.cbClsExtra = 0;
6659 cls.cbWndExtra = 0;
6660 cls.hInstance = GetModuleHandleA(0);
6661 cls.hIcon = 0;
6664 cls.lpszMenuName = NULL;
6665 cls.lpszClassName = "WM_NOTIFY_ParentClass";
6666 if(!RegisterClassA(&cls)) assert(0);
6667
6669 0, 0, 200, 60, NULL, NULL, NULL, NULL);
6670 ok (parent != 0, "Failed to create parent window\n");
6671
6673 ok(hwndRichedit_WM_NOTIFY != 0, "Failed to create edit window\n");
6674
6676
6677 /* Notifications for selection change should only be sent when selection
6678 actually changes. EM_SETCHARFORMAT is one message that calls
6679 ME_CommitUndo, which should check whether message should be sent */
6681 cf2.cbSize = sizeof(CHARFORMAT2A);
6683 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
6684 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
6686 ok(received_WM_NOTIFY == 0, "Unexpected WM_NOTIFY was sent!\n");
6687
6688 /* WM_SETTEXT should NOT cause a WM_NOTIFY to be sent when selection is
6689 already at 0. */
6693 ok(received_WM_NOTIFY == 0, "Unexpected WM_NOTIFY was sent!\n");
6694 ok(modify_at_WM_NOTIFY == 0, "WM_NOTIFY callback saw text flagged as modified!\n");
6695
6699 ok(received_WM_NOTIFY == 1, "Expected WM_NOTIFY was NOT sent!\n");
6700
6704 ok(received_WM_NOTIFY == 1, "Expected WM_NOTIFY was NOT sent!\n");
6705 ok(modify_at_WM_NOTIFY == 0, "WM_NOTIFY callback saw text flagged as modified!\n");
6706
6707 /* Test for WM_NOTIFY messages with redraw disabled. */
6712 ok(received_WM_NOTIFY == 1, "Expected WM_NOTIFY was NOT sent!\n");
6714
6715 /* Test filtering key events. */
6718 SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
6721 SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
6722 ok(sel_start == 1 && sel_end == 1,
6723 "selections is incorrectly at (%d,%d)\n", sel_start, sel_end);
6727 SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
6728 ok(sel_start == 1 && sel_end == 1,
6729 "selections is incorrectly at (%d,%d)\n", sel_start, sel_end);
6730
6731 /* test with owner set to NULL */
6734 SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
6735 ok(sel_start == 1 && sel_end == 1,
6736 "selections is incorrectly at (%d,%d)\n", sel_start, sel_end);
6737
6740}
6741
6743#define CURSOR_CLIENT_X 5
6744#define CURSOR_CLIENT_Y 5
6745#define WP_PARENT 1
6746#define WP_CHILD 2
6747
6749{
6750 if(message == WM_NOTIFY && ((NMHDR*)lParam)->code == EN_LINK)
6751 {
6752 enlink = *(ENLINK*)lParam;
6753 }
6755}
6756
6757static void link_notify_test(const char *desc, int i, HWND hwnd, HWND parent,
6758 UINT msg, WPARAM wParam, LPARAM lParam, BOOL notifies)
6759{
6760 ENLINK junk_enlink;
6761
6762 switch (msg)
6763 {
6764 case WM_LBUTTONDBLCLK:
6765 case WM_LBUTTONDOWN:
6766 case WM_LBUTTONUP:
6767 case WM_MOUSEHOVER:
6768 case WM_MOUSEMOVE:
6769 case WM_MOUSEWHEEL:
6770 case WM_RBUTTONDBLCLK:
6771 case WM_RBUTTONDOWN:
6772 case WM_RBUTTONUP:
6774 break;
6775 case WM_SETCURSOR:
6776 if (wParam == WP_PARENT)
6777 wParam = (WPARAM)parent;
6778 else if (wParam == WP_CHILD)
6779 wParam = (WPARAM)hwnd;
6780 break;
6781 }
6782
6783 memset(&junk_enlink, 0x23, sizeof(junk_enlink));
6784 enlink = junk_enlink;
6785
6787
6788 if (notifies)
6789 {
6791 "%s test %i: Expected hwnd %p got %p\n", desc, i, hwnd, enlink.nmhdr.hwndFrom);
6792 ok(enlink.nmhdr.idFrom == 0,
6793 "%s test %i: Expected idFrom 0 got 0x%lx\n", desc, i, enlink.nmhdr.idFrom);
6794 ok(enlink.msg == msg,
6795 "%s test %i: Expected msg 0x%x got 0x%x\n", desc, i, msg, enlink.msg);
6796 if (msg == WM_SETCURSOR)
6797 {
6798 ok(enlink.wParam == 0,
6799 "%s test %i: Expected wParam 0 got 0x%lx\n", desc, i, enlink.wParam);
6800 }
6801 else
6802 {
6804 "%s test %i: Expected wParam 0x%lx got 0x%lx\n", desc, i, wParam, enlink.wParam);
6805 }
6807 "%s test %i: Expected lParam 0x%lx got 0x%lx\n",
6809 ok(enlink.chrg.cpMin == 0 && enlink.chrg.cpMax == 31,
6810 "%s test %i: Expected link range [0,31) got [%i,%i)\n", desc, i, enlink.chrg.cpMin, enlink.chrg.cpMax);
6811 }
6812 else
6813 {
6814 ok(memcmp(&enlink, &junk_enlink, sizeof(enlink)) == 0,
6815 "%s test %i: Expected enlink to remain unmodified\n", desc, i);
6816 }
6817}
6818
6819static void test_EN_LINK(void)
6820{
6821 HWND hwnd, parent;
6822 WNDCLASSA cls;
6823 CHARFORMAT2A cf2;
6824 POINT orig_cursor_pos;
6825 POINT cursor_screen_pos = {CURSOR_CLIENT_X, CURSOR_CLIENT_Y};
6826 int i;
6827
6828 static const struct
6829 {
6830 UINT msg;
6831 WPARAM wParam;
6832 LPARAM lParam;
6833 BOOL notifies;
6834 }
6835 link_notify_tests[] =
6836 {
6837 /* hold down the left button and try some messages */
6838 { WM_LBUTTONDOWN, 0, 0, TRUE }, /* 0 */
6839 { EM_LINESCROLL, 0, 1, FALSE },
6840 { EM_SCROLL, SB_BOTTOM, 0, FALSE },
6841 { WM_LBUTTONDBLCLK, 0, 0, TRUE },
6842 { WM_MOUSEHOVER, 0, 0, FALSE },
6843 { WM_MOUSEMOVE, 0, 0, FALSE },
6844 { WM_MOUSEWHEEL, 0, 0, FALSE },
6845 { WM_RBUTTONDBLCLK, 0, 0, TRUE },
6846 { WM_RBUTTONDOWN, 0, 0, TRUE },
6847 { WM_RBUTTONUP, 0, 0, TRUE },
6848 { WM_SETCURSOR, 0, 0, FALSE },
6849 { WM_SETCURSOR, WP_PARENT, 0, FALSE },
6850 { WM_SETCURSOR, WP_CHILD, 0, TRUE },
6851 { WM_SETCURSOR, WP_CHILD, 1, TRUE },
6852 { WM_VSCROLL, SB_BOTTOM, 0, FALSE },
6853 { WM_LBUTTONUP, 0, 0, TRUE },
6854 /* hold down the right button and try some messages */
6855 { WM_RBUTTONDOWN, 0, 0, TRUE }, /* 16 */
6856 { EM_LINESCROLL, 0, 1, FALSE },
6857 { EM_SCROLL, SB_BOTTOM, 0, FALSE },
6858 { WM_LBUTTONDBLCLK, 0, 0, TRUE },
6859 { WM_LBUTTONDOWN, 0, 0, TRUE },
6860 { WM_LBUTTONUP, 0, 0, TRUE },
6861 { WM_MOUSEHOVER, 0, 0, FALSE },
6862 { WM_MOUSEMOVE, 0, 0, TRUE },
6863 { WM_MOUSEWHEEL, 0, 0, FALSE },
6864 { WM_RBUTTONDBLCLK, 0, 0, TRUE },
6865 { WM_SETCURSOR, 0, 0, FALSE },
6866 { WM_SETCURSOR, WP_PARENT, 0, FALSE },
6867 { WM_SETCURSOR, WP_CHILD, 0, TRUE },
6868 { WM_SETCURSOR, WP_CHILD, 1, TRUE },
6869 { WM_VSCROLL, SB_BOTTOM, 0, FALSE },
6870 { WM_RBUTTONUP, 0, 0, TRUE },
6871 /* try the messages with both buttons released */
6872 { EM_LINESCROLL, 0, 1, FALSE }, /* 32 */
6873 { EM_SCROLL, SB_BOTTOM, 0, FALSE },
6874 { WM_LBUTTONDBLCLK, 0, 0, TRUE },
6875 { WM_LBUTTONDOWN, 0, 0, TRUE },
6876 { WM_LBUTTONUP, 0, 0, TRUE },
6877 { WM_MOUSEHOVER, 0, 0, FALSE },
6878 { WM_MOUSEMOVE, 0, 0, TRUE },
6879 { WM_MOUSEWHEEL, 0, 0, FALSE },
6880 { WM_RBUTTONDBLCLK, 0, 0, TRUE },
6881 { WM_RBUTTONDOWN, 0, 0, TRUE },
6882 { WM_RBUTTONUP, 0, 0, TRUE },
6883 { WM_SETCURSOR, 0, 0, FALSE },
6884 { WM_SETCURSOR, WP_CHILD, 0, TRUE },
6885 { WM_SETCURSOR, WP_CHILD, 1, TRUE },
6886 { WM_SETCURSOR, WP_PARENT, 0, FALSE },
6887 { WM_VSCROLL, SB_BOTTOM, 0, FALSE }
6888 };
6889
6890 /* register class to capture WM_NOTIFY */
6891 cls.style = 0;
6893 cls.cbClsExtra = 0;
6894 cls.cbWndExtra = 0;
6895 cls.hInstance = GetModuleHandleA(0);
6896 cls.hIcon = 0;
6899 cls.lpszMenuName = NULL;
6900 cls.lpszClassName = "EN_LINK_ParentClass";
6901 if(!RegisterClassA(&cls)) assert(0);
6902
6904 0, 0, 200, 60, NULL, NULL, NULL, NULL);
6905 ok(parent != 0, "Failed to create parent window\n");
6906
6908 ok(hwnd != 0, "Failed to create edit window\n");
6909
6911
6912 cf2.cbSize = sizeof(CHARFORMAT2A);
6913 cf2.dwMask = CFM_LINK;
6914 cf2.dwEffects = CFE_LINK;
6916 /* mixing letters and numbers causes runs to be split */
6917 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"link text with at least 2 runs");
6918
6919 GetCursorPos(&orig_cursor_pos);
6920 SetCursorPos(0, 0);
6921
6922 for (i = 0; i < ARRAY_SIZE(link_notify_tests); i++)
6923 {
6924 link_notify_test("cursor position simulated", i, hwnd, parent,
6925 link_notify_tests[i].msg, link_notify_tests[i].wParam, link_notify_tests[i].lParam,
6926 link_notify_tests[i].msg == WM_SETCURSOR ? FALSE : link_notify_tests[i].notifies);
6927 }
6928
6929 ClientToScreen(hwnd, &cursor_screen_pos);
6930 SetCursorPos(cursor_screen_pos.x, cursor_screen_pos.y);
6931
6932 for (i = 0; i < ARRAY_SIZE(link_notify_tests); i++)
6933 {
6934 link_notify_test("cursor position set", i, hwnd, parent,
6935 link_notify_tests[i].msg, link_notify_tests[i].wParam, link_notify_tests[i].lParam,
6936 link_notify_tests[i].notifies);
6937 }
6938
6939 SetCursorPos(orig_cursor_pos.x, orig_cursor_pos.y);
6942}
6943
6944static void test_undo_coalescing(void)
6945{
6946 HWND hwnd;
6947 int result;
6948 char buffer[64] = {0};
6949
6950 /* multi-line control inserts CR normally */
6951 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP|ES_MULTILINE,
6952 0, 0, 200, 60, 0, 0, 0, 0);
6953 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
6954
6956 ok (result == FALSE, "Can undo after window creation.\n");
6957 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
6958 ok (result == FALSE, "Undo operation successful with nothing to undo.\n");
6960 ok (result == FALSE, "Can redo after window creation.\n");
6961 result = SendMessageA(hwnd, EM_REDO, 0, 0);
6962 ok (result == FALSE, "Redo operation successful with nothing undone.\n");
6963
6964 /* Test the effect of arrows keys during typing on undo transactions*/
6965 simulate_typing_characters(hwnd, "one two three");
6968 simulate_typing_characters(hwnd, " four five six");
6969
6971 ok (result == FALSE, "Can redo before anything is undone.\n");
6973 ok (result == TRUE, "Cannot undo typed characters.\n");
6974 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
6975 ok (result == TRUE, "EM_UNDO Failed to undo typed characters.\n");
6977 ok (result == TRUE, "Cannot redo after undo.\n");
6979 result = strcmp(buffer, "one two three");
6980 ok (result == 0, "expected '%s' but got '%s'\n", "one two three", buffer);
6981
6983 ok (result == TRUE, "Cannot undo typed characters.\n");
6984 result = SendMessageA(hwnd, WM_UNDO, 0, 0);
6985 ok (result == TRUE, "Failed to undo typed characters.\n");
6987 result = strcmp(buffer, "");
6988 ok (result == 0, "expected '%s' but got '%s'\n", "", buffer);
6989
6990 /* Test the effect of focus changes during typing on undo transactions*/
6991 simulate_typing_characters(hwnd, "one two three");
6993 ok (result == FALSE, "Redo buffer should have been cleared by typing.\n");
6996 simulate_typing_characters(hwnd, " four five six");
6997 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
6998 ok (result == TRUE, "Failed to undo typed characters.\n");
7000 result = strcmp(buffer, "one two three");
7001 ok (result == 0, "expected '%s' but got '%s'\n", "one two three", buffer);
7002
7003 /* Test the effect of the back key during typing on undo transactions */
7006 ok (result == TRUE, "Failed to clear the text.\n");
7007 simulate_typing_characters(hwnd, "one two threa");
7009 ok (result == FALSE, "Redo buffer should have been cleared by typing.\n");
7012 simulate_typing_characters(hwnd, "e four five six");
7013 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
7014 ok (result == TRUE, "Failed to undo typed characters.\n");
7016 result = strcmp(buffer, "");
7017 ok (result == 0, "expected '%s' but got '%s'\n", "", buffer);
7018
7019 /* Test the effect of the delete key during typing on undo transactions */
7021 result = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"abcd");
7022 ok(result == TRUE, "Failed to set the text.\n");
7023 SendMessageA(hwnd, EM_SETSEL, 1, 1);
7028 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
7029 ok (result == TRUE, "Failed to undo typed characters.\n");
7031 result = strcmp(buffer, "acd");
7032 ok (result == 0, "expected '%s' but got '%s'\n", "acd", buffer);
7033 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
7034 ok (result == TRUE, "Failed to undo typed characters.\n");
7036 result = strcmp(buffer, "abcd");
7037 ok (result == 0, "expected '%s' but got '%s'\n", "abcd", buffer);
7038
7039 /* Test the effect of EM_STOPGROUPTYPING on undo transactions*/
7042 ok (result == TRUE, "Failed to clear the text.\n");
7043 simulate_typing_characters(hwnd, "one two three");
7045 ok (result == 0, "expected %d but got %d\n", 0, result);
7046 simulate_typing_characters(hwnd, " four five six");
7047 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
7048 ok (result == TRUE, "Failed to undo typed characters.\n");
7050 result = strcmp(buffer, "one two three");
7051 ok (result == 0, "expected '%s' but got '%s'\n", "one two three", buffer);
7052 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
7053 ok (result == TRUE, "Failed to undo typed characters.\n");
7055 result = strcmp(buffer, "");
7056 ok (result == 0, "expected '%s' but got '%s'\n", "", buffer);
7057
7059}
7060
7062{
7063 int length;
7064
7065 /* MSDN lied, length is actually the number of bytes. */
7066 length = bytes / sizeof(WCHAR);
7067 switch(code)
7068 {
7069 case WB_ISDELIMITER:
7070 return text[pos] == 'X';
7071 case WB_LEFT:
7072 case WB_MOVEWORDLEFT:
7074 return pos-1;
7076 case WB_LEFTBREAK:
7077 pos--;
7079 pos--;
7080 return pos;
7081 case WB_RIGHT:
7082 case WB_MOVEWORDRIGHT:
7084 return pos+1;
7086 case WB_RIGHTBREAK:
7087 pos++;
7089 pos++;
7090 return pos;
7091 default:
7092 ok(FALSE, "Unexpected code %d\n", code);
7093 break;
7094 }
7095 return 0;
7096}
7097
7098static void test_word_movement(void)
7099{
7100 HWND hwnd;
7101 int result;
7102 int sel_start, sel_end;
7103 const WCHAR textW[] = {'o','n','e',' ','t','w','o','X','t','h','r','e','e',0};
7104
7105 /* multi-line control inserts CR normally */
7107
7108 result = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"one two three");
7109 ok (result == TRUE, "Failed to clear the text.\n");
7110 SendMessageA(hwnd, EM_SETSEL, 0, 0);
7111 /* |one two three */
7112
7114 /* one |two three */
7115 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7116 ok(sel_start == sel_end, "Selection should be empty\n");
7117 ok(sel_start == 4, "Cursor is at %d instead of %d\n", sel_start, 4);
7118
7120 /* one two |three */
7121 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7122 ok(sel_start == sel_end, "Selection should be empty\n");
7123 ok(sel_start == 9, "Cursor is at %d instead of %d\n", sel_start, 9);
7124
7126 /* one |two three */
7127 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7128 ok(sel_start == sel_end, "Selection should be empty\n");
7129 ok(sel_start == 4, "Cursor is at %d instead of %d\n", sel_start, 4);
7130
7132 /* |one two three */
7133 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7134 ok(sel_start == sel_end, "Selection should be empty\n");
7135 ok(sel_start == 0, "Cursor is at %d instead of %d\n", sel_start, 0);
7136
7137 SendMessageA(hwnd, EM_SETSEL, 8, 8);
7138 /* one two | three */
7140 /* one two |three */
7141 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7142 ok(sel_start == sel_end, "Selection should be empty\n");
7143 ok(sel_start == 9, "Cursor is at %d instead of %d\n", sel_start, 9);
7144
7145 SendMessageA(hwnd, EM_SETSEL, 11, 11);
7146 /* one two th|ree */
7148 /* one two |three */
7149 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7150 ok(sel_start == sel_end, "Selection should be empty\n");
7151 ok(sel_start == 9, "Cursor is at %d instead of %d\n", sel_start, 9);
7152
7153 /* Test with a custom word break procedure that uses X as the delimiter. */
7154 result = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"one twoXthree");
7155 ok (result == TRUE, "Failed to clear the text.\n");
7157 /* |one twoXthree */
7159 /* one twoX|three */
7160 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7161 ok(sel_start == sel_end, "Selection should be empty\n");
7162 ok(sel_start == 8, "Cursor is at %d instead of %d\n", sel_start, 8);
7163
7165
7166 /* Make sure the behaviour is the same with a unicode richedit window,
7167 * and using unicode functions. */
7168
7171 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7172
7173 /* Test with a custom word break procedure that uses X as the delimiter. */
7175 ok (result == TRUE, "Failed to clear the text.\n");
7177 /* |one twoXthree */
7179 /* one twoX|three */
7180 SendMessageW(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7181 ok(sel_start == sel_end, "Selection should be empty\n");
7182 ok(sel_start == 8, "Cursor is at %d instead of %d\n", sel_start, 8);
7183
7185}
7186
7187static void test_EM_CHARFROMPOS(void)
7188{
7189 HWND hwnd;
7190 int result;
7191 RECT rcClient;
7192 POINTL point;
7193 point.x = 0;
7194 point.y = 40;
7195
7196 /* multi-line control inserts CR normally */
7199 (LPARAM)"one two three four five six seven\reight");
7200 ok(result == 1, "Expected 1, got %d\n", result);
7201 GetClientRect(hwnd, &rcClient);
7202
7204 ok(result == 34, "expected character index of 34 but got %d\n", result);
7205
7206 /* Test with points outside the bounds of the richedit control. */
7207 point.x = -1;
7208 point.y = 40;
7210 todo_wine ok(result == 34, "expected character index of 34 but got %d\n", result);
7211
7212 point.x = 1000;
7213 point.y = 0;
7215 todo_wine ok(result == 33, "expected character index of 33 but got %d\n", result);
7216
7217 point.x = 1000;
7218 point.y = 36;
7220 todo_wine ok(result == 39, "expected character index of 39 but got %d\n", result);
7221
7222 point.x = 1000;
7223 point.y = -1;
7225 todo_wine ok(result == 0, "expected character index of 0 but got %d\n", result);
7226
7227 point.x = 1000;
7228 point.y = rcClient.bottom + 1;
7230 todo_wine ok(result == 34, "expected character index of 34 but got %d\n", result);
7231
7232 point.x = 1000;
7233 point.y = rcClient.bottom;
7235 todo_wine ok(result == 39, "expected character index of 39 but got %d\n", result);
7236
7238}
7239
7240static void test_word_wrap(void)
7241{
7242 HWND hwnd;
7243 POINTL point = {0, 60}; /* This point must be below the first line */
7244 const char *text = "Must be long enough to test line wrapping";
7246 int res, pos, lines;
7247
7248 /* Test the effect of WS_HSCROLL and ES_AUTOHSCROLL styles on wrapping
7249 * when specified on window creation and set later. */
7250 hwnd = CreateWindowA(RICHEDIT_CLASS20A, NULL, dwCommonStyle,
7251 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
7252 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
7254 ok(res, "WM_SETTEXT failed.\n");
7256 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
7258 ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines);
7259
7262 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
7264
7266 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
7267 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
7268
7270 ok(res, "WM_SETTEXT failed.\n");
7272 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
7274 ok(lines == 1, "Line wasn't expected to wrap (lines=%d).\n", lines);
7275
7276 SetWindowLongW(hwnd, GWL_STYLE, dwCommonStyle);
7278 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
7280
7282 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
7283 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
7285 ok(res, "WM_SETTEXT failed.\n");
7287 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
7288
7289 SetWindowLongW(hwnd, GWL_STYLE, dwCommonStyle);
7291 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
7293
7295 dwCommonStyle|WS_HSCROLL|ES_AUTOHSCROLL,
7296 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
7297 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
7299 ok(res, "WM_SETTEXT failed.\n");
7301 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
7302
7303 SetWindowLongW(hwnd, GWL_STYLE, dwCommonStyle);
7305 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
7306
7307 /* Test the effect of EM_SETTARGETDEVICE on word wrap. */
7309 ok(res, "EM_SETTARGETDEVICE failed (returned %d).\n", res);
7311 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
7312
7314 ok(res, "EM_SETTARGETDEVICE failed (returned %d).\n", res);
7316 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
7318
7319 /* Test to see if wrapping happens with redraw disabled. */
7320 hwnd = CreateWindowA(RICHEDIT_CLASS20A, NULL, dwCommonStyle,
7321 0, 0, 400, 80, NULL, NULL, hmoduleRichEdit, NULL);
7322 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
7325 ok(res, "EM_REPLACESEL failed.\n");
7327 ok(lines == 1, "Line wasn't expected to wrap (lines=%d).\n", lines);
7328 MoveWindow(hwnd, 0, 0, 200, 80, FALSE);
7330 ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines);
7331
7334}
7335
7336static void test_autoscroll(void)
7337{
7339 int lines, ret, redraw;
7340 POINT pt;
7341
7342 for (redraw = 0; redraw <= 1; redraw++) {
7343 trace("testing with WM_SETREDRAW=%d\n", redraw);
7345 SendMessageA(hwnd, EM_REPLACESEL, 0, (LPARAM)"1\n2\n3\n4\n5\n6\n7\n8");
7347 ok(lines == 8, "%d lines instead of 8\n", lines);
7349 ok(ret == 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret);
7350 ok(pt.y != 0, "Didn't scroll down after replacing text.\n");
7352 ok(ret & WS_VSCROLL, "Scrollbar was not shown yet (style=%x).\n", (UINT)ret);
7353
7356 ok(lines == 1, "%d lines instead of 1\n", lines);
7358 ok(ret == 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret);
7359 ok(pt.y == 0, "y scroll position is %d after clearing text.\n", pt.y);
7361 ok(!(ret & WS_VSCROLL), "Scrollbar is still shown (style=%x).\n", (UINT)ret);
7362 }
7363
7366
7367 /* The WS_VSCROLL and WS_HSCROLL styles implicitly set
7368 * auto vertical/horizontal scrolling options. */
7371 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7372 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7374 ok(ret & ECO_AUTOVSCROLL, "ECO_AUTOVSCROLL isn't set.\n");
7375 ok(ret & ECO_AUTOHSCROLL, "ECO_AUTOHSCROLL isn't set.\n");
7377 ok(!(ret & ES_AUTOVSCROLL), "ES_AUTOVSCROLL is set.\n");
7378 ok(!(ret & ES_AUTOHSCROLL), "ES_AUTOHSCROLL is set.\n");
7380
7383 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7384 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7386 ok(!(ret & ECO_AUTOVSCROLL), "ECO_AUTOVSCROLL is set.\n");
7387 ok(!(ret & ECO_AUTOHSCROLL), "ECO_AUTOHSCROLL is set.\n");
7389 ok(!(ret & ES_AUTOVSCROLL), "ES_AUTOVSCROLL is set.\n");
7390 ok(!(ret & ES_AUTOHSCROLL), "ES_AUTOHSCROLL is set.\n");
7392}
7393
7394
7395static void test_format_rect(void)
7396{
7397 HWND hwnd;
7398 RECT rc, expected, clientRect;
7399 int n;
7400 DWORD options;
7401
7404 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7405 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7406
7407 GetClientRect(hwnd, &clientRect);
7408
7409 expected = clientRect;
7410 InflateRect(&expected, -1, 0);
7412 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7414
7415 for (n = -3; n <= 3; n++)
7416 {
7417 rc = clientRect;
7418 InflateRect(&rc, -n, -n);
7420
7421 expected = rc;
7422 expected.top = max(0, rc.top);
7423 expected.left = max(0, rc.left);
7424 expected.bottom = min(clientRect.bottom, rc.bottom);
7425 expected.right = min(clientRect.right, rc.right);
7427 ok(EqualRect(&rc, &expected), "[n=%d] rect %s != %s\n", n, wine_dbgstr_rect(&rc),
7429 }
7430
7431 rc = clientRect;
7433 expected = clientRect;
7435 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7437
7438 /* Adding the selectionbar adds the selectionbar width to the left side. */
7441 ok(options & ECO_SELECTIONBAR, "EM_SETOPTIONS failed to add selectionbar.\n");
7442 expected.left += 8; /* selection bar width */
7444 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7446
7447 rc = clientRect;
7449 expected = clientRect;
7451 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7453
7454 /* Removing the selectionbar subtracts the selectionbar width from the left side,
7455 * even if the left side is already 0. */
7458 ok(!(options & ECO_SELECTIONBAR), "EM_SETOPTIONS failed to remove selectionbar.\n");
7459 expected.left -= 8; /* selection bar width */
7461 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7463
7464 /* Set the absolute value of the formatting rectangle. */
7465 rc = clientRect;
7467 expected = clientRect;
7469 ok(EqualRect(&rc, &expected), "[n=%d] rect %s != %s\n", n, wine_dbgstr_rect(&rc),
7471
7472 /* MSDN documents the EM_SETRECT message as using the rectangle provided in
7473 * LPARAM as being a relative offset when the WPARAM value is 1, but these
7474 * tests show that this isn't true. */
7475 rc.top = 15;
7476 rc.left = 15;
7477 rc.bottom = clientRect.bottom - 15;
7478 rc.right = clientRect.right - 15;
7479 expected = rc;
7482 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7484
7485 /* For some reason it does not limit the values to the client rect with
7486 * a WPARAM value of 1. */
7487 rc.top = -15;
7488 rc.left = -15;
7489 rc.bottom = clientRect.bottom + 15;
7490 rc.right = clientRect.right + 15;
7491 expected = rc;
7494 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7496
7497 /* Reset to default rect and check how the format rect adjusts to window
7498 * resize and how it copes with very small windows */
7500
7501 MoveWindow(hwnd, 0, 0, 100, 30, FALSE);
7502 GetClientRect(hwnd, &clientRect);
7503
7504 expected = clientRect;
7505 InflateRect(&expected, -1, 0);
7507 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7509
7510 MoveWindow(hwnd, 0, 0, 0, 30, FALSE);
7511 GetClientRect(hwnd, &clientRect);
7512
7513 expected = clientRect;
7514 InflateRect(&expected, -1, 0);
7516 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7518
7519 MoveWindow(hwnd, 0, 0, 100, 0, FALSE);
7520 GetClientRect(hwnd, &clientRect);
7521
7522 expected = clientRect;
7523 InflateRect(&expected, -1, 0);
7525 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7527
7529
7530 /* The extended window style affects the formatting rectangle. */
7533 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7534 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7535
7536 GetClientRect(hwnd, &clientRect);
7537
7538 expected = clientRect;
7539 expected.top += 1;
7540 InflateRect(&expected, -1, 0);
7542 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7544
7545 rc = clientRect;
7546 InflateRect(&rc, -5, -5);
7547 expected = rc;
7548 expected.top -= 1;
7549 InflateRect(&expected, 1, 0);
7552 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7554
7556}
7557
7558static void test_WM_GETDLGCODE(void)
7559{
7560 HWND hwnd;
7561 UINT res, expected;
7562 MSG msg;
7563
7565
7568 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7569 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7570 msg.hwnd = hwnd;
7573 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7574 res, expected);
7576
7577 msg.message = WM_KEYDOWN;
7578 msg.wParam = VK_RETURN;
7579 msg.lParam = (MapVirtualKeyA(VK_RETURN, MAPVK_VK_TO_VSC) << 16) | 0x0001;
7580 msg.pt.x = 0;
7581 msg.pt.y = 0;
7582 msg.time = GetTickCount();
7583
7586 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7587 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7588 msg.hwnd = hwnd;
7591 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7592 res, expected);
7594
7597 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7598 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7599 msg.hwnd = hwnd;
7602 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7603 res, expected);
7605
7608 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7609 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7610 msg.hwnd = hwnd;
7613 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7614 res, expected);
7616
7618 WS_POPUP,
7619 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7620 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7621 msg.hwnd = hwnd;
7624 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7625 res, expected);
7627
7628 msg.wParam = VK_TAB;
7629 msg.lParam = (MapVirtualKeyA(VK_TAB, MAPVK_VK_TO_VSC) << 16) | 0x0001;
7630
7633 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7634 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7635 msg.hwnd = hwnd;
7638 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7639 res, expected);
7641
7643 WS_POPUP,
7644 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7645 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7646 msg.hwnd = hwnd;
7649 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7650 res, expected);
7652
7654
7657 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7658 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7659 msg.hwnd = hwnd;
7662 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7663 res, expected);
7665
7667 WS_POPUP,
7668 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7669 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7670 msg.hwnd = hwnd;
7673 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7674 res, expected);
7676
7678
7679 msg.wParam = 'a';
7680 msg.lParam = (MapVirtualKeyA('a', MAPVK_VK_TO_VSC) << 16) | 0x0001;
7681
7684 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7685 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7686 msg.hwnd = hwnd;
7689 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7690 res, expected);
7692
7694 WS_POPUP,
7695 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7696 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7697 msg.hwnd = hwnd;
7700 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7701 res, expected);
7703
7704 msg.message = WM_CHAR;
7705
7708 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7709 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7710 msg.hwnd = hwnd;
7713 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7714 res, expected);
7716
7718 WS_POPUP,
7719 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7720 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7721 msg.hwnd = hwnd;
7724 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7725 res, expected);
7727
7730 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7731 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7734 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7735 res, expected);
7737}
7738
7739static void test_zoom(void)
7740{
7741 HWND hwnd;
7742 UINT ret;
7743 RECT rc;
7744 POINT pt;
7745 int numerator, denominator;
7746
7748 GetClientRect(hwnd, &rc);
7749 pt.x = (rc.right - rc.left) / 2;
7750 pt.y = (rc.bottom - rc.top) / 2;
7752
7753 /* Test initial zoom value */
7754 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7755 ok(numerator == 0, "Numerator should be initialized to 0 (got %d).\n", numerator);
7756 ok(denominator == 0, "Denominator should be initialized to 0 (got %d).\n", denominator);
7757 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7758
7759 /* test scroll wheel */
7762 MAKELPARAM(pt.x, pt.y));
7763 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret);
7765
7766 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7767 ok(numerator == 110, "incorrect numerator is %d\n", numerator);
7768 ok(denominator == 100, "incorrect denominator is %d\n", denominator);
7769 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7770
7771 /* Test how much the mouse wheel can zoom in and out. */
7772 ret = SendMessageA(hwnd, EM_SETZOOM, 490, 100);
7773 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret);
7774
7777 MAKELPARAM(pt.x, pt.y));
7778 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret);
7780
7781 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7782 ok(numerator == 500, "incorrect numerator is %d\n", numerator);
7783 ok(denominator == 100, "incorrect denominator is %d\n", denominator);
7784 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7785
7786 ret = SendMessageA(hwnd, EM_SETZOOM, 491, 100);
7787 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret);
7788
7791 MAKELPARAM(pt.x, pt.y));
7792 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret);
7794
7795 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7796 ok(numerator == 491, "incorrect numerator is %d\n", numerator);
7797 ok(denominator == 100, "incorrect denominator is %d\n", denominator);
7798 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7799
7800 ret = SendMessageA(hwnd, EM_SETZOOM, 20, 100);
7801 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret);
7802
7805 MAKELPARAM(pt.x, pt.y));
7806 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret);
7808
7809 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7810 ok(numerator == 10, "incorrect numerator is %d\n", numerator);
7811 ok(denominator == 100, "incorrect denominator is %d\n", denominator);
7812 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7813
7814 ret = SendMessageA(hwnd, EM_SETZOOM, 19, 100);
7815 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret);
7816
7819 MAKELPARAM(pt.x, pt.y));
7820 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret);
7822
7823 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7824 ok(numerator == 19, "incorrect numerator is %d\n", numerator);
7825 ok(denominator == 100, "incorrect denominator is %d\n", denominator);
7826 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7827
7828 /* Test how WM_SCROLLWHEEL treats our custom denominator. */
7829 ret = SendMessageA(hwnd, EM_SETZOOM, 50, 13);
7830 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret);
7831
7834 MAKELPARAM(pt.x, pt.y));
7835 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret);
7837
7838 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7839 ok(numerator == 394, "incorrect numerator is %d\n", numerator);
7840 ok(denominator == 100, "incorrect denominator is %d\n", denominator);
7841 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7842
7843 /* Test bounds checking on EM_SETZOOM */
7844 ret = SendMessageA(hwnd, EM_SETZOOM, 2, 127);
7845 ok(ret == TRUE, "EM_SETZOOM rejected valid values (%d).\n", ret);
7846
7847 ret = SendMessageA(hwnd, EM_SETZOOM, 127, 2);
7848 ok(ret == TRUE, "EM_SETZOOM rejected valid values (%d).\n", ret);
7849
7850 ret = SendMessageA(hwnd, EM_SETZOOM, 2, 128);
7851 ok(ret == FALSE, "EM_SETZOOM accepted invalid values (%d).\n", ret);
7852
7853 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7854 ok(numerator == 127, "incorrect numerator is %d\n", numerator);
7855 ok(denominator == 2, "incorrect denominator is %d\n", denominator);
7856 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7857
7858 ret = SendMessageA(hwnd, EM_SETZOOM, 128, 2);
7859 ok(ret == FALSE, "EM_SETZOOM accepted invalid values (%d).\n", ret);
7860
7861 /* See if negative numbers are accepted. */
7862 ret = SendMessageA(hwnd, EM_SETZOOM, -100, -100);
7863 ok(ret == FALSE, "EM_SETZOOM accepted invalid values (%d).\n", ret);
7864
7865 /* See if negative numbers are accepted. */
7866 ret = SendMessageA(hwnd, EM_SETZOOM, 0, 100);
7867 ok(ret == FALSE, "EM_SETZOOM failed (%d).\n", ret);
7868
7869 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7870 ok(numerator == 127, "incorrect numerator is %d\n", numerator);
7871 ok(denominator == 2, "incorrect denominator is %d\n", denominator);
7872 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7873
7874 /* Reset the zoom value */
7875 ret = SendMessageA(hwnd, EM_SETZOOM, 0, 0);
7876 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret);
7877
7879}
7880
7882{
7884};
7885
7887
7888#define test_dm_messages(wmclose, wmgetdefid, wmnextdlgctl) \
7889 ok(dm_messages.wm_close == wmclose, "expected %d WM_CLOSE message, " \
7890 "got %d\n", wmclose, dm_messages.wm_close); \
7891 ok(dm_messages.wm_getdefid == wmgetdefid, "expected %d WM_GETDIFID message, " \
7892 "got %d\n", wmgetdefid, dm_messages.wm_getdefid);\
7893 ok(dm_messages.wm_nextdlgctl == wmnextdlgctl, "expected %d WM_NEXTDLGCTL message, " \
7894 "got %d\n", wmnextdlgctl, dm_messages.wm_nextdlgctl)
7895
7897{
7898 switch (iMsg)
7899 {
7900 case DM_GETDEFID:
7901 dm_messages.wm_getdefid++;
7903 case WM_NEXTDLGCTL:
7904 dm_messages.wm_nextdlgctl++;
7905 break;
7906 case WM_CLOSE:
7907 dm_messages.wm_close++;
7908 break;
7909 }
7910
7911 return DefWindowProcA(hwnd, iMsg, wParam, lParam);
7912}
7913
7914static void test_dialogmode(void)
7915{
7916 HWND hwRichEdit, hwParent, hwButton;
7917 MSG msg= {0};
7918 int lcount, r;
7919 WNDCLASSA cls;
7920
7921 cls.style = 0;
7923 cls.cbClsExtra = 0;
7924 cls.cbWndExtra = 0;
7925 cls.hInstance = GetModuleHandleA(0);
7926 cls.hIcon = 0;
7929 cls.lpszMenuName = NULL;
7930 cls.lpszClassName = "DialogModeParentClass";
7931 if(!RegisterClassA(&cls)) assert(0);
7932
7933 hwParent = CreateWindowA("DialogModeParentClass", NULL, WS_OVERLAPPEDWINDOW,
7934 CW_USEDEFAULT, 0, 200, 120, NULL, NULL, GetModuleHandleA(0), NULL);
7935
7936 /* Test richedit(ES_MULTILINE) */
7937
7938 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE, hwParent);
7939
7940 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
7941 ok(0 == r, "expected 0, got %d\n", r);
7942 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
7943 ok(2 == lcount, "expected 2, got %d\n", lcount);
7944
7945 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, 0);
7946 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r);
7947
7948 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
7949 ok(0 == r, "expected 0, got %d\n", r);
7950 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
7951 ok(3 == lcount, "expected 3, got %d\n", lcount);
7952
7953 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
7954 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r);
7955 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
7956 ok(0 == r, "expected 0, got %d\n", r);
7957 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
7958 ok(3 == lcount, "expected 3, got %d\n", lcount);
7959
7960 DestroyWindow(hwRichEdit);
7961
7962 /* Test standalone richedit(ES_MULTILINE) */
7963
7965
7966 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
7967 ok(0 == r, "expected 0, got %d\n", r);
7968 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
7969 ok(2 == lcount, "expected 2, got %d\n", lcount);
7970
7971 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
7972 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r);
7973
7974 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
7975 ok(0 == r, "expected 0, got %d\n", r);
7976 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
7977 ok(2 == lcount, "expected 2, got %d\n", lcount);
7978
7979 DestroyWindow(hwRichEdit);
7980
7981 /* Check a destination for messages */
7982
7983 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE, hwParent);
7984
7985 SetWindowLongA(hwRichEdit, GWL_STYLE, GetWindowLongA(hwRichEdit, GWL_STYLE)& ~WS_POPUP);
7986 SetParent( hwRichEdit, NULL);
7987
7988 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
7989 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r);
7990
7991 memset(&dm_messages, 0, sizeof(dm_messages));
7992 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
7993 ok(0 == r, "expected 0, got %d\n", r);
7994 test_dm_messages(0, 1, 0);
7995
7996 memset(&dm_messages, 0, sizeof(dm_messages));
7997 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
7998 ok(0 == r, "expected 0, got %d\n", r);
7999 test_dm_messages(0, 0, 1);
8000
8001 DestroyWindow(hwRichEdit);
8002
8003 /* Check messages from richedit(ES_MULTILINE) */
8004
8005 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE, hwParent);
8006
8007 memset(&dm_messages, 0, sizeof(dm_messages));
8008 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8009 ok(0 == r, "expected 0, got %d\n", r);
8010 test_dm_messages(0, 0, 0);
8011
8012 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8013 ok(2 == lcount, "expected 2, got %d\n", lcount);
8014
8015 memset(&dm_messages, 0, sizeof(dm_messages));
8016 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
8017 ok(0 == r, "expected 0, got %d\n", r);
8018 test_dm_messages(0, 0, 0);
8019
8020 memset(&dm_messages, 0, sizeof(dm_messages));
8021 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
8022 ok(0 == r, "expected 0, got %d\n", r);
8023 test_dm_messages(0, 0, 0);
8024
8025 memset(&dm_messages, 0, sizeof(dm_messages));
8026 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
8027 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r);
8028 test_dm_messages(0, 0, 0);
8029
8030 memset(&dm_messages, 0, sizeof(dm_messages));
8031 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8032 ok(0 == r, "expected 0, got %d\n", r);
8033 test_dm_messages(0, 1, 0);
8034
8035 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8036 ok(2 == lcount, "expected 2, got %d\n", lcount);
8037
8038 memset(&dm_messages, 0, sizeof(dm_messages));
8039 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
8040 ok(0 == r, "expected 0, got %d\n", r);
8041 test_dm_messages(0, 0, 0);
8042
8043 memset(&dm_messages, 0, sizeof(dm_messages));
8044 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
8045 ok(0 == r, "expected 0, got %d\n", r);
8046 test_dm_messages(0, 0, 1);
8047
8048 hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON,
8049 100, 100, 50, 20, hwParent, (HMENU)ID_RICHEDITTESTDBUTTON, GetModuleHandleA(0), NULL);
8050 ok(hwButton!=NULL, "CreateWindow failed with error code %d\n", GetLastError());
8051
8052 memset(&dm_messages, 0, sizeof(dm_messages));
8053 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8054 ok(0 == r, "expected 0, got %d\n", r);
8055 test_dm_messages(0, 1, 1);
8056
8057 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8058 ok(2 == lcount, "expected 2, got %d\n", lcount);
8059
8060 DestroyWindow(hwButton);
8061 DestroyWindow(hwRichEdit);
8062
8063 /* Check messages from richedit(ES_MULTILINE|ES_WANTRETURN) */
8064
8065 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE|ES_WANTRETURN, hwParent);
8066
8067 memset(&dm_messages, 0, sizeof(dm_messages));
8068 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8069 ok(0 == r, "expected 0, got %d\n", r);
8070 test_dm_messages(0, 0, 0);
8071
8072 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8073 ok(2 == lcount, "expected 2, got %d\n", lcount);
8074
8075 memset(&dm_messages, 0, sizeof(dm_messages));
8076 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
8077 ok(0 == r, "expected 0, got %d\n", r);
8078 test_dm_messages(0, 0, 0);
8079
8080 memset(&dm_messages, 0, sizeof(dm_messages));
8081 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
8082 ok(0 == r, "expected 0, got %d\n", r);
8083 test_dm_messages(0, 0, 0);
8084
8085 memset(&dm_messages, 0, sizeof(dm_messages));
8086 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
8087 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r);
8088 test_dm_messages(0, 0, 0);
8089
8090 memset(&dm_messages, 0, sizeof(dm_messages));
8091 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8092 ok(0 == r, "expected 0, got %d\n", r);
8093 test_dm_messages(0, 0, 0);
8094
8095 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8096 ok(3 == lcount, "expected 3, got %d\n", lcount);
8097
8098 memset(&dm_messages, 0, sizeof(dm_messages));
8099 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
8100 ok(0 == r, "expected 0, got %d\n", r);
8101 test_dm_messages(0, 0, 0);
8102
8103 memset(&dm_messages, 0, sizeof(dm_messages));
8104 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
8105 ok(0 == r, "expected 0, got %d\n", r);
8106 test_dm_messages(0, 0, 1);
8107
8108 hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON,
8109 100, 100, 50, 20, hwParent, (HMENU)ID_RICHEDITTESTDBUTTON, GetModuleHandleA(0), NULL);
8110 ok(hwButton!=NULL, "CreateWindow failed with error code %d\n", GetLastError());
8111
8112 memset(&dm_messages, 0, sizeof(dm_messages));
8113 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8114 ok(0 == r, "expected 0, got %d\n", r);
8115 test_dm_messages(0, 0, 0);
8116
8117 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8118 ok(4 == lcount, "expected 4, got %d\n", lcount);
8119
8120 DestroyWindow(hwButton);
8121 DestroyWindow(hwRichEdit);
8122
8123 /* Check messages from richedit(0) */
8124
8125 hwRichEdit = new_window(RICHEDIT_CLASS20A, 0, hwParent);
8126
8127 memset(&dm_messages, 0, sizeof(dm_messages));
8128 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8129 ok(0 == r, "expected 0, got %d\n", r);
8130 test_dm_messages(0, 0, 0);
8131
8132 memset(&dm_messages, 0, sizeof(dm_messages));
8133 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
8134 ok(0 == r, "expected 0, got %d\n", r);
8135 test_dm_messages(0, 0, 0);
8136
8137 memset(&dm_messages, 0, sizeof(dm_messages));
8138 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
8139 ok(0 == r, "expected 0, got %d\n", r);
8140 test_dm_messages(0, 0, 0);
8141
8142 memset(&dm_messages, 0, sizeof(dm_messages));
8143 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
8144 ok(0x8b == r, "expected 0x8b, got 0x%x\n", r);
8145 test_dm_messages(0, 0, 0);
8146
8147 memset(&dm_messages, 0, sizeof(dm_messages));
8148 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8149 ok(0 == r, "expected 0, got %d\n", r);
8150 test_dm_messages(0, 1, 0);
8151
8152 memset(&dm_messages, 0, sizeof(dm_messages));
8153 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
8154 ok(0 == r, "expected 0, got %d\n", r);
8155 test_dm_messages(0, 0, 0);
8156
8157 memset(&dm_messages, 0, sizeof(dm_messages));
8158 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
8159 ok(0 == r, "expected 0, got %d\n", r);
8160 test_dm_messages(0, 0, 1);
8161
8162 hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON,
8163 100, 100, 50, 20, hwParent, (HMENU)ID_RICHEDITTESTDBUTTON, GetModuleHandleA(0), NULL);
8164 ok(hwButton!=NULL, "CreateWindow failed with error code %d\n", GetLastError());
8165
8166 memset(&dm_messages, 0, sizeof(dm_messages));
8167 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8168 ok(0 == r, "expected 0, got %d\n", r);
8169 test_dm_messages(0, 1, 1);
8170
8171 DestroyWindow(hwRichEdit);
8172
8173 /* Check messages from richedit(ES_WANTRETURN) */
8174
8175 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_WANTRETURN, hwParent);
8176
8177 memset(&dm_messages, 0, sizeof(dm_messages));
8178 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8179 ok(0 == r, "expected 0, got %d\n", r);
8180 test_dm_messages(0, 0, 0);
8181
8182 memset(&dm_messages, 0, sizeof(dm_messages));
8183 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
8184 ok(0x8b == r, "expected 0x8b, got 0x%x\n", r);
8185 test_dm_messages(0, 0, 0);
8186
8187 memset(&dm_messages, 0, sizeof(dm_messages));
8188 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8189 ok(0 == r, "expected 0, got %d\n", r);
8190 test_dm_messages(0, 0, 0);
8191
8192 hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON,
8193 100, 100, 50, 20, hwParent, (HMENU)ID_RICHEDITTESTDBUTTON, GetModuleHandleA(0), NULL);
8194 ok(hwButton!=NULL, "CreateWindow failed with error code %d\n", GetLastError());
8195
8196 memset(&dm_messages, 0, sizeof(dm_messages));
8197 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8198 ok(0 == r, "expected 0, got %d\n", r);
8199 test_dm_messages(0, 0, 0);
8200
8201 DestroyWindow(hwRichEdit);
8202 DestroyWindow(hwParent);
8203}
8204
8206{
8207 static const struct {
8208 WCHAR c;
8209 BOOL isdelimiter; /* expected result of WB_ISDELIMITER */
8210 } delimiter_tests[] = {
8211 {0x0a, FALSE}, /* newline */
8212 {0x0b, FALSE}, /* vertical tab */
8213 {0x0c, FALSE}, /* form feed */
8214 {0x0d, FALSE}, /* carriage return */
8215 {0x20, TRUE}, /* space */
8216 {0x61, FALSE}, /* capital letter a */
8217 {0xa0, FALSE}, /* no-break space */
8218 {0x2000, FALSE}, /* en quad */
8219 {0x3000, FALSE}, /* Ideographic space */
8220 {0x1100, FALSE}, /* Hangul Choseong Kiyeok (G sound) Ordinary Letter*/
8221 {0x11ff, FALSE}, /* Hangul Jongseoung Kiyeok-Hieuh (Hard N sound) Ordinary Letter*/
8222 {0x115f, FALSE}, /* Hangul Choseong Filler (no sound, used with two letter Hangul words) Ordinary Letter */
8223 {0xac00, FALSE}, /* Hangul character GA*/
8224 {0xd7af, FALSE}, /* End of Hangul character chart */
8225 {0xf020, TRUE}, /* MS private for CP_SYMBOL round trip?, see kb897872 */
8226 {0xff20, FALSE}, /* fullwidth commercial @ */
8227 {WCH_EMBEDDING, FALSE}, /* object replacement character*/
8228 };
8229 int i;
8230 HWND hwndRichEdit = new_richeditW(NULL);
8231 ok(IsWindowUnicode(hwndRichEdit), "window should be unicode\n");
8232 for (i = 0; i < ARRAY_SIZE(delimiter_tests); i++)
8233 {
8234 WCHAR wbuf[2];
8235 int result;
8236
8237 wbuf[0] = delimiter_tests[i].c;
8238 wbuf[1] = 0;
8239 SendMessageW(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)wbuf);
8241 todo_wine_if (wbuf[0] == 0x20 || wbuf[0] == 0xf020)
8242 ok(result == delimiter_tests[i].isdelimiter,
8243 "wanted ISDELIMITER_W(0x%x) %d, got %d\n",
8244 delimiter_tests[i].c, delimiter_tests[i].isdelimiter, result);
8245 }
8246 DestroyWindow(hwndRichEdit);
8247}
8248
8250{
8251 static const struct {
8252 WCHAR c;
8253 BOOL isdelimiter; /* expected result of WB_ISDELIMITER */
8254 } delimiter_tests[] = {
8255 {0x0a, FALSE}, /* newline */
8256 {0x0b, FALSE}, /* vertical tab */
8257 {0x0c, FALSE}, /* form feed */
8258 {0x0d, FALSE}, /* carriage return */
8259 {0x20, TRUE}, /* space */
8260 {0x61, FALSE}, /* capital letter a */
8261 };
8262 int i;
8263 HWND hwndRichEdit = new_richedit(NULL);
8264
8265 ok(!IsWindowUnicode(hwndRichEdit), "window should not be unicode\n");
8266 for (i = 0; i < ARRAY_SIZE(delimiter_tests); i++)
8267 {
8268 int result;
8269 char buf[2];
8270 buf[0] = delimiter_tests[i].c;
8271 buf[1] = 0;
8272 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buf);
8274 todo_wine_if (buf[0] == 0x20)
8275 ok(result == delimiter_tests[i].isdelimiter,
8276 "wanted ISDELIMITER_A(0x%x) %d, got %d\n",
8277 delimiter_tests[i].c, delimiter_tests[i].isdelimiter, result);
8278 }
8279 DestroyWindow(hwndRichEdit);
8280}
8281
8282static void format_test_result(char *target, const char *src)
8283{
8284 int i;
8285 for (i = 0; i < strlen(src); i++)
8286 sprintf(target + 2*i, "%02x", src[i] & 0xFF);
8287 target[2*i] = 0;
8288}
8289
8290/*
8291 * This test attempts to show the effect of enter on a richedit
8292 * control v1.0 inserts CRLF whereas for higher versions it only
8293 * inserts CR. If shows that EM_GETTEXTEX with GT_USECRLF == WM_GETTEXT
8294 * and also shows that GT_USECRLF has no effect in richedit 1.0, but
8295 * does for higher. The same test is cloned in riched32 and riched20.
8296 * Also shows the difference between WM_CHAR/WM_KEYDOWN in v1.0 and higher versions
8297 */
8298static void test_enter(void)
8299{
8300 static const struct {
8301 const char *initialtext;
8302 const int cursor;
8303 const char *expectedwmtext;
8304 const char *expectedemtext;
8305 const char *expectedemtextcrlf;
8306 } testenteritems[] = {
8307 { "aaabbb\r\n", 3, "aaa\r\nbbb\r\n", "aaa\rbbb\r", "aaa\r\nbbb\r\n"},
8308 { "aaabbb\r\n", 6, "aaabbb\r\n\r\n", "aaabbb\r\r", "aaabbb\r\n\r\n"},
8309 { "aa\rabbb\r\n", 7, "aa\r\nabbb\r\n\r\n", "aa\rabbb\r\r", "aa\r\nabbb\r\n\r\n"},
8310 { "aa\rabbb\r\n", 3, "aa\r\n\r\nabbb\r\n", "aa\r\rabbb\r", "aa\r\n\r\nabbb\r\n"},
8311 { "aa\rabbb\r\n", 2, "aa\r\n\r\nabbb\r\n", "aa\r\rabbb\r", "aa\r\n\r\nabbb\r\n"}
8312 };
8313
8314 char expectedbuf[1024];
8315 char resultbuf[1024];
8316 HWND hwndRichEdit = new_richedit(NULL);
8317 UINT i;
8318 char buf[1024] = {0};
8319 GETTEXTEX getText = {sizeof(buf)};
8321 const char *expected;
8322
8323 for (i = 0; i < ARRAY_SIZE(testenteritems); i++)
8324 {
8325 /* Set the text to the initial text */
8326 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)testenteritems[i].initialtext);
8327 ok (result == 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i, result);
8328
8329 /* Send Enter */
8330 SendMessageA(hwndRichEdit, EM_SETSEL, testenteritems[i].cursor, testenteritems[i].cursor);
8331 simulate_typing_characters(hwndRichEdit, "\r");
8332
8333 /* 1. Retrieve with WM_GETTEXT */
8334 buf[0] = 0x00;
8335 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf);
8336 expected = testenteritems[i].expectedwmtext;
8337
8338 format_test_result(resultbuf, buf);
8339 format_test_result(expectedbuf, expected);
8340
8342 ok (result == 0,
8343 "[%d] WM_GETTEXT unexpected '%s' expected '%s'\n",
8344 i, resultbuf, expectedbuf);
8345
8346 /* 2. Retrieve with EM_GETTEXTEX, GT_DEFAULT */
8347 getText.flags = GT_DEFAULT;
8348 getText.codepage = CP_ACP;
8349 buf[0] = 0x00;
8350 result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
8351 expected = testenteritems[i].expectedemtext;
8352
8353 format_test_result(resultbuf, buf);
8354 format_test_result(expectedbuf, expected);
8355
8357 ok (result == 0,
8358 "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n",
8359 i, resultbuf, expectedbuf);
8360
8361 /* 3. Retrieve with EM_GETTEXTEX, GT_USECRLF */
8362 getText.flags = GT_USECRLF;
8363 getText.codepage = CP_ACP;
8364 buf[0] = 0x00;
8365 result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
8366 expected = testenteritems[i].expectedemtextcrlf;
8367
8368 format_test_result(resultbuf, buf);
8369 format_test_result(expectedbuf, expected);
8370
8372 ok (result == 0,
8373 "[%d] EM_GETTEXTEX, GT_USECRLF unexpected '%s', expected '%s'\n",
8374 i, resultbuf, expectedbuf);
8375 }
8376
8377 /* Show that WM_CHAR is handled differently from WM_KEYDOWN */
8378 getText.flags = GT_DEFAULT;
8379 getText.codepage = CP_ACP;
8380
8381 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
8382 ok (result == 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i, result);
8383 SendMessageW(hwndRichEdit, WM_CHAR, 'T', 0);
8384 SendMessageW(hwndRichEdit, WM_KEYDOWN, VK_RETURN, 0);
8385
8386 result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
8387 ok(result == 2, "Got %d\n", (int)result);
8388 format_test_result(resultbuf, buf);
8389 format_test_result(expectedbuf, "T\r");
8390 result = strcmp(resultbuf, expectedbuf);
8391 ok (result == 0, "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n", i, resultbuf, expectedbuf);
8392
8393 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
8394 ok (result == 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i, result);
8395 SendMessageW(hwndRichEdit, WM_CHAR, 'T', 0);
8396 SendMessageW(hwndRichEdit, WM_CHAR, '\r', 0);
8397
8398 result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
8399 ok(result == 1, "Got %d\n", (int)result);
8400 format_test_result(resultbuf, buf);
8401 format_test_result(expectedbuf, "T");
8402 result = strcmp(resultbuf, expectedbuf);
8403 ok (result == 0, "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n", i, resultbuf, expectedbuf);
8404
8405 DestroyWindow(hwndRichEdit);
8406}
8407
8408static void test_WM_CREATE(void)
8409{
8410 static const WCHAR titleW[] = {'l','i','n','e','1','\n','l','i','n','e','2',0};
8411 static const char title[] = "line1\nline2";
8412
8413 HWND rich_edit;
8414 LRESULT res;
8415 char buf[64];
8416 int len;
8417
8419 0, 0, 200, 80, NULL, NULL, NULL, NULL);
8420 ok(rich_edit != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
8421
8422 len = GetWindowTextA(rich_edit, buf, sizeof(buf));
8423 ok(len == 5, "GetWindowText returned %d\n", len);
8424 ok(!strcmp(buf, "line1"), "buf = %s\n", buf);
8425
8426 res = SendMessageA(rich_edit, EM_GETSEL, 0, 0);
8427 ok(res == 0, "SendMessage(EM_GETSEL) returned %lx\n", res);
8428
8429 DestroyWindow(rich_edit);
8430
8432 0, 0, 200, 80, NULL, NULL, NULL, NULL);
8433 ok(rich_edit != NULL, "class: %s, error: %d\n", wine_dbgstr_w(RICHEDIT_CLASS20W), (int) GetLastError());
8434
8435 len = GetWindowTextA(rich_edit, buf, sizeof(buf));
8436 ok(len == 12, "GetWindowText returned %d\n", len);
8437 ok(!strcmp(buf, "line1\r\nline2"), "buf = %s\n", buf);
8438
8439 res = SendMessageA(rich_edit, EM_GETSEL, 0, 0);
8440 ok(res == 0, "SendMessage(EM_GETSEL) returned %lx\n", res);
8441
8442 DestroyWindow(rich_edit);
8443}
8444
8445/*******************************************************************
8446 * Test that after deleting all of the text, the first paragraph
8447 * format reverts to the default.
8448 */
8450{
8451 HWND richedit = new_richeditW( NULL );
8453 WORD def_align, new_align;
8454
8455 memset( &fmt, 0, sizeof(fmt) );
8456 fmt.cbSize = sizeof(PARAFORMAT2);
8457 fmt.dwMask = -1;
8458 SendMessageA( richedit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt );
8459 def_align = fmt.wAlignment;
8460 new_align = (def_align == PFA_LEFT) ? PFA_RIGHT : PFA_LEFT;
8461
8462 simulate_typing_characters( richedit, "123" );
8463
8464 SendMessageA( richedit, EM_SETSEL, 0, -1 );
8465 fmt.dwMask = PFM_ALIGNMENT;
8466 fmt.wAlignment = new_align;
8467 SendMessageA( richedit, EM_SETPARAFORMAT, 0, (LPARAM)&fmt );
8468
8469 SendMessageA( richedit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt );
8470 ok( fmt.wAlignment == new_align, "got %d expect %d\n", fmt.wAlignment, new_align );
8471
8472 SendMessageA( richedit, EM_SETSEL, 0, -1 );
8473 SendMessageA( richedit, WM_CUT, 0, 0 );
8474
8475 SendMessageA( richedit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt );
8476 ok( fmt.wAlignment == def_align, "got %d expect %d\n", fmt.wAlignment, def_align );
8477
8478 DestroyWindow( richedit );
8479}
8480
8481static void test_EM_SETREADONLY(void)
8482{
8483 HWND richedit = new_richeditW(NULL);
8484 DWORD dwStyle;
8485 LRESULT res;
8486
8487 res = SendMessageA(richedit, EM_SETREADONLY, TRUE, 0);
8488 ok(res == 1, "EM_SETREADONLY\n");
8489 dwStyle = GetWindowLongA(richedit, GWL_STYLE);
8490 ok(dwStyle & ES_READONLY, "got wrong value: 0x%x\n", dwStyle);
8491
8492 res = SendMessageA(richedit, EM_SETREADONLY, FALSE, 0);
8493 ok(res == 1, "EM_SETREADONLY\n");
8494 dwStyle = GetWindowLongA(richedit, GWL_STYLE);
8495 ok(!(dwStyle & ES_READONLY), "got wrong value: 0x%x\n", dwStyle);
8496
8497 DestroyWindow(richedit);
8498}
8499
8501{
8502 return value / 20;
8503}
8504
8505#define TEST_EM_SETFONTSIZE(hwnd,size,expected_size,expected_res,expected_undo) \
8506 _test_font_size(__LINE__,hwnd,size,expected_size,expected_res,expected_undo)
8507static void _test_font_size(unsigned line, HWND hwnd, LONG size, LONG expected_size,
8508 LRESULT expected_res, BOOL expected_undo)
8509{
8511 LRESULT res;
8512 BOOL isundo;
8513
8514 cf.cbSize = sizeof(cf);
8515 cf.dwMask = CFM_SIZE;
8516
8519 isundo = SendMessageA(hwnd, EM_CANUNDO, 0, 0);
8520 ok_(__FILE__,line)(res == expected_res, "EM_SETFONTSIZE unexpected return value: %lx.\n", res);
8521 ok_(__FILE__,line)(twips2points(cf.yHeight) == expected_size, "got wrong font size: %d, expected: %d\n",
8522 twips2points(cf.yHeight), expected_size);
8523 ok_(__FILE__,line)(isundo == expected_undo, "get wrong undo mark: %d, expected: %d.\n",
8524 isundo, expected_undo);
8525}
8526
8527static void test_EM_SETFONTSIZE(void)
8528{
8529 HWND richedit = new_richedit(NULL);
8530 CHAR text[] = "wine";
8531 CHARFORMAT2A tmp_cf;
8532 LONG default_size;
8533
8534 tmp_cf.cbSize = sizeof(tmp_cf);
8535 tmp_cf.dwMask = CFM_SIZE;
8536 tmp_cf.yHeight = 9 * 20.0;
8537 SendMessageA(richedit, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM)&tmp_cf);
8538
8539 SendMessageA(richedit, WM_SETTEXT, 0, (LPARAM)text);
8540
8541 SendMessageA(richedit, EM_SETMODIFY, FALSE, 0);
8542 /* without selection */
8543 TEST_EM_SETFONTSIZE(richedit, 1, 10, TRUE, FALSE); /* 9 + 1 -> 10 */
8544 SendMessageA(richedit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&tmp_cf);
8545 default_size = twips2points(tmp_cf.yHeight);
8546 ok(default_size == 9, "Default font size should not be changed.\n");
8547 ok(SendMessageA(richedit, EM_SETMODIFY, 0, 0) == FALSE, "Modify flag should not be changed.\n");
8548
8549 SendMessageA(richedit, EM_SETSEL, 0, 2);
8550
8551 TEST_EM_SETFONTSIZE(richedit, 0, 9, TRUE, TRUE); /* 9 + 0 -> 9 */
8552
8553 SendMessageA(richedit, EM_SETMODIFY, FALSE, 0);
8554 TEST_EM_SETFONTSIZE(richedit, 3, 12, TRUE, TRUE); /* 9 + 3 -> 12 */
8555 ok(SendMessageA(richedit, EM_SETMODIFY, 0, 0) == FALSE, "Modify flag should not be changed.\n");
8556
8557 TEST_EM_SETFONTSIZE(richedit, 1, 14, TRUE, TRUE); /* 12 + 1 + 1 -> 14 */
8558 TEST_EM_SETFONTSIZE(richedit, -1, 12, TRUE, TRUE); /* 14 - 1 - 1 -> 12 */
8559 TEST_EM_SETFONTSIZE(richedit, 4, 16, TRUE, TRUE); /* 12 + 4 -> 16 */
8560 TEST_EM_SETFONTSIZE(richedit, 3, 20, TRUE, TRUE); /* 16 + 3 + 1 -> 20 */
8561 TEST_EM_SETFONTSIZE(richedit, 0, 20, TRUE, TRUE); /* 20 + 0 -> 20 */
8562 TEST_EM_SETFONTSIZE(richedit, 8, 28, TRUE, TRUE); /* 20 + 8 -> 28 */
8563 TEST_EM_SETFONTSIZE(richedit, 0, 28, TRUE, TRUE); /* 28 + 0 -> 28 */
8564 TEST_EM_SETFONTSIZE(richedit, 1, 36, TRUE, TRUE); /* 28 + 1 -> 36 */
8565 TEST_EM_SETFONTSIZE(richedit, 0, 36, TRUE, TRUE); /* 36 + 0 -> 36 */
8566 TEST_EM_SETFONTSIZE(richedit, 1, 48, TRUE, TRUE); /* 36 + 1 -> 48 */
8567 TEST_EM_SETFONTSIZE(richedit, 0, 48, TRUE, TRUE); /* 48 + 0 -> 48 */
8568 TEST_EM_SETFONTSIZE(richedit, 1, 72, TRUE, TRUE); /* 48 + 1 -> 72 */
8569 TEST_EM_SETFONTSIZE(richedit, 0, 72, TRUE, TRUE); /* 72 + 0 -> 72 */
8570 TEST_EM_SETFONTSIZE(richedit, 1, 80, TRUE, TRUE); /* 72 + 1 -> 80 */
8571 TEST_EM_SETFONTSIZE(richedit, 0, 80, TRUE, TRUE); /* 80 + 0 -> 80 */
8572 TEST_EM_SETFONTSIZE(richedit, 1, 90, TRUE, TRUE); /* 80 + 1 -> 90 */
8573 TEST_EM_SETFONTSIZE(richedit, 0, 90, TRUE, TRUE); /* 90 + 0 -> 90 */
8574 TEST_EM_SETFONTSIZE(richedit, 1, 100, TRUE, TRUE); /* 90 + 1 -> 100 */
8575 TEST_EM_SETFONTSIZE(richedit, 25, 130, TRUE, TRUE); /* 100 + 25 -> 130 */
8576 TEST_EM_SETFONTSIZE(richedit, -1, 120, TRUE, TRUE); /* 130 - 1 -> 120 */
8577 TEST_EM_SETFONTSIZE(richedit, -35, 80, TRUE, TRUE); /* 120 - 35 -> 80 */
8578 TEST_EM_SETFONTSIZE(richedit, -7, 72, TRUE, TRUE); /* 80 - 7 -> 72 */
8579 TEST_EM_SETFONTSIZE(richedit, -42, 28, TRUE, TRUE); /* 72 - 42 -> 28 */
8580 TEST_EM_SETFONTSIZE(richedit, -16, 12, TRUE, TRUE); /* 28 - 16 -> 12 */
8581 TEST_EM_SETFONTSIZE(richedit, -3, 9, TRUE, TRUE); /* 12 - 3 -> 9 */
8582 TEST_EM_SETFONTSIZE(richedit, -8, 1, TRUE, TRUE); /* 9 - 8 -> 1 */
8583 TEST_EM_SETFONTSIZE(richedit, -111, 1, TRUE, TRUE); /* 1 - 111 -> 1 */
8584 TEST_EM_SETFONTSIZE(richedit, 10086, 1638, TRUE, TRUE); /* 1 + 10086 -> 1638 */
8585
8586 /* return FALSE when richedit is TM_PLAINTEXT mode */
8587 SendMessageA(richedit, WM_SETTEXT, 0, (LPARAM)"");
8589 TEST_EM_SETFONTSIZE(richedit, 0, 9, FALSE, FALSE);
8590
8591 DestroyWindow(richedit);
8592}
8593
8594static void test_alignment_style(void)
8595{
8596 HWND richedit = NULL;
8597 PARAFORMAT2 pf;
8598 DWORD align_style[] = {ES_LEFT, ES_CENTER, ES_RIGHT, ES_RIGHT | ES_CENTER,
8603 const char * streamtext =
8604 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n"
8605 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n"
8606 "}\r\n";
8607 EDITSTREAM es;
8608 int i;
8609
8610 for (i = 0; i < ARRAY_SIZE(align_style); i++)
8611 {
8612 DWORD dwStyle, new_align;
8613
8614 richedit = new_windowW(RICHEDIT_CLASS20W, align_style[i], NULL);
8615 memset(&pf, 0, sizeof(pf));
8616 pf.cbSize = sizeof(PARAFORMAT2);
8617 pf.dwMask = -1;
8618
8619 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
8620 ok(pf.wAlignment == align_mask[i], "(i = %d) got %d expected %d\n",
8621 i, pf.wAlignment, align_mask[i]);
8622 dwStyle = GetWindowLongW(richedit, GWL_STYLE);
8623 ok((i ? (dwStyle & align_style[i]) : (!(dwStyle & 0x0000000f))) ,
8624 "(i = %d) didn't set right align style: 0x%x\n", i, dwStyle);
8625
8626
8627 /* Based on test_reset_default_para_fmt() */
8628 new_align = (align_mask[i] == PFA_LEFT) ? PFA_RIGHT : PFA_LEFT;
8629 simulate_typing_characters(richedit, "123");
8630
8631 SendMessageW(richedit, EM_SETSEL, 0, -1);
8632 pf.dwMask = PFM_ALIGNMENT;
8633 pf.wAlignment = new_align;
8634 SendMessageW(richedit, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
8635
8636 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
8637 ok(pf.wAlignment == new_align, "got %d expect %d\n", pf.wAlignment, new_align);
8638
8639 SendMessageW(richedit, EM_SETSEL, 0, -1);
8640 SendMessageW(richedit, WM_CUT, 0, 0);
8641
8642 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
8643 ok(pf.wAlignment == align_mask[i], "got %d expect %d\n", pf.wAlignment, align_mask[i]);
8644
8645 DestroyWindow(richedit);
8646 }
8647
8648 /* test with EM_STREAMIN */
8650 simulate_typing_characters(richedit, "abc");
8651 es.dwCookie = (DWORD_PTR)&streamtext;
8652 es.dwError = 0;
8653 es.pfnCallback = test_EM_STREAMIN_esCallback;
8654 SendMessageW(richedit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
8655 SendMessageW(richedit, EM_SETSEL, 0, -1);
8656 memset(&pf, 0, sizeof(pf));
8657 pf.cbSize = sizeof(PARAFORMAT2);
8658 pf.dwMask = -1;
8660 ok(pf.wAlignment == PFA_LEFT, "got %d expected PFA_LEFT\n", pf.wAlignment);
8661 DestroyWindow(richedit);
8662}
8663
8664static void test_WM_GETTEXTLENGTH(void)
8665{
8666 HWND hwndRichEdit = new_richedit(NULL);
8667 static const char text1[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee";
8668 static const char text2[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee\r\n";
8669 static const char text3[] = "abcdef\x8e\xf0";
8670 int result;
8671
8672 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
8673 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
8674 ok(result == lstrlenA(text1), "WM_GETTEXTLENGTH returned %d, expected %d\n",
8675 result, lstrlenA(text1));
8676
8677 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
8678 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
8679 ok(result == lstrlenA(text2), "WM_GETTEXTLENGTH returned %d, expected %d\n",
8680 result, lstrlenA(text2));
8681
8682 /* Test with multibyte character */
8683 if (!is_lang_japanese)
8684 skip("Skip multibyte character tests on non-Japanese platform\n");
8685 else
8686 {
8687 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text3);
8688 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
8689 todo_wine ok(result == 8, "WM_GETTEXTLENGTH returned %d, expected 8\n", result);
8690 }
8691
8692 DestroyWindow(hwndRichEdit);
8693}
8694
8695static void test_rtf(void)
8696{
8697 const char *specials = "{\\rtf1\\emspace\\enspace\\bullet\\lquote"
8698 "\\rquote\\ldblquote\\rdblquote\\ltrmark\\rtlmark\\zwj\\zwnj}";
8699 const WCHAR expect_specials[] = {' ',' ',0x2022,0x2018,0x2019,0x201c,
8700 0x201d,0x200e,0x200f,0x200d,0x200c};
8701 const char *pard = "{\\rtf1 ABC\\rtlpar\\par DEF\\par HIJ\\pard\\par}";
8702 const char *highlight = "{\\rtf1{\\colortbl;\\red0\\green0\\blue0;\\red128\\green128\\blue128;\\red192\\green192\\blue192;}\\cf2\\highlight3 foo\\par}";
8703
8704 HWND edit = new_richeditW( NULL );
8705 EDITSTREAM es;
8706 WCHAR buf[80];
8710
8711 /* Test rtf specials */
8712 es.dwCookie = (DWORD_PTR)&specials;
8713 es.dwError = 0;
8714 es.pfnCallback = test_EM_STREAMIN_esCallback;
8716 ok( result == 11, "got %ld\n", result );
8717
8719 ok( result == ARRAY_SIZE(expect_specials), "got %ld\n", result );
8720 ok( !memcmp( buf, expect_specials, sizeof(expect_specials) ), "got %s\n", wine_dbgstr_w(buf) );
8721
8722 /* Show that \rtlpar propagates to the second paragraph and is
8723 reset by \pard in the third. */
8724 es.dwCookie = (DWORD_PTR)&pard;
8726 ok( result == 11, "got %ld\n", result );
8727
8728 fmt.cbSize = sizeof(fmt);
8729 SendMessageW( edit, EM_SETSEL, 1, 1 );
8730 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt );
8731 ok( fmt.dwMask & PFM_RTLPARA, "rtl para mask not set\n" );
8732 ok( fmt.wEffects & PFE_RTLPARA, "rtl para not set\n" );
8733 SendMessageW( edit, EM_SETSEL, 5, 5 );
8734 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt );
8735 ok( fmt.dwMask & PFM_RTLPARA, "rtl para mask not set\n" );
8736 ok( fmt.wEffects & PFE_RTLPARA, "rtl para not set\n" );
8737 SendMessageW( edit, EM_SETSEL, 9, 9 );
8738 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt );
8739 ok( fmt.dwMask & PFM_RTLPARA, "rtl para mask not set\n" );
8740 ok( !(fmt.wEffects & PFE_RTLPARA), "rtl para set\n" );
8741
8742 /* Test \highlight */
8743 es.dwCookie = (DWORD_PTR)&highlight;
8745 ok( result == 3, "got %ld\n", result );
8746 SendMessageW( edit, EM_SETSEL, 1, 1 );
8747 memset( &cf, 0, sizeof(cf) );
8748 cf.cbSize = sizeof(cf);
8750 ok( (cf.dwEffects & (CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR)) == 0, "got %08x\n", cf.dwEffects );
8751 ok( cf.crTextColor == RGB(128,128,128), "got %08x\n", cf.crTextColor );
8752 ok( cf.crBackColor == RGB(192,192,192), "got %08x\n", cf.crBackColor );
8753
8754 DestroyWindow( edit );
8755}
8756
8757static void test_background(void)
8758{
8759 HWND hwndRichEdit = new_richedit(NULL);
8760
8761 /* set the background color to black */
8762 ValidateRect(hwndRichEdit, NULL);
8763 SendMessageA(hwndRichEdit, EM_SETBKGNDCOLOR, FALSE, RGB(0, 0, 0));
8764 ok(GetUpdateRect(hwndRichEdit, NULL, FALSE), "Update rectangle is empty!\n");
8765
8766 DestroyWindow(hwndRichEdit);
8767}
8768
8769static void test_eop_char_fmt(void)
8770{
8771 HWND edit = new_richedit( NULL );
8772 const char *rtf = "{\\rtf1{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 Arial;}{\\f1\\fnil\\fcharset2 Symbol;}}"
8773 "{\\fs10{\\pard\\fs16\\fi200\\li360\\f0 First\\par"
8774 "\\f0\\fs25 Second\\par"
8775 "{\\f0\\fs26 Third}\\par"
8776 "{\\f0\\fs22 Fourth}\\par}}}";
8777 EDITSTREAM es;
8779 int i, num, expect_height;
8780
8781 es.dwCookie = (DWORD_PTR)&rtf;
8782 es.dwError = 0;
8783 es.pfnCallback = test_EM_STREAMIN_esCallback;
8784 num = SendMessageA( edit, EM_STREAMIN, SF_RTF, (LPARAM)&es );
8785 ok( num == 25, "got %d\n", num );
8786
8787 for (i = 0; i <= num; i++)
8788 {
8789 SendMessageW( edit, EM_SETSEL, i, i + 1 );
8790 cf.cbSize = sizeof(cf);
8791 cf.dwMask = CFM_SIZE;
8793 ok( cf.dwMask & CFM_SIZE, "%d: got %08x\n", i, cf.dwMask );
8794 if (i < 6) expect_height = 160;
8795 else if (i < 13) expect_height = 250;
8796 else if (i < 18) expect_height = 260;
8797 else if (i == 18 || i == 25) expect_height = 250;
8798 else expect_height = 220;
8799 ok( cf.yHeight == expect_height, "%d: got %d\n", i, cf.yHeight );
8800 }
8801
8802 DestroyWindow( edit );
8803}
8804
8805static void test_para_numbering(void)
8806{
8807 HWND edit = new_richeditW( NULL );
8808 const char *numbers = "{\\rtf1{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 Arial;}{\\f1\\fnil\\fcharset2 Symbol;}}"
8809 "\\pard{\\pntext\\f0 3.\\tab}{\\*\\pn\\pnlvlbody\\pnfs32\\pnf0\\pnindent1000\\pnstart2\\pndec{\\pntxta.}}"
8810 "\\fs20\\fi200\\li360\\f0 First\\par"
8811 "{\\pntext\\f0 4.\\tab}\\f0 Second\\par"
8812 "{\\pntext\\f0 6.\\tab}\\f0 Third\\par}";
8813 const WCHAR expect_numbers_txt[] = {'F','i','r','s','t','\r','S','e','c','o','n','d','\r','T','h','i','r','d',0};
8814 EDITSTREAM es;
8815 WCHAR buf[80];
8817 PARAFORMAT2 fmt, fmt2;
8820
8821 get_text.cb = sizeof(buf);
8822 get_text.flags = GT_RAWTEXT;
8823 get_text.codepage = 1200;
8824 get_text.lpDefaultChar = NULL;
8825 get_text.lpUsedDefChar = NULL;
8826
8827 es.dwCookie = (DWORD_PTR)&numbers;
8828 es.dwError = 0;
8829 es.pfnCallback = test_EM_STREAMIN_esCallback;
8831 ok( result == lstrlenW( expect_numbers_txt ), "got %ld\n", result );
8832
8834 ok( result == lstrlenW( expect_numbers_txt ), "got %ld\n", result );
8835 ok( !lstrcmpW( buf, expect_numbers_txt ), "got %s\n", wine_dbgstr_w(buf) );
8836
8837 SendMessageW( edit, EM_SETSEL, 1, 1 );
8838 memset( &fmt, 0, sizeof(fmt) );
8839 fmt.cbSize = sizeof(fmt);
8840 fmt.dwMask = PFM_ALL2;
8841 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt );
8842 ok( fmt.wNumbering == PFN_ARABIC, "got %d\n", fmt.wNumbering );
8843 ok( fmt.wNumberingStart == 2, "got %d\n", fmt.wNumberingStart );
8844 ok( fmt.wNumberingStyle == PFNS_PERIOD, "got %04x\n", fmt.wNumberingStyle );
8845 ok( fmt.wNumberingTab == 1000, "got %d\n", fmt.wNumberingTab );
8846 ok( fmt.dxStartIndent == 560, "got %d\n", fmt.dxStartIndent );
8847 ok( fmt.dxOffset == -200, "got %d\n", fmt.dxOffset );
8848
8849 /* Second para should have identical fmt */
8850 SendMessageW( edit, EM_SETSEL, 10, 10 );
8851 memset( &fmt2, 0, sizeof(fmt2) );
8852 fmt2.cbSize = sizeof(fmt2);
8853 fmt2.dwMask = PFM_ALL2;
8854 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt2 );
8855 ok( !memcmp( &fmt, &fmt2, sizeof(fmt) ), "format mismatch\n" );
8856
8857 /* Check the eop heights - this determines the label height */
8858 SendMessageW( edit, EM_SETSEL, 12, 13 );
8859 cf.cbSize = sizeof(cf);
8860 cf.dwMask = CFM_SIZE;
8862 ok( cf.yHeight == 200, "got %d\n", cf.yHeight );
8863
8864 SendMessageW( edit, EM_SETSEL, 18, 19 );
8865 cf.cbSize = sizeof(cf);
8866 cf.dwMask = CFM_SIZE;
8868 ok( cf.yHeight == 200, "got %d\n", cf.yHeight );
8869
8870 DestroyWindow( edit );
8871}
8872
8873static void fill_reobject_struct(REOBJECT *reobj, LONG cp, LPOLEOBJECT poleobj,
8874 LPSTORAGE pstg, LPOLECLIENTSITE polesite, LONG sizel_cx,
8875 LONG sizel_cy, DWORD aspect, DWORD flags, DWORD user)
8876{
8877 reobj->cbStruct = sizeof(*reobj);
8878 reobj->clsid = CLSID_NULL;
8879 reobj->cp = cp;
8880 reobj->poleobj = poleobj;
8881 reobj->pstg = pstg;
8882 reobj->polesite = polesite;
8883 reobj->sizel.cx = sizel_cx;
8884 reobj->sizel.cy = sizel_cy;
8885 reobj->dvaspect = aspect;
8886 reobj->dwFlags = flags;
8887 reobj->dwUser = user;
8888}
8889
8890static void test_EM_SELECTIONTYPE(void)
8891{
8893 IRichEditOle *reole = NULL;
8894 static const char text1[] = "abcdefg\n";
8895 int result;
8896 REOBJECT reo1, reo2;
8897 IOleClientSite *clientsite;
8898 HRESULT hr;
8899
8900 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)text1);
8902
8903 SendMessageA(hwnd, EM_SETSEL, 1, 1);
8905 ok(result == SEL_EMPTY, "got wrong selection type: %x.\n", result);
8906
8907 SendMessageA(hwnd, EM_SETSEL, 1, 2);
8909 ok(result == SEL_TEXT, "got wrong selection type: %x.\n", result);
8910
8911 SendMessageA(hwnd, EM_SETSEL, 2, 5);
8913 ok(result == (SEL_TEXT | SEL_MULTICHAR), "got wrong selection type: %x.\n", result);
8914
8915 SendMessageA(hwnd, EM_SETSEL, 0, 1);
8916 hr = IRichEditOle_GetClientSite(reole, &clientsite);
8917 ok(hr == S_OK, "IRichEditOle_GetClientSite failed: 0x%08x\n", hr);
8918 fill_reobject_struct(&reo1, REO_CP_SELECTION, NULL, NULL, clientsite, 10, 10,
8919 DVASPECT_CONTENT, 0, 1);
8920 hr = IRichEditOle_InsertObject(reole, &reo1);
8921 ok(hr == S_OK, "IRichEditOle_InsertObject failed: 0x%08x\n", hr);
8922 IOleClientSite_Release(clientsite);
8923
8924 SendMessageA(hwnd, EM_SETSEL, 0, 1);
8926 ok(result == SEL_OBJECT, "got wrong selection type: %x.\n", result);
8927
8928 SendMessageA(hwnd, EM_SETSEL, 0, 2);
8930 ok(result == (SEL_TEXT | SEL_OBJECT), "got wrong selection type: %x.\n", result);
8931
8932 SendMessageA(hwnd, EM_SETSEL, 0, 3);
8934 ok(result == (SEL_TEXT | SEL_MULTICHAR | SEL_OBJECT), "got wrong selection type: %x.\n", result);
8935
8936 SendMessageA(hwnd, EM_SETSEL, 2, 3);
8937 hr = IRichEditOle_GetClientSite(reole, &clientsite);
8938 ok(hr == S_OK, "IRichEditOle_GetClientSite failed: 0x%08x\n", hr);
8939 fill_reobject_struct(&reo2, REO_CP_SELECTION, NULL, NULL, clientsite, 10, 10,
8940 DVASPECT_CONTENT, 0, 2);
8941 hr = IRichEditOle_InsertObject(reole, &reo2);
8942 ok(hr == S_OK, "IRichEditOle_InsertObject failed: 0x%08x\n", hr);
8943 IOleClientSite_Release(clientsite);
8944
8945 SendMessageA(hwnd, EM_SETSEL, 0, 2);
8947 ok(result == (SEL_OBJECT | SEL_TEXT), "got wrong selection type: %x.\n", result);
8948
8949 SendMessageA(hwnd, EM_SETSEL, 0, 3);
8951 ok(result == (SEL_OBJECT | SEL_MULTIOBJECT | SEL_TEXT), "got wrong selection type: %x.\n", result);
8952
8953 SendMessageA(hwnd, EM_SETSEL, 0, 4);
8955 ok(result == (SEL_TEXT| SEL_MULTICHAR | SEL_OBJECT | SEL_MULTIOBJECT), "got wrong selection type: %x.\n", result);
8956
8957 IRichEditOle_Release(reole);
8959}
8960
8961static void test_window_classes(void)
8962{
8963 static const struct
8964 {
8965 const char *class;
8966 BOOL success;
8967 } test[] =
8968 {
8969 { "RichEdit", FALSE },
8970 { "RichEdit20A", TRUE },
8971 { "RichEdit20W", TRUE },
8972 { "RichEdit50A", FALSE },
8973 { "RichEdit50W", FALSE }
8974 };
8975 int i;
8976 HWND hwnd;
8977
8978 for (i = 0; i < sizeof(test)/sizeof(test[0]); i++)
8979 {
8980 SetLastError(0xdeadbeef);
8981 hwnd = CreateWindowExA(0, test[i].class, NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL);
8982todo_wine_if(!strcmp(test[i].class, "RichEdit50A") || !strcmp(test[i].class, "RichEdit50W"))
8983 ok(!hwnd == !test[i].success, "CreateWindow(%s) should %s\n",
8984 test[i].class, test[i].success ? "succeed" : "fail");
8985 if (!hwnd)
8988 else
8990 }
8991}
8992
8993START_TEST( editor )
8994{
8995 BOOL ret;
8996 /* Must explicitly LoadLibrary(). The test has no references to functions in
8997 * RICHED20.DLL, so the linker doesn't actually link to it. */
8998 hmoduleRichEdit = LoadLibraryA("riched20.dll");
8999 ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError());
9001
9003 test_WM_CHAR();
9030 test_WM_PASTE();
9043 test_EN_LINK();
9054 test_zoom();
9058 test_enter();
9064 test_rtf();
9069
9070 /* Set the environment variable WINETEST_RICHED20 to keep windows
9071 * responsive and open for 30 seconds. This is useful for debugging.
9072 */
9073 if (getenv( "WINETEST_RICHED20" )) {
9074 keep_responsive(30);
9075 }
9076
9079 ok(ret, "error: %d\n", (int) GetLastError());
9080}
#define expect(EXPECTED, GOT)
Definition: SystemMenu.c:483
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
#define isalpha(c)
Definition: acclib.h:74
char * strstr(char *String1, char *String2)
Definition: utclib.c:653
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
#define isdigit(c)
Definition: acclib.h:68
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
char * strchr(const char *String, int ch)
Definition: utclib.c:501
static unsigned char bytes[4]
Definition: adnsresfilter.c:74
Arabic default style
Definition: afstyles.h:94
#define trace
Definition: atltest.h:70
#define ok(value,...)
Definition: atltest.h:57
#define skip(...)
Definition: atltest.h:64
#define START_TEST(x)
Definition: atltest.h:75
#define ok_(x1, x2)
Definition: atltest.h:61
static const char * wine_dbgstr_rect(const RECT *prc)
Definition: atltest.h:160
#define msg(x)
Definition: auth_time.c:54
void user(int argc, const char *argv[])
Definition: cmds.c:1350
#define ARRAY_SIZE(A)
Definition: main.h:33
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
#define FR_WHOLEWORD
Definition: commdlg.h:145
#define FR_MATCHCASE
Definition: commdlg.h:136
#define FR_DOWN
Definition: commdlg.h:127
static TAGID TAGID find
Definition: db.cpp:155
#define E_INVALIDARG
Definition: ddrawi.h:101
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define GetProcessHeap()
Definition: compat.h:736
#define CP_ACP
Definition: compat.h:109
#define SetLastError(x)
Definition: compat.h:752
#define HeapAlloc
Definition: compat.h:733
#define FreeLibrary(x)
Definition: compat.h:748
#define MAX_PATH
Definition: compat.h:34
#define HeapFree(x, y, z)
Definition: compat.h:735
#define CALLBACK
Definition: compat.h:35
#define WideCharToMultiByte
Definition: compat.h:111
#define MultiByteToWideChar
Definition: compat.h:110
#define lstrlenW
Definition: compat.h:750
HMODULE WINAPI DECLSPEC_HOTPATCH GetModuleHandleA(LPCSTR lpModuleName)
Definition: loader.c:812
HINSTANCE WINAPI DECLSPEC_HOTPATCH LoadLibraryA(LPCSTR lpLibFileName)
Definition: loader.c:111
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:455
const WCHAR * text
Definition: package.c:1799
HRESULT WINAPI OleFlushClipboard(void)
Definition: clipboard.c:2293
#define assert(x)
Definition: debug.h:53
#define pt(x, y)
Definition: drawing.c:79
#define RGB(r, g, b)
Definition: precomp.h:62
r parent
Definition: btrfs.c:3010
__kernel_time_t time_t
Definition: linux.h:252
static WCHAR * get_text(const ME_Run *run, int offset)
Definition: editor.h:41
POINTL point
Definition: edittest.c:50
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
unsigned short WORD
Definition: ntddk_ex.h:93
GLuint start
Definition: gl.h:1545
const GLdouble * v
Definition: gl.h:2040
GLuint GLuint end
Definition: gl.h:1545
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLint GLint GLsizei GLsizei height
Definition: gl.h:1546
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLsizeiptr size
Definition: glext.h:5919
GLdouble n
Definition: glext.h:7729
GLuint res
Definition: glext.h:9613
GLenum src
Definition: glext.h:6340
GLuint buffer
Definition: glext.h:5915
const GLubyte * c
Definition: glext.h:8905
GLfloat f
Definition: glext.h:7540
GLenum GLint * range
Definition: glext.h:7539
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLbitfield flags
Definition: glext.h:7161
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
const GLint * first
Definition: glext.h:5794
GLfloat GLfloat p
Definition: glext.h:8902
GLuint GLuint num
Definition: glext.h:9618
GLenum GLsizei len
Definition: glext.h:6722
GLuint64EXT * result
Definition: glext.h:11304
GLenum target
Definition: glext.h:7315
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble * u
Definition: glfuncs.h:240
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
static const WCHAR titleW[]
Definition: htmlelem.c:1067
#define es
Definition: i386-dis.c:440
const char cursor[]
Definition: icontest.c:13
_Check_return_ char *__cdecl getenv(_In_z_ const char *_VarName)
#define S_OK
Definition: intsafe.h:52
#define c
Definition: ke_i.h:80
#define wine_dbgstr_w
Definition: kernel32.h:34
INT WINAPI GetLocaleInfoA(LCID lcid, LCTYPE lctype, LPSTR buffer, INT len)
Definition: lang.c:1028
LANGID WINAPI GetUserDefaultLangID(void)
Definition: lang.c:744
LCID WINAPI GetSystemDefaultLCID(void)
Definition: lang.c:797
int WINAPI lstrcmpW(LPCWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:170
int WINAPI lstrcmpA(LPCSTR lpString1, LPCSTR lpString2)
Definition: lstring.c:18
int WINAPI lstrlenA(LPCSTR lpString)
Definition: lstring.c:145
POINT cp
Definition: magnifier.c:59
__u16 time
Definition: mkdosfs.c:8
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
char string[160]
Definition: util.h:11
static PVOID ptr
Definition: dispmode.c:27
#define sprintf(buf, format,...)
Definition: sprintf.c:55
HDC hdc
Definition: main.c:9
static const char textA[]
Definition: registrar.c:40
static HDC
Definition: imagelist.c:92
static BOOL rtl
Definition: propsheet.c:36
static const WCHAR textW[]
Definition: itemdlg.c:1559
static const WCHAR url[]
Definition: encode.c:1432
static const WCHAR desc[]
Definition: protectdata.c:36
BOOL expected
Definition: store.c:2063
static DWORD *static HFONT(WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *)
static HMODULE MODULEINFO DWORD cb
Definition: module.c:33
#define todo_wine_if(is_todo)
Definition: custom.c:76
#define todo_wine
Definition: custom.c:79
static char * dest
Definition: rtl.c:135
static unsigned int recursionLevel
Definition: editor.c:2864
static struct dialog_mode_messages dm_messages
Definition: editor.c:7886
static void test_EM_SELECTIONTYPE(void)
Definition: editor.c:8890
static void test_EM_FORMATRANGE(void)
Definition: editor.c:5594
static CHAR string2[MAX_PATH]
Definition: editor.c:42
static DWORD CALLBACK test_EM_STREAMIN_esCallback_UTF8Split(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
Definition: editor.c:5754
#define expect_empty(hwnd, wm_get_text)
static LRESULT WINAPI WM_NOTIFY_ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
Definition: editor.c:6637
static void test_SETPARAFORMAT(void)
Definition: editor.c:1506
static void simulate_typing_characters(HWND hwnd, const char *szChars)
Definition: editor.c:104
static LRESULT WINAPI EN_LINK_ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
Definition: editor.c:6748
static LRESULT CALLBACK dialog_mode_wnd_proc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
Definition: editor.c:7896
static void test_WM_PASTE(void)
Definition: editor.c:5429
static DWORD CALLBACK test_EM_STREAMIN_null_bytes(DWORD_PTR cookie, BYTE *buf, LONG size, LONG *written)
Definition: editor.c:5777
static void test_EM_EXSETSEL(void)
Definition: editor.c:4948
static void test_EM_GETSELTEXT(void)
Definition: editor.c:1801
static void check_CFE_LINK_rcvd(HWND hwnd, BOOL is_url, const char *url)
Definition: editor.c:1921
static void test_WM_GETTEXT(void)
Definition: editor.c:1650
#define CURSOR_CLIENT_Y
Definition: editor.c:6744
static void fill_reobject_struct(REOBJECT *reobj, LONG cp, LPOLEOBJECT poleobj, LPSTORAGE pstg, LPOLECLIENTSITE polesite, LONG sizel_cx, LONG sizel_cy, DWORD aspect, DWORD flags, DWORD user)
Definition: editor.c:8873
static void test_EM_StreamIn_Undo(void)
Definition: editor.c:6100
#define test_dm_messages(wmclose, wmgetdefid, wmnextdlgctl)
Definition: editor.c:7888
static void test_EM_SETOPTIONS(void)
Definition: editor.c:1840
static UINT message
Definition: editor.c:2867
static HWND new_richeditW(HWND parent)
Definition: editor.c:80
static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
Definition: editor.c:6544
static void test_EM_FINDWORDBREAK_W(void)
Definition: editor.c:8205
static void test_WM_SETFONT(void)
Definition: editor.c:4645
static void check_EM_SETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id)
Definition: editor.c:4987
#define WP_PARENT
Definition: editor.c:6745
LONG streamout_written
Definition: editor.c:3676
static HMODULE hmoduleRichEdit
Definition: editor.c:51
#define ID_RICHEDITTESTDBUTTON
Definition: editor.c:40
static void test_undo_coalescing(void)
Definition: editor.c:6944
#define TEST_SETTEXTW(a, b)
static void test_EM_GETTEXTLENGTHEX(void)
Definition: editor.c:6388
static void format_test_result(char *target, const char *src)
Definition: editor.c:8282
static HWND new_richedit(HWND parent)
Definition: editor.c:72
static void test_EM_STREAMOUT_FONTTBL(void)
Definition: editor.c:3923
static void test_EM_GETLINE(void)
Definition: editor.c:390
#define DISABLE_WS_VSCROLL(hwnd)
static void test_WM_GETTEXTLENGTH(void)
Definition: editor.c:8664
#define expect_textW(hwnd, wm_get_text, txt)
static void test_EM_SCROLL(void)
Definition: editor.c:2730
static HWND new_windowW(LPCWSTR lpClassName, DWORD dwStyle, HWND parent)
Definition: editor.c:63
static unsigned int WM_SIZE_recursionLevel
Definition: editor.c:2865
static DWORD CALLBACK test_EM_STREAMIN_esCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
Definition: editor.c:5736
static int nCallbackCount
Definition: editor.c:5710
static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *find, int num_tests, BOOL unicode)
Definition: editor.c:321
static void move_cursor(HWND hwnd, LONG charindex)
Definition: editor.c:526
static WCHAR * atowstr(const char *str)
Definition: editor.c:229
static void test_EM_GETLIMITTEXT(void)
Definition: editor.c:4630
static const struct exsetsel_s exsetsel_tests[]
Definition: editor.c:4901
#define expect_textA(hwnd, wm_get_text, txt)
static void test_EN_LINK(void)
Definition: editor.c:6819
static void test_unicode_conversions(void)
Definition: editor.c:6179
static void test_EM_STREAMIN(void)
Definition: editor.c:5826
static void check_EM_EXSETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id)
Definition: editor.c:4930
static BOOL check_CFE_LINK_selection(HWND hwnd, int sel_start, int sel_end)
Definition: editor.c:1912
static BOOL is_em_settextex_supported(HWND hwnd)
Definition: editor.c:6173
static void test_EM_STREAMOUT(void)
Definition: editor.c:3821
static BOOL hold_key(int vk)
Definition: editor.c:117
static void test_EM_AUTOURLDETECT(void)
Definition: editor.c:1940
static void test_EM_REPLACESEL(int redraw)
Definition: editor.c:5045
static LRESULT send_ctrl_key(HWND hwnd, UINT key)
Definition: editor.c:5420
static int received_WM_NOTIFY
Definition: editor.c:6632
#define ok_w3(format, szString1, szString2, szString3)
Definition: editor.c:44
static HWND new_richedit_with_style(HWND parent, DWORD style)
Definition: editor.c:76
static DWORD CALLBACK test_esCallback_written_1(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
Definition: editor.c:3792
static void test_WM_CREATE(void)
Definition: editor.c:8408
static void test_WM_SETTEXT(void)
Definition: editor.c:3693
static void test_EM_SETCHARFORMAT(void)
Definition: editor.c:750
static int queriedEventMask
Definition: editor.c:6540
static void test_background(void)
Definition: editor.c:8757
static BOOL is_lang_japanese
Definition: editor.c:52
static void test_dialogmode(void)
Definition: editor.c:7914
static BOOL filter_on_WM_NOTIFY
Definition: editor.c:6634
static struct find_s find_tests2[]
Definition: editor.c:166
static void test_EM_SETTEXTMODE(void)
Definition: editor.c:1364
static void test_format_rect(void)
Definition: editor.c:7395
static HWND hwndRichedit_WM_NOTIFY
Definition: editor.c:6635
static LRESULT WINAPI RicheditStupidOverrideProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
Definition: editor.c:2869
static void test_eventMask(void)
Definition: editor.c:6554
static void test_EM_LINELENGTH(void)
Definition: editor.c:462
static struct find_s find_tests[]
Definition: editor.c:157
static void test_scrollbar_visibility(void)
Definition: editor.c:2896
static CHAR string1[MAX_PATH]
Definition: editor.c:42
static void keep_responsive(time_t delay_time)
Definition: editor.c:86
static void test_EM_CHARFROMPOS(void)
Definition: editor.c:7187
#define CURSOR_CLIENT_X
Definition: editor.c:6743
static HWND eventMaskEditHwnd
Definition: editor.c:6539
static BOOL release_key(int vk)
Definition: editor.c:131
static void test_EM_SETFONTSIZE(void)
Definition: editor.c:8527
static DWORD CALLBACK test_EM_GETMODIFY_esCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
Definition: editor.c:4707
static void test_EM_SETSEL(void)
Definition: editor.c:5002
static void line_scroll(HWND hwnd, int amount)
Definition: editor.c:534
static int modify_at_WM_NOTIFY
Definition: editor.c:6633
static void test_rtf(void)
Definition: editor.c:8695
#define MAX_BUF_LEN
static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id, BOOL unicode)
Definition: editor.c:239
static void test_WM_GETDLGCODE(void)
Definition: editor.c:7558
static void test_EM_SCROLLCARET(void)
Definition: editor.c:539
static ENLINK enlink
Definition: editor.c:6742
static int get_scroll_pos_y(HWND hwnd)
Definition: editor.c:518
static void test_EM_SETUNDOLIMIT(void)
Definition: editor.c:3586
static CHAR string3[MAX_PATH]
Definition: editor.c:42
static void test_EM_STREAMOUT_empty_para(void)
Definition: editor.c:3976
#define WP_CHILD
Definition: editor.c:6746
static void test_EM_LIMITTEXT(void)
Definition: editor.c:4459
static void test_autoscroll(void)
Definition: editor.c:7336
static void check_EM_FINDTEXTEX(HWND hwnd, const char *name, struct find_s *f, int id, BOOL unicode)
Definition: editor.c:275
static void test_word_wrap(void)
Definition: editor.c:7240
static void test_enter(void)
Definition: editor.c:8298
#define TEST_SETTEXT(a, b)
static void test_EM_FINDWORDBREAK_A(void)
Definition: editor.c:8249
static LONG CALLBACK customWordBreakProc(WCHAR *text, int pos, int bytes, int code)
Definition: editor.c:7061
static void test_reset_default_para_fmt(void)
Definition: editor.c:8449
static void test_window_classes(void)
Definition: editor.c:8961
static DWORD CALLBACK test_WM_SETTEXT_esCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
Definition: editor.c:3678
static LONG twips2points(LONG value)
Definition: editor.c:8500
#define ENABLE_WS_VSCROLL(hwnd)
static int count_pars(const char *buf)
Definition: editor.c:3808
#define set_textA(hwnd, wm_set_text, txt)
static void test_EM_POSFROMCHAR(void)
Definition: editor.c:597
static DWORD CALLBACK EditStreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
Definition: editor.c:5712
static void test_zoom(void)
Definition: editor.c:7739
static int watchForEventMask
Definition: editor.c:6541
static HWND new_static_wnd(HWND parent)
Definition: editor.c:1936
static DWORD CALLBACK test_EM_STREAMIN_esCallback2(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
Definition: editor.c:5807
static HWND new_window(LPCSTR lpClassName, DWORD dwStyle, HWND parent)
Definition: editor.c:54
static void test_ES_PASSWORD(void)
Definition: editor.c:3650
static const struct getline_s gl[]
static void test_EM_EXLIMITTEXT(void)
Definition: editor.c:4499
static void _test_font_size(unsigned line, HWND hwnd, LONG size, LONG expected_size, LRESULT expected_res, BOOL expected_undo)
Definition: editor.c:8507
static void link_notify_test(const char *desc, int i, HWND hwnd, HWND parent, UINT msg, WPARAM wParam, LPARAM lParam, BOOL notifies)
Definition: editor.c:6757
static BOOL bailedOutOfRecursion
Definition: editor.c:2866
static void test_WM_CHAR(void)
Definition: editor.c:6337
static void test_eop_char_fmt(void)
Definition: editor.c:8769
static void test_word_movement(void)
Definition: editor.c:7098
#define TEST_EM_SETFONTSIZE(hwnd, size, expected_size, expected_res, expected_undo)
Definition: editor.c:8505
static const char haystack[]
Definition: editor.c:145
static void test_para_numbering(void)
Definition: editor.c:8805
#define set_textW(hwnd, wm_set_text, txt)
static void test_EM_GETTEXTRANGE(void)
Definition: editor.c:1717
static void test_alignment_style(void)
Definition: editor.c:8594
static void test_EM_SETTEXTEX(void)
Definition: editor.c:3996
static void test_WM_NOTIFY(void)
Definition: editor.c:6648
static void test_EM_SETREADONLY(void)
Definition: editor.c:8481
static void test_TM_PLAINTEXT(void)
Definition: editor.c:1540
static void test_EM_GETMODIFY(void)
Definition: editor.c:4727
static void test_EM_FINDTEXT(void)
Definition: editor.c:779
static const CLSID *static CLSID *static const GUID VARIANT VARIANT *static IServiceProvider DWORD *static HMENU
Definition: ordinal.c:63
WORD vk
Definition: input.c:77
#define min(a, b)
Definition: monoChain.cc:55
unsigned int UINT
Definition: ndis.h:50
#define LOCALE_USER_DEFAULT
interface IStorage * LPSTORAGE
Definition: objfwd.h:30
#define LRESULT
Definition: ole.h:14
#define LOWORD(l)
Definition: pedump.c:82
#define WS_CHILD
Definition: pedump.c:617
#define WS_OVERLAPPEDWINDOW
Definition: pedump.c:637
#define ES_READONLY
Definition: pedump.c:675
#define ES_AUTOVSCROLL
Definition: pedump.c:671
#define ES_WANTRETURN
Definition: pedump.c:676
#define ES_NOHIDESEL
Definition: pedump.c:673
#define WS_POPUP
Definition: pedump.c:616
#define WS_VSCROLL
Definition: pedump.c:627
#define ES_AUTOHSCROLL
Definition: pedump.c:672
#define WS_VISIBLE
Definition: pedump.c:620
long LONG
Definition: pedump.c:60
#define ES_LEFT
Definition: pedump.c:664
#define WS_HSCROLL
Definition: pedump.c:628
#define ES_CENTER
Definition: pedump.c:665
#define ES_RIGHT
Definition: pedump.c:666
#define BS_PUSHBUTTON
Definition: pedump.c:651
#define ES_MULTILINE
Definition: pedump.c:667
static char title[]
Definition: ps.c:92
#define WM_MOUSEHOVER
Definition: commctrl.h:4974
#define CLSID_NULL
Definition: guiddef.h:99
void redraw(int x, int y, int cx, int cy)
Definition: qtewin.cpp:1248
#define WB_MOVEWORDRIGHT
Definition: richedit.h:1002
#define TM_RICHTEXT
Definition: richedit.h:1029
#define GT_DEFAULT
Definition: richedit.h:1036
#define SEL_EMPTY
Definition: richedit.h:822
#define ENM_CHANGE
Definition: richedit.h:468
#define EM_CANREDO
Definition: richedit.h:118
#define EM_SCROLLCARET
Definition: richedit.h:81
#define SEL_OBJECT
Definition: richedit.h:824
#define CFU_UNDERLINEDOUBLE
Definition: richedit.h:430
#define PFA_RIGHT
Definition: richedit.h:922
#define CFM_EFFECTS
Definition: richedit.h:364
#define SFF_SELECTION
Definition: richedit.h:979
#define PFA_CENTER
Definition: richedit.h:923
#define PFE_RTLPARA
Definition: richedit.h:932
#define EM_GETEVENTMASK
Definition: richedit.h:92
#define EM_REDO
Definition: richedit.h:117
#define EM_GETSELTEXT
Definition: richedit.h:95
#define PFN_ARABIC
Definition: richedit.h:906
#define ST_DEFAULT
Definition: richedit.h:1070
struct _charformat CHARFORMATA
#define EM_AUTOURLDETECT
Definition: richedit.h:125
#define CFE_STRIKEOUT
Definition: richedit.h:409
#define SCF_WORD
Definition: richedit.h:236
#define CFE_BOLD
Definition: richedit.h:406
#define EM_FORMATRANGE
Definition: richedit.h:90
#define PFA_LEFT
Definition: richedit.h:921
#define CFE_AUTOCOLOR
Definition: richedit.h:414
#define EM_SETZOOM
Definition: richedit.h:170
#define ENM_LINK
Definition: richedit.h:485
#define EM_STREAMIN
Definition: richedit.h:106
#define ST_SELECTION
Definition: richedit.h:1072
#define EM_SETEVENTMASK
Definition: richedit.h:102
#define EM_SETOPTIONS
Definition: richedit.h:110
#define GTL_DEFAULT
Definition: richedit.h:1054
#define WB_RIGHTBREAK
Definition: richedit.h:1006
static const WCHAR RICHEDIT_CLASS20W[]
Definition: richedit.h:50
#define CFM_WEIGHT
Definition: richedit.h:354
#define ST_KEEPUNDO
Definition: richedit.h:1071
#define SF_RTF
Definition: richedit.h:721
#define CFE_ITALIC
Definition: richedit.h:407
#define SEL_MULTICHAR
Definition: richedit.h:825
#define SCF_SELECTION
Definition: richedit.h:235
#define EM_SETBKGNDCOLOR
Definition: richedit.h:100
#define EM_SETTEXTEX
Definition: richedit.h:131
#define EM_POSFROMCHAR
Definition: richedit.h:77
#define SCF_DEFAULT
Definition: richedit.h:234
#define EM_GETCHARFORMAT
Definition: richedit.h:91
#define CFE_SUPERSCRIPT
Definition: richedit.h:413
#define GTL_NUMCHARS
Definition: richedit.h:1058
struct _charformatw CHARFORMATW
#define ENM_UPDATE
Definition: richedit.h:469
#define SEL_TEXT
Definition: richedit.h:823
#define CFM_SPACING
Definition: richedit.h:353
#define EM_SETCHARFORMAT
Definition: richedit.h:101
#define PFM_ALL2
Definition: richedit.h:892
#define EM_SETFONTSIZE
Definition: richedit.h:168
#define ENM_SELCHANGE
Definition: richedit.h:478
#define EM_GETPARAFORMAT
Definition: richedit.h:94
#define ENM_KEYEVENTS
Definition: richedit.h:475
#define EM_GETOPTIONS
Definition: richedit.h:111
#define RICHEDIT_CLASS20A
Definition: richedit.h:43
#define CFE_UNDERLINE
Definition: richedit.h:408
#define ECO_AUTOHSCROLL
Definition: richedit.h:458
#define EM_CHARFROMPOS
Definition: richedit.h:78
#define CFE_SUBSCRIPT
Definition: richedit.h:412
#define ES_DISABLENOSCROLL
Definition: richedit.h:224
#define CFM_ITALIC
Definition: richedit.h:333
#define EM_GETTEXTRANGE
Definition: richedit.h:108
#define CFU_UNDERLINE
Definition: richedit.h:428
struct _paraformat2 PARAFORMAT2
#define CFE_PROTECTED
Definition: richedit.h:410
#define CFE_LINK
Definition: richedit.h:411
#define CFM_LINK
Definition: richedit.h:337
#define EM_SETTEXTMODE
Definition: richedit.h:123
#define CFM_SIZE
Definition: richedit.h:362
#define EM_FINDTEXTW
Definition: richedit.h:147
#define GT_RAWTEXT
Definition: richedit.h:1039
#define EM_GETZOOM
Definition: richedit.h:169
#define EM_EXSETSEL
Definition: richedit.h:88
#define EM_GETSCROLLPOS
Definition: richedit.h:165
#define GTL_PRECISE
Definition: richedit.h:1056
#define CFM_ALL2
Definition: richedit.h:393
struct _charformat2a CHARFORMAT2A
#define CFM_EFFECTS2
Definition: richedit.h:372
#define EM_EXLIMITTEXT
Definition: richedit.h:86
#define PFM_ALIGNMENT
Definition: richedit.h:841
#define WCH_EMBEDDING
Definition: richedit.h:1024
#define SF_TEXT
Definition: richedit.h:720
#define CFE_AUTOBACKCOLOR
Definition: richedit.h:425
#define EM_SELECTIONTYPE
Definition: richedit.h:99
#define EM_FINDTEXT
Definition: richedit.h:89
#define CFM_ALL
Definition: richedit.h:387
#define TM_PLAINTEXT
Definition: richedit.h:1028
#define EM_STOPGROUPTYPING
Definition: richedit.h:121
#define ES_SAVESEL
Definition: richedit.h:226
#define ENM_NONE
Definition: richedit.h:467
#define ECO_READONLY
Definition: richedit.h:460
#define ECOOP_OR
Definition: richedit.h:451
#define EM_GETTEXTLENGTHEX
Definition: richedit.h:129
#define ECOOP_SET
Definition: richedit.h:450
#define SCF_ALL
Definition: richedit.h:237
#define SF_UNICODE
Definition: richedit.h:724
#define EM_SETTARGETDEVICE
Definition: richedit.h:105
#define SEL_MULTIOBJECT
Definition: richedit.h:826
#define CFM_BOLD
Definition: richedit.h:332
#define EM_GETLIMITTEXT
Definition: richedit.h:74
#define CFM_UNDERLINETYPE
Definition: richedit.h:355
#define EN_LINK
Definition: richedit.h:202
#define ES_SELECTIONBAR
Definition: richedit.h:230
#define GT_USECRLF
Definition: richedit.h:1037
#define CFU_UNDERLINENONE
Definition: richedit.h:427
#define ES_VERTICAL
Definition: richedit.h:229
#define CFM_FACE
Definition: richedit.h:360
#define EM_GETOLEINTERFACE
Definition: richedit.h:93
#define ECO_AUTOVSCROLL
Definition: richedit.h:457
#define WM_NOTIFY
Definition: richedit.h:61
#define PFM_RTLPARA
Definition: richedit.h:856
#define EM_GETTEXTEX
Definition: richedit.h:128
#define GTL_NUMBYTES
Definition: richedit.h:1059
#define EM_SETPARAFORMAT
Definition: richedit.h:104
#define WB_MOVEWORDLEFT
Definition: richedit.h:1000
#define CFM_UNDERLINE
Definition: richedit.h:334
#define EM_EXGETSEL
Definition: richedit.h:85
#define WB_LEFTBREAK
Definition: richedit.h:1004
#define EM_FINDTEXTEX
Definition: richedit.h:112
#define PFNS_PERIOD
Definition: richedit.h:915
#define EM_SETUNDOLIMIT
Definition: richedit.h:116
#define GTL_USECRLF
Definition: richedit.h:1055
#define EM_FINDWORDBREAK
Definition: richedit.h:109
#define ECO_SELECTIONBAR
Definition: richedit.h:463
#define ECOOP_AND
Definition: richedit.h:452
#define CFM_SUPERSCRIPT
Definition: richedit.h:349
#define EM_STREAMOUT
Definition: richedit.h:107
#define test
Definition: rosglue.h:37
const WCHAR * str
#define LANG_ENGLISH
Definition: nls.h:52
#define CP_UTF8
Definition: nls.h:20
#define LANG_JAPANESE
Definition: nls.h:76
#define PRIMARYLANGID(l)
Definition: nls.h:16
#define ros_skip_flaky
Definition: test.h:177
#define memset(x, y, z)
Definition: compat.h:39
HRESULT hr
Definition: shlfolder.c:183
CHAR lfFaceName[LF_FACESIZE]
Definition: dimm.idl:55
char * buffer
Definition: editor.c:5803
LONG y
Definition: windef.h:330
LONG x
Definition: windef.h:329
LONG cx
Definition: kdterminal.h:27
LONG cy
Definition: kdterminal.h:28
HBRUSH hbrBackground
Definition: winuser.h:3170
HICON hIcon
Definition: winuser.h:3168
HINSTANCE hInstance
Definition: winuser.h:3167
HCURSOR hCursor
Definition: winuser.h:3169
int cbWndExtra
Definition: winuser.h:3166
UINT style
Definition: winuser.h:3163
LPCSTR lpszMenuName
Definition: winuser.h:3171
LPCSTR lpszClassName
Definition: winuser.h:3172
WNDPROC lpfnWndProc
Definition: winuser.h:3164
int cbClsExtra
Definition: winuser.h:3165
DWORD dwMask
Definition: richedit.h:283
BYTE bRevAuthor
Definition: richedit.h:300
LONG yHeight
Definition: richedit.h:285
BYTE bUnderlineType
Definition: richedit.h:298
char szFaceName[LF_FACESIZE]
Definition: richedit.h:290
SHORT sSpacing
Definition: richedit.h:292
LONG yOffset
Definition: richedit.h:286
SHORT sStyle
Definition: richedit.h:296
WORD wKerning
Definition: richedit.h:297
DWORD dwEffects
Definition: richedit.h:284
BYTE bAnimation
Definition: richedit.h:299
WORD wWeight
Definition: richedit.h:291
DWORD dwMask
Definition: richedit.h:306
WORD wWeight
Definition: richedit.h:314
SHORT sSpacing
Definition: richedit.h:315
UINT cbSize
Definition: richedit.h:255
DWORD dwEffects
Definition: richedit.h:257
DWORD dwMask
Definition: richedit.h:256
UINT cbSize
Definition: richedit.h:268
DWORD dwMask
Definition: richedit.h:269
DWORD dwEffects
Definition: richedit.h:270
LONG cpMax
Definition: richedit.h:501
LONG cpMin
Definition: richedit.h:500
CHARRANGE chrg
Definition: richedit.h:581
LPCSTR lpstrText
Definition: richedit.h:582
CHARRANGE chrg
Definition: richedit.h:586
LPCWSTR lpstrText
Definition: richedit.h:587
LPCSTR lpstrText
Definition: richedit.h:594
CHARRANGE chrg
Definition: richedit.h:593
CHARRANGE chrgText
Definition: richedit.h:595
CHARRANGE chrg
Definition: richedit.h:599
CHARRANGE chrgText
Definition: richedit.h:601
LPCWSTR lpstrText
Definition: richedit.h:600
HDC hdcTarget
Definition: richedit.h:608
CHARRANGE chrg
Definition: richedit.h:611
RECT rcPage
Definition: richedit.h:610
DWORD cb
Definition: richedit.h:706
DWORD flags
Definition: richedit.h:707
LPCSTR lpDefaultChar
Definition: richedit.h:709
LPBOOL lpUsedDefChar
Definition: richedit.h:710
UINT codepage
Definition: richedit.h:708
WORD wAlignment
Definition: richedit.h:673
DWORD dwMask
Definition: richedit.h:667
UINT cbSize
Definition: richedit.h:666
DWORD dwUser
Definition: richole.idl:67
CLSID clsid
Definition: richole.idl:60
DWORD dwFlags
Definition: richole.idl:66
LPSTORAGE pstg
Definition: richole.idl:62
LPOLEOBJECT poleobj
Definition: richole.idl:61
DWORD dvaspect
Definition: richole.idl:65
LPOLECLIENTSITE polesite
Definition: richole.idl:63
DWORD cbStruct
Definition: richole.idl:58
LONG cp
Definition: richole.idl:59
SIZEL sizel
Definition: richole.idl:64
UINT codepage
Definition: richedit.h:1066
DWORD flags
Definition: richedit.h:1065
CHARRANGE chrg
Definition: richedit.h:508
LPSTR lpstrText
Definition: richedit.h:509
Definition: ftp_var.h:139
Definition: inflate.c:139
Definition: cookie.c:34
Definition: query.h:87
LRESULT expected_retval
Definition: editor.c:4895
LONG max
Definition: editor.c:4894
BOOL todo
Definition: editor.c:4898
int expected_getsel_end
Definition: editor.c:4897
LONG min
Definition: editor.c:4893
int expected_getsel_start
Definition: editor.c:4896
Definition: editor.c:148
int flags
Definition: editor.c:152
int start
Definition: editor.c:149
int end
Definition: editor.c:150
int expected_loc
Definition: editor.c:153
const char * needle
Definition: editor.c:151
Definition: dsound.c:943
size_t buffer_len
Definition: editor.c:376
int line
Definition: editor.c:375
const char * text
Definition: editor.c:377
Definition: copy.c:22
Definition: parser.c:49
Definition: tftpd.h:60
Definition: name.c:39
DWORD lsUsb[4]
Definition: wingdi.h:2611
UINT_PTR idFrom
Definition: winuser.h:3158
HWND hwndFrom
Definition: winuser.h:3157
long y
Definition: polytest.cpp:48
long x
Definition: polytest.cpp:48
LONG right
Definition: windef.h:308
LONG bottom
Definition: windef.h:309
LONG top
Definition: windef.h:307
LONG left
Definition: windef.h:306
#define max(a, b)
Definition: svc.c:63
VOID WINAPI DECLSPEC_HOTPATCH Sleep(IN DWORD dwMilliseconds)
Definition: synch.c:790
void test_string()
Definition: test_string.cpp:38
#define WHEEL_DELTA
Definition: treelist.c:99
#define WM_MOUSEWHEEL
Definition: treelist.c:96
#define DWORD_PTR
Definition: treelist.c:76
eMaj lines
Definition: tritemp.h:206
TW_UINT32 TW_UINT16 TW_UINT16 MSG
Definition: twain.h:1829
uint32_t DWORD_PTR
Definition: typedefs.h:65
unsigned char * LPBYTE
Definition: typedefs.h:53
#define MAKELONG(a, b)
Definition: typedefs.h:249
#define HIWORD(l)
Definition: typedefs.h:247
Definition: pdh_main.c:94
int ret
int WINAPI GetWindowTextA(HWND hWnd, LPSTR lpString, int nMaxCount)
Definition: window.c:1330
#define success(from, fromstr, to, tostr)
#define ZeroMemory
Definition: winbase.h:1712
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
LONG_PTR LPARAM
Definition: windef.h:208
LONG_PTR LRESULT
Definition: windef.h:209
UINT_PTR WPARAM
Definition: windef.h:207
#define WINAPI
Definition: msvc.h:6
#define E_UNEXPECTED
Definition: winerror.h:2456
#define ERROR_CANNOT_FIND_WND_CLASS
Definition: winerror.h:888
#define DEFAULT_PITCH
Definition: wingdi.h:443
#define FW_LIGHT
Definition: wingdi.h:372
HGDIOBJ WINAPI GetStockObject(_In_ int)
#define FW_DONTCARE
Definition: wingdi.h:368
int WINAPI GetDeviceCaps(_In_opt_ HDC, _In_ int)
int WINAPI GetObjectA(_In_ HANDLE h, _In_ int c, _Out_writes_bytes_opt_(c) LPVOID pv)
#define DEFAULT_QUALITY
Definition: wingdi.h:436
#define FF_DONTCARE
Definition: wingdi.h:448
#define LOGPIXELSY
Definition: wingdi.h:719
#define WHITE_BRUSH
Definition: wingdi.h:902
#define OUT_DEFAULT_PRECIS
Definition: wingdi.h:415
#define ANSI_CHARSET
Definition: wingdi.h:383
#define OUT_TT_PRECIS
Definition: wingdi.h:419
#define CLIP_DEFAULT_PRECIS
Definition: wingdi.h:426
#define LOGPIXELSX
Definition: wingdi.h:718
HFONT WINAPI CreateFontA(_In_ int, _In_ int, _In_ int, _In_ int, _In_ int, _In_ DWORD, _In_ DWORD, _In_ DWORD, _In_ DWORD, _In_ DWORD, _In_ DWORD, _In_ DWORD, _In_ DWORD, _In_opt_ LPCSTR)
BOOL WINAPI GetTextExtentPoint32A(_In_ HDC hdc, _In_reads_(c) LPCSTR lpString, _In_ int c, _Out_ LPSIZE psizl)
#define LOCALE_FONTSIGNATURE
Definition: winnls.h:125
#define EM_SETREADONLY
Definition: winuser.h:2015
int WINAPI ReleaseDC(_In_opt_ HWND, _In_ HDC)
LRESULT WINAPI DispatchMessageA(_In_ const MSG *)
#define MAKEWPARAM(l, h)
Definition: winuser.h:4009
#define SetWindowLongPtrA
Definition: winuser.h:5345
#define WM_GETTEXTLENGTH
Definition: winuser.h:1619
#define EM_GETRECT
Definition: winuser.h:1996
#define WM_CLOSE
Definition: winuser.h:1621
#define EM_LIMITTEXT
Definition: winuser.h:2000
#define VK_TAB
Definition: winuser.h:2199
UINT WINAPI MapVirtualKeyA(_In_ UINT, _In_ UINT)
#define SB_LINEUP
Definition: winuser.h:564
#define WM_HSCROLL
Definition: winuser.h:1743
BOOL WINAPI SetKeyboardState(_In_reads_(256) LPBYTE)
#define WM_PASTE
Definition: winuser.h:1863
BOOL WINAPI TranslateMessage(_In_ const MSG *)
#define MAKELPARAM(l, h)
Definition: winuser.h:4008
#define WM_KEYUP
Definition: winuser.h:1716
HWND WINAPI CreateWindowExA(_In_ DWORD dwExStyle, _In_opt_ LPCSTR lpClassName, _In_opt_ LPCSTR lpWindowName, _In_ DWORD dwStyle, _In_ int X, _In_ int Y, _In_ int nWidth, _In_ int nHeight, _In_opt_ HWND hWndParent, _In_opt_ HMENU hMenu, _In_opt_ HINSTANCE hInstance, _In_opt_ LPVOID lpParam)
#define EM_GETPASSWORDCHAR
Definition: winuser.h:1995
LONG WINAPI GetWindowLongA(_In_ HWND, _In_ int)
LRESULT WINAPI DefWindowProcA(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define WM_VSCROLL
Definition: winuser.h:1744
#define CreateWindowA(a, b, c, d, e, f, g, h, i, j, k)
Definition: winuser.h:4315
LONG WINAPI SetWindowLongA(_In_ HWND, _In_ int, _In_ LONG)
#define SIF_RANGE
Definition: winuser.h:1235
#define DLGC_WANTCHARS
Definition: winuser.h:2618
#define DLGC_WANTTAB
Definition: winuser.h:2611
#define EM_GETSEL
Definition: winuser.h:1997
#define EM_SETPASSWORDCHAR
Definition: winuser.h:2014
#define EN_UPDATE
Definition: winuser.h:2028
#define EM_GETMODIFY
Definition: winuser.h:1994
#define WB_ISDELIMITER
Definition: winuser.h:549
HWND WINAPI SetParent(_In_ HWND, _In_opt_ HWND)
#define WM_SIZE
Definition: winuser.h:1611
#define SB_VERT
Definition: winuser.h:553
#define EM_EMPTYUNDOBUFFER
Definition: winuser.h:1985
LONG WINAPI SetWindowLongW(_In_ HWND, _In_ int, _In_ LONG)
LONG WINAPI GetWindowLongW(_In_ HWND, _In_ int)
#define SB_BOTTOM
Definition: winuser.h:577
#define WM_LBUTTONDBLCLK
Definition: winuser.h:1778
BOOL WINAPI ValidateRect(_In_opt_ HWND, _In_opt_ LPCRECT)
#define WM_COMMAND
Definition: winuser.h:1740
#define EM_REPLACESEL
Definition: winuser.h:2006
#define IDC_ARROW
Definition: winuser.h:687
#define VK_CONTROL
Definition: winuser.h:2203
BOOL WINAPI GetCursorPos(_Out_ LPPOINT)
Definition: cursoricon.c:2670
#define EM_SETRECT
Definition: winuser.h:2016
#define WM_RBUTTONUP
Definition: winuser.h:1780
#define DC_HASDEFID
Definition: winuser.h:2609
#define WM_RBUTTONDBLCLK
Definition: winuser.h:1781
LRESULT WINAPI SendMessageA(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define WM_SETFOCUS
Definition: winuser.h:1613
#define SIF_PAGE
Definition: winuser.h:1233
#define WM_MOUSEMOVE
Definition: winuser.h:1775
#define WM_GETTEXT
Definition: winuser.h:1618
_Check_return_ BOOL WINAPI GetKeyboardState(_Out_writes_(256) PBYTE lpKeyState)
#define WM_CUT
Definition: winuser.h:1861
#define SB_LINERIGHT
Definition: winuser.h:567
#define WM_LBUTTONDOWN
Definition: winuser.h:1776
BOOL WINAPI SetCursorPos(_In_ int, _In_ int)
Definition: cursoricon.c:2662
#define EM_LINESCROLL
Definition: winuser.h:2004
#define EM_GETFIRSTVISIBLELINE
Definition: winuser.h:1988
BOOL WINAPI ClientToScreen(_In_ HWND, _Inout_ LPPOINT)
#define WM_NEXTDLGCTL
Definition: winuser.h:1643
#define WM_UNDO
Definition: winuser.h:1865
#define WM_RBUTTONDOWN
Definition: winuser.h:1779
#define WM_SETTEXT
Definition: winuser.h:1617
#define EM_CANUNDO
Definition: winuser.h:1983
#define EM_LINELENGTH
Definition: winuser.h:2003
BOOL WINAPI IsWindowUnicode(_In_ HWND)
BOOL WINAPI GetClientRect(_In_ HWND, _Out_ LPRECT)
ATOM WINAPI RegisterClassA(_In_ CONST WNDCLASSA *)
#define VK_RETURN
Definition: winuser.h:2201
#define EM_GETLINE
Definition: winuser.h:1991
#define SB_LINELEFT
Definition: winuser.h:566
#define MK_CONTROL
Definition: winuser.h:2370
#define WB_LEFT
Definition: winuser.h:550
#define GWLP_HWNDPARENT
Definition: winuser.h:858
#define WM_SETFONT
Definition: winuser.h:1650
#define EM_UNDO
Definition: winuser.h:2021
#define DLGC_WANTARROWS
Definition: winuser.h:2610
#define EM_SCROLL
Definition: winuser.h:2007
#define PM_REMOVE
Definition: winuser.h:1196
#define SB_PAGEDOWN
Definition: winuser.h:569
#define EM_SETWORDBREAKPROC
Definition: winuser.h:2020
#define SIF_ALL
Definition: winuser.h:1232
#define VK_BACK
Definition: winuser.h:2198
HDC WINAPI GetDC(_In_opt_ HWND)
#define SB_LINEDOWN
Definition: winuser.h:565
#define EM_SETSEL
Definition: winuser.h:2018
#define CreateWindowW(a, b, c, d, e, f, g, h, i, j, k)
Definition: winuser.h:4316
BOOL WINAPI GetClassInfoA(_In_opt_ HINSTANCE, _In_ LPCSTR, _Out_ LPWNDCLASSA)
#define WM_LBUTTONUP
Definition: winuser.h:1777
#define WB_RIGHT
Definition: winuser.h:551
#define WM_CHAR
Definition: winuser.h:1717
#define CW_USEDEFAULT
Definition: winuser.h:225
#define VK_LEFT
Definition: winuser.h:2224
#define VK_RIGHT
Definition: winuser.h:2226
#define WM_COPY
Definition: winuser.h:1862
#define WM_SETCURSOR
Definition: winuser.h:1636
BOOL WINAPI PeekMessageA(_Out_ LPMSG, _In_opt_ HWND, _In_ UINT, _In_ UINT, _In_ UINT)
#define DLGC_WANTMESSAGE
Definition: winuser.h:2613
#define VK_DELETE
Definition: winuser.h:2233
#define MAPVK_VK_TO_VSC
Definition: winuser.h:2355
#define WS_EX_CLIENTEDGE
Definition: winuser.h:384
#define WM_CLEAR
Definition: winuser.h:1864
BOOL WINAPI ShowScrollBar(_In_ HWND, _In_ int, _In_ BOOL)
#define WM_KEYDOWN
Definition: winuser.h:1715
#define EM_GETLINECOUNT
Definition: winuser.h:1992
#define DM_GETDEFID
Definition: winuser.h:2098
BOOL WINAPI InflateRect(_Inout_ LPRECT, _In_ int, _In_ int)
#define GWL_STYLE
Definition: winuser.h:852
BOOL WINAPI GetScrollInfo(_In_ HWND, _In_ int, _Inout_ LPSCROLLINFO)
BOOL WINAPI GetUpdateRect(_In_ HWND, _Out_opt_ LPRECT, _In_ BOOL)
#define VK_ESCAPE
Definition: winuser.h:2214
#define DLGC_HASSETSEL
Definition: winuser.h:2614
BOOL WINAPI IsWindowVisible(_In_ HWND)
BOOL WINAPI DestroyWindow(_In_ HWND)
#define WM_KILLFOCUS
Definition: winuser.h:1614
BOOL WINAPI EqualRect(_In_ LPCRECT, _In_ LPCRECT)
#define SB_PAGEUP
Definition: winuser.h:568
BOOL WINAPI MoveWindow(_In_ HWND, _In_ int, _In_ int, _In_ int, _In_ int, _In_ BOOL)
#define WM_GETDLGCODE
Definition: winuser.h:1689
#define EM_SETMODIFY
Definition: winuser.h:2013
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
HCURSOR WINAPI LoadCursorA(_In_opt_ HINSTANCE, _In_ LPCSTR)
Definition: cursoricon.c:2090
#define EN_CHANGE
Definition: winuser.h:2022
#define WM_SETREDRAW
Definition: winuser.h:1616
const char * LPCSTR
Definition: xmlstorage.h:183
char * LPSTR
Definition: xmlstorage.h:182
__wchar_t WCHAR
Definition: xmlstorage.h:180
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
char CHAR
Definition: xmlstorage.h:175
unsigned char BYTE
Definition: xxhash.c:193