ReactOS 0.4.16-dev-1311-g81a4d83
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 <imm.h>
37#include <textserv.h>
38#include <commdlg.h>
39#include <time.h>
40#include <wine/test.h>
41
42#define ID_RICHEDITTESTDBUTTON 0x123
43
45
46#define ok_w3(format, szString1, szString2, szString3) \
47 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
48 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
49 WideCharToMultiByte(CP_ACP, 0, szString3, -1, string3, MAX_PATH, NULL, NULL); \
50 ok(!lstrcmpW(szString3, szString1) || !lstrcmpW(szString3, szString2), \
51 format, string1, string2, string3);
52
55
56#if defined(__i386__) && !defined(__MINGW32__) && (!defined(_MSC_VER) || !defined(__clang__))
57static void disable_beep( HWND hwnd )
58{
59 /* don't attempt to disable beep if we don't have thiscall compiler support */
60}
61#else
62#define ITextServices_OnTxPropertyBitsChange(This,a,b) (This)->lpVtbl->OnTxPropertyBitsChange(This,a,b)
63static void disable_beep( HWND hwnd )
64{
65 IRichEditOle *richole;
66 ITextServices *services;
67 IID *pIID_ITextServices = (IID *)GetProcAddress( hmoduleRichEdit, "IID_ITextServices" );
68
69 if (SendMessageW( hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&richole ))
70 {
71 if (SUCCEEDED( IRichEditOle_QueryInterface( richole, pIID_ITextServices, (void **)&services ) ))
72 {
74 ITextServices_Release( services );
75 }
76 IRichEditOle_Release( richole );
77 }
78}
79#endif
80
81static HWND new_window(LPCSTR lpClassName, DWORD dwStyle, HWND parent) {
82 HWND hwnd;
83 hwnd = CreateWindowA(lpClassName, NULL, dwStyle|WS_POPUP|WS_HSCROLL|WS_VSCROLL
84 |WS_VISIBLE, 0, 0, 200, 60, parent, NULL,
86 ok(hwnd != NULL, "class: %s, error: %d\n", lpClassName, (int) GetLastError());
88 return hwnd;
89}
90
91static HWND new_windowW(LPCWSTR lpClassName, DWORD dwStyle, HWND parent) {
92 HWND hwnd;
93 hwnd = CreateWindowW(lpClassName, NULL, dwStyle|WS_POPUP|WS_HSCROLL|WS_VSCROLL
94 |WS_VISIBLE, 0, 0, 200, 60, parent, NULL,
96 ok(hwnd != NULL, "class: %s, error: %d\n", wine_dbgstr_w(lpClassName), (int) GetLastError());
98 return hwnd;
99}
100
103}
104
107}
108
111}
112
113static WNDCLASSA make_simple_class(WNDPROC wndproc, LPCSTR lpClassName)
114{
115 WNDCLASSA cls;
116 cls.style = 0;
117 cls.lpfnWndProc = wndproc;
118 cls.cbClsExtra = 0;
119 cls.cbWndExtra = 0;
121 cls.hIcon = 0;
124 cls.lpszMenuName = NULL;
125 cls.lpszClassName = lpClassName;
126 return cls;
127}
128
129/* Keeps the window reponsive for the deley_time in seconds.
130 * This is useful for debugging a test to see what is happening. */
131static void keep_responsive(time_t delay_time)
132{
133 MSG msg;
134 time_t end;
135
136 /* The message pump uses PeekMessage() to empty the queue and then
137 * sleeps for 50ms before retrying the queue. */
138 end = time(NULL) + delay_time;
139 while (time(NULL) < end) {
140 if (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
143 } else {
144 Sleep(50);
145 }
146 }
147}
148
149static void simulate_typing_characters(HWND hwnd, const char* szChars)
150{
151 int ret;
152
153 while (*szChars != '\0') {
154 SendMessageA(hwnd, WM_KEYDOWN, *szChars, 1);
155 ret = SendMessageA(hwnd, WM_CHAR, *szChars, 1);
156 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *szChars, ret);
157 SendMessageA(hwnd, WM_KEYUP, *szChars, 1);
158 szChars++;
159 }
160}
161
162static BOOL hold_key(int vk)
163{
164 BYTE key_state[256];
165 BOOL result;
166
167 result = GetKeyboardState(key_state);
168 ok(result, "GetKeyboardState failed.\n");
169 if (!result) return FALSE;
170 key_state[vk] |= 0x80;
171 result = SetKeyboardState(key_state);
172 ok(result, "SetKeyboardState failed.\n");
173 return result != 0;
174}
175
176static BOOL release_key(int vk)
177{
178 BYTE key_state[256];
179 BOOL result;
180
181 result = GetKeyboardState(key_state);
182 ok(result, "GetKeyboardState failed.\n");
183 if (!result) return FALSE;
184 key_state[vk] &= ~0x80;
185 result = SetKeyboardState(key_state);
186 ok(result, "SetKeyboardState failed.\n");
187 return result != 0;
188}
189
190static const char haystack[] = "WINEWine wineWine wine WineWine";
191 /* ^0 ^10 ^20 ^30 */
192
193struct find_s {
194 int start;
195 int end;
196 const char *needle;
197 int flags;
199};
200
201
202static struct find_s find_tests[] = {
203 /* Find in empty text */
204 {0, -1, "foo", FR_DOWN, -1},
205 {0, -1, "foo", 0, -1},
206 {0, -1, "", FR_DOWN, -1},
207 {20, 5, "foo", FR_DOWN, -1},
208 {5, 20, "foo", FR_DOWN, -1}
209};
210
211static struct find_s find_tests2[] = {
212 /* No-result find */
213 {0, -1, "foo", FR_DOWN | FR_MATCHCASE, -1},
214 {5, 20, "WINE", FR_DOWN | FR_MATCHCASE, -1},
215
216 /* Subsequent finds */
217 {0, -1, "Wine", FR_DOWN | FR_MATCHCASE, 4},
218 {5, 31, "Wine", FR_DOWN | FR_MATCHCASE, 13},
219 {14, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23},
220 {24, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27},
221
222 /* Find backwards */
223 {19, 20, "Wine", FR_MATCHCASE, 13},
224 {10, 20, "Wine", FR_MATCHCASE, 4},
225 {20, 10, "Wine", FR_MATCHCASE, 13},
226
227 /* Case-insensitive */
228 {1, 31, "wInE", FR_DOWN, 4},
229 {1, 31, "Wine", FR_DOWN, 4},
230
231 /* High-to-low ranges */
232 {20, 5, "Wine", FR_DOWN, -1},
233 {2, 1, "Wine", FR_DOWN, -1},
234 {30, 29, "Wine", FR_DOWN, -1},
235 {20, 5, "Wine", 0, 13},
236
237 /* Find nothing */
238 {5, 10, "", FR_DOWN, -1},
239 {10, 5, "", FR_DOWN, -1},
240 {0, -1, "", FR_DOWN, -1},
241 {10, 5, "", 0, -1},
242
243 /* Whole-word search */
244 {0, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18},
245 {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1},
246 {13, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18},
247 {0, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 0},
248 {10, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 23},
249 {11, -1, "winewine", FR_WHOLEWORD, 0},
250 {31, -1, "winewine", FR_WHOLEWORD, 23},
251
252 /* Bad ranges */
253 {5, 200, "XXX", FR_DOWN, -1},
254 {-20, 20, "Wine", FR_DOWN, -1},
255 {-20, 20, "Wine", FR_DOWN, -1},
256 {-15, -20, "Wine", FR_DOWN, -1},
257 {1<<12, 1<<13, "Wine", FR_DOWN, -1},
258
259 /* Check the case noted in bug 4479 where matches at end aren't recognized */
260 {23, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23},
261 {27, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27},
262 {27, 32, "Wine", FR_DOWN | FR_MATCHCASE, 27},
263 {13, 31, "WineWine", FR_DOWN | FR_MATCHCASE, 23},
264 {13, 32, "WineWine", FR_DOWN | FR_MATCHCASE, 23},
265
266 /* The backwards case of bug 4479; bounds look right
267 * Fails because backward find is wrong */
268 {19, 20, "WINE", FR_MATCHCASE, 0},
269 {0, 20, "WINE", FR_MATCHCASE, -1},
270
271 {0, -1, "wineWine wine", 0, -1},
272};
273
274static WCHAR *atowstr(const char *str)
275{
276 WCHAR *ret;
277 DWORD len;
278 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
279 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
281 return ret;
282}
283
284static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id, BOOL unicode)
285{
286 int findloc;
287
288 if(unicode){
289 FINDTEXTW ftw;
290 memset(&ftw, 0, sizeof(ftw));
291 ftw.chrg.cpMin = f->start;
292 ftw.chrg.cpMax = f->end;
293 ftw.lpstrText = atowstr(f->needle);
294
295 findloc = SendMessageA(hwnd, EM_FINDTEXT, f->flags, (LPARAM)&ftw);
296 ok(findloc == f->expected_loc,
297 "EM_FINDTEXT(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
298 name, id, unicode, f->needle, f->start, f->end, f->flags, findloc, f->expected_loc);
299
300 findloc = SendMessageA(hwnd, EM_FINDTEXTW, f->flags, (LPARAM)&ftw);
301 ok(findloc == f->expected_loc,
302 "EM_FINDTEXTW(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
303 name, id, unicode, f->needle, f->start, f->end, f->flags, findloc, f->expected_loc);
304
305 HeapFree(GetProcessHeap(), 0, (void*)ftw.lpstrText);
306 }else{
307 FINDTEXTA fta;
308 memset(&fta, 0, sizeof(fta));
309 fta.chrg.cpMin = f->start;
310 fta.chrg.cpMax = f->end;
311 fta.lpstrText = f->needle;
312
313 findloc = SendMessageA(hwnd, EM_FINDTEXT, f->flags, (LPARAM)&fta);
314 ok(findloc == f->expected_loc,
315 "EM_FINDTEXT(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
316 name, id, unicode, f->needle, f->start, f->end, f->flags, findloc, f->expected_loc);
317 }
318}
319
320static void check_EM_FINDTEXTEX(HWND hwnd, const char *name, struct find_s *f,
321 int id, BOOL unicode)
322{
323 int findloc;
324 int expected_end_loc;
325
326 if(unicode){
327 FINDTEXTEXW ftw;
328 memset(&ftw, 0, sizeof(ftw));
329 ftw.chrg.cpMin = f->start;
330 ftw.chrg.cpMax = f->end;
331 ftw.lpstrText = atowstr(f->needle);
332 findloc = SendMessageA(hwnd, EM_FINDTEXTEX, f->flags, (LPARAM)&ftw);
333 ok(findloc == f->expected_loc,
334 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
335 name, id, f->needle, f->start, f->end, f->flags, findloc);
336 ok(ftw.chrgText.cpMin == f->expected_loc,
337 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %ld\n",
338 name, id, f->needle, f->start, f->end, f->flags, ftw.chrgText.cpMin);
339 expected_end_loc = ((f->expected_loc == -1) ? -1
340 : f->expected_loc + strlen(f->needle));
341 ok(ftw.chrgText.cpMax == expected_end_loc,
342 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %ld, expected %d\n",
343 name, id, f->needle, f->start, f->end, f->flags, ftw.chrgText.cpMax, expected_end_loc);
344 HeapFree(GetProcessHeap(), 0, (void*)ftw.lpstrText);
345 }else{
346 FINDTEXTEXA fta;
347 memset(&fta, 0, sizeof(fta));
348 fta.chrg.cpMin = f->start;
349 fta.chrg.cpMax = f->end;
350 fta.lpstrText = f->needle;
351 findloc = SendMessageA(hwnd, EM_FINDTEXTEX, f->flags, (LPARAM)&fta);
352 ok(findloc == f->expected_loc,
353 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
354 name, id, f->needle, f->start, f->end, f->flags, findloc);
355 ok(fta.chrgText.cpMin == f->expected_loc,
356 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %ld\n",
357 name, id, f->needle, f->start, f->end, f->flags, fta.chrgText.cpMin);
358 expected_end_loc = ((f->expected_loc == -1) ? -1
359 : f->expected_loc + strlen(f->needle));
360 ok(fta.chrgText.cpMax == expected_end_loc,
361 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %ld, expected %d\n",
362 name, id, f->needle, f->start, f->end, f->flags, fta.chrgText.cpMax, expected_end_loc);
363 }
364}
365
366static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *find,
367 int num_tests, BOOL unicode)
368{
369 int i;
370
371 for (i = 0; i < num_tests; i++) {
372 check_EM_FINDTEXT(hwnd, name, &find[i], i, unicode);
373 check_EM_FINDTEXTEX(hwnd, name, &find[i], i, unicode);
374 }
375}
376
377static void test_EM_FINDTEXT(BOOL unicode)
378{
379 HWND hwndRichEdit;
380 CHARFORMAT2A cf2;
381
382 if(unicode)
383 hwndRichEdit = new_richeditW(NULL);
384 else
385 hwndRichEdit = new_richedit(NULL);
386
387 /* Empty rich edit control */
388 run_tests_EM_FINDTEXT(hwndRichEdit, "1", find_tests, ARRAY_SIZE(find_tests), unicode);
389
390 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)haystack);
391
392 /* Haystack text */
393 run_tests_EM_FINDTEXT(hwndRichEdit, "2", find_tests2, ARRAY_SIZE(find_tests2), unicode);
394
395 /* Setting a format on an arbitrary range should have no effect in search
396 results. This tests correct offset reporting across runs. */
397 cf2.cbSize = sizeof(CHARFORMAT2A);
398 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2);
399 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
400 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
401 SendMessageA(hwndRichEdit, EM_SETSEL, 6, 20);
402 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
403
404 /* Haystack text, again */
405 run_tests_EM_FINDTEXT(hwndRichEdit, "2-bis", find_tests2, ARRAY_SIZE(find_tests2), unicode);
406
407 /* Yet another range */
408 cf2.dwMask = CFM_BOLD | cf2.dwMask;
409 cf2.dwEffects = CFE_BOLD ^ cf2.dwEffects;
410 SendMessageA(hwndRichEdit, EM_SETSEL, 11, 15);
411 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
412
413 /* Haystack text, again */
414 run_tests_EM_FINDTEXT(hwndRichEdit, "2-bisbis", find_tests2, ARRAY_SIZE(find_tests2), unicode);
415
416 DestroyWindow(hwndRichEdit);
417}
418
419static const struct getline_s {
420 int line;
422 const char *text;
423} gl[] = {
424 {0, 10, "foo bar\r"},
425 {1, 10, "\r"},
426 {2, 10, "bar\r"},
427 {3, 10, "\r"},
428
429 /* Buffer smaller than line length */
430 {0, 2, "foo bar\r"},
431 {0, 1, "foo bar\r"},
432 {0, 0, "foo bar\r"}
434
435static void test_EM_GETLINE(void)
436{
437 int i;
438 HWND hwndRichEdit = new_richedit(NULL);
439 static const int nBuf = 1024;
440 char dest[1024], origdest[1024];
441 const char text[] = "foo bar\n"
442 "\n"
443 "bar\n";
444
445 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
446
447 memset(origdest, 0xBB, nBuf);
448 for (i = 0; i < ARRAY_SIZE(gl); i++)
449 {
450 int nCopied;
451 int expected_nCopied = min(gl[i].buffer_len, strlen(gl[i].text));
452 int expected_bytes_written = min(gl[i].buffer_len, strlen(gl[i].text));
453 memset(dest, 0xBB, nBuf);
454 *(WORD *) dest = gl[i].buffer_len;
455
456 /* EM_GETLINE appends a "\r\0" to the end of the line
457 * nCopied counts up to and including the '\r' */
458 nCopied = SendMessageA(hwndRichEdit, EM_GETLINE, gl[i].line, (LPARAM)dest);
459 ok(nCopied == expected_nCopied, "%d: %d!=%d\n", i, nCopied,
460 expected_nCopied);
461 /* two special cases since a parameter is passed via dest */
462 if (gl[i].buffer_len == 0)
463 ok(!dest[0] && !dest[1] && !strncmp(dest+2, origdest+2, nBuf-2),
464 "buffer_len=0\n");
465 else if (gl[i].buffer_len == 1)
466 ok(dest[0] == gl[i].text[0] && !dest[1] &&
467 !strncmp(dest+2, origdest+2, nBuf-2), "buffer_len=1\n");
468 else
469 {
470 /* Prepare hex strings of buffers to dump on failure. */
471 char expectedbuf[1024];
472 char resultbuf[1024];
473 int j;
474 resultbuf[0] = '\0';
475 for (j = 0; j < 32; j++)
476 sprintf(resultbuf+strlen(resultbuf), "%02x", dest[j] & 0xFF);
477 expectedbuf[0] = '\0';
478 for (j = 0; j < expected_bytes_written; j++) /* Written bytes */
479 sprintf(expectedbuf+strlen(expectedbuf), "%02x", gl[i].text[j] & 0xFF);
480 for (; j < gl[i].buffer_len; j++) /* Ignored bytes */
481 sprintf(expectedbuf+strlen(expectedbuf), "??");
482 for (; j < 32; j++) /* Bytes after declared buffer size */
483 sprintf(expectedbuf+strlen(expectedbuf), "%02x", origdest[j] & 0xFF);
484
485 /* Test the part of the buffer that is expected to be written according
486 * to the MSDN documentation fo EM_GETLINE, which does not state that
487 * a NULL terminating character will be added unless no text is copied.
488 *
489 * Windows NT does not append a NULL terminating character, but
490 * Windows 2000 and up do append a NULL terminating character if there
491 * is space in the buffer. The test will ignore this difference. */
492 ok(!strncmp(dest, gl[i].text, expected_bytes_written),
493 "%d: expected_bytes_written=%d\n" "expected=0x%s\n" "but got= 0x%s\n",
494 i, expected_bytes_written, expectedbuf, resultbuf);
495 /* Test the part of the buffer after the declared length to make sure
496 * there are no buffer overruns. */
497 ok(!strncmp(dest + gl[i].buffer_len, origdest + gl[i].buffer_len,
498 nBuf - gl[i].buffer_len),
499 "%d: expected_bytes_written=%d\n" "expected=0x%s\n" "but got= 0x%s\n",
500 i, expected_bytes_written, expectedbuf, resultbuf);
501 }
502 }
503
504 DestroyWindow(hwndRichEdit);
505}
506
507static void test_EM_LINELENGTH(void)
508{
509 HWND hwndRichEdit = new_richedit(NULL);
510 const char * text =
511 "richedit1\r"
512 "richedit1\n"
513 "richedit1\r\n"
514 "richedit1";
515 int offset_test[10][2] = {
516 {0, 9},
517 {5, 9},
518 {10, 9},
519 {15, 9},
520 {20, 9},
521 {25, 9},
522 {30, 9},
523 {35, 9},
524 {40, 0},
525 {45, 0},
526 };
527 int i;
529
530 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
531
532 for (i = 0; i < 10; i++) {
533 result = SendMessageA(hwndRichEdit, EM_LINELENGTH, offset_test[i][0], 0);
534 ok(result == offset_test[i][1], "Length of line at offset %d is %Id, expected %d\n",
535 offset_test[i][0], result, offset_test[i][1]);
536 }
537
538 /* Test with multibyte character */
539 if (!is_lang_japanese)
540 skip("Skip multibyte character tests on non-Japanese platform\n");
541 else
542 {
543 const char *text1 =
544 "wine\n"
545 "richedit\x8e\xf0\n"
546 "wine";
547 int offset_test1[3][2] = {
548 {0, 4}, /* Line 1: |wine\n */
549 {5, 9}, /* Line 2: |richedit\x8e\xf0\n */
550 {15, 4}, /* Line 3: |wine */
551 };
552 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
553 for (i = 0; i < ARRAY_SIZE(offset_test1); i++) {
554 result = SendMessageA(hwndRichEdit, EM_LINELENGTH, offset_test1[i][0], 0);
555 ok(result == offset_test1[i][1], "Length of line at offset %d is %Id, expected %d\n",
556 offset_test1[i][0], result, offset_test1[i][1]);
557 }
558 }
559
560 DestroyWindow(hwndRichEdit);
561}
562
564{
565 POINT p = {-1, -1};
567 ok(p.x != -1 && p.y != -1, "p.x:%ld p.y:%ld\n", p.x, p.y);
568 return p.y;
569}
570
571static void move_cursor(HWND hwnd, LONG charindex)
572{
573 CHARRANGE cr;
574 cr.cpMax = charindex;
575 cr.cpMin = charindex;
577}
578
579static void line_scroll(HWND hwnd, int amount)
580{
581 SendMessageA(hwnd, EM_LINESCROLL, 0, amount);
582}
583
584static void test_EM_SCROLLCARET(void)
585{
586 int prevY, curY;
587 const char text[] = "aa\n"
588 "this is a long line of text that should be longer than the "
589 "control's width\n"
590 "cc\n"
591 "dd\n"
592 "ee\n"
593 "ff\n"
594 "gg\n"
595 "hh\n";
596 /* The richedit window height needs to be large enough vertically to fit in
597 * more than two lines of text, so the new_richedit function can't be used
598 * since a height of 60 was not large enough on some systems.
599 */
602 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
603 ok(hwndRichEdit != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
604
605 /* Can't verify this */
606 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0);
607
608 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
609
610 /* Caret above visible window */
611 line_scroll(hwndRichEdit, 3);
612 prevY = get_scroll_pos_y(hwndRichEdit);
613 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0);
614 curY = get_scroll_pos_y(hwndRichEdit);
615 ok(prevY != curY, "%d == %d\n", prevY, curY);
616
617 /* Caret below visible window */
618 move_cursor(hwndRichEdit, sizeof(text) - 1);
619 line_scroll(hwndRichEdit, -3);
620 prevY = get_scroll_pos_y(hwndRichEdit);
621 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0);
622 curY = get_scroll_pos_y(hwndRichEdit);
623 ok(prevY != curY, "%d == %d\n", prevY, curY);
624
625 /* Caret in visible window */
626 move_cursor(hwndRichEdit, sizeof(text) - 2);
627 prevY = get_scroll_pos_y(hwndRichEdit);
628 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0);
629 curY = get_scroll_pos_y(hwndRichEdit);
630 ok(prevY == curY, "%d != %d\n", prevY, curY);
631
632 /* Caret still in visible window */
633 line_scroll(hwndRichEdit, -1);
634 prevY = get_scroll_pos_y(hwndRichEdit);
635 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0);
636 curY = get_scroll_pos_y(hwndRichEdit);
637 ok(prevY == curY, "%d != %d\n", prevY, curY);
638
639 DestroyWindow(hwndRichEdit);
640}
641
642static void test_EM_POSFROMCHAR(void)
643{
644 HWND hwndRichEdit = new_richedit(NULL);
645 int i, expected;
647 unsigned int height = 0;
648 int xpos = 0;
649 POINTL pt;
650 LOCALESIGNATURE sig;
651 BOOL rtl;
653 static const char text[] = "aa\n"
654 "this is a long line of text that should be longer than the "
655 "control's width\n"
656 "cc\n"
657 "dd\n"
658 "ee\n"
659 "ff\n"
660 "gg\n"
661 "hh\n";
662
664 (LPSTR) &sig, sizeof(LOCALESIGNATURE)) &&
665 (sig.lsUsb[3] & 0x08000000) != 0);
666
667 /* Fill the control to lines to ensure that most of them are offscreen */
668 for (i = 0; i < 50; i++)
669 {
670 /* Do not modify the string; it is exactly 16 characters long. */
671 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 0);
672 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"0123456789ABCDE\n");
673 }
674
675 /*
676 Richedit 1.0 receives a POINTL* on wParam and character offset on lParam, returns void.
677 Richedit 2.0 receives character offset on wParam, ignores lParam, returns MAKELONG(x,y)
678 Richedit 3.0 accepts either of the above API conventions.
679 */
680
681 /* Testing Richedit 2.0 API format */
682
683 /* Testing start of lines. X-offset should be constant on all cases (native is 1).
684 Since all lines are identical and drawn with the same font,
685 they should have the same height... right?
686 */
687 for (i = 0; i < 50; i++)
688 {
689 /* All the lines are 16 characters long */
690 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, i * 16, 0);
691 if (i == 0)
692 {
693 ok(HIWORD(result) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result));
694 ok(LOWORD(result) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
695 xpos = LOWORD(result);
696 }
697 else if (i == 1)
698 {
699 ok(HIWORD(result) > 0, "EM_POSFROMCHAR reports y=%d, expected > 0\n", HIWORD(result));
700 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
702 }
703 else
704 {
706 ok(HIWORD(result) == i * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), i * height);
707 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
708 }
709 }
710
711 /* Testing position at end of text */
712 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 50 * 16, 0);
713 ok(HIWORD(result) == 50 * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), 50 * height);
714 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
715
716 /* Testing position way past end of text */
717 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 55 * 16, 0);
718 ok(HIWORD(result) == 50 * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), 50 * height);
719 expected = (rtl ? 8 : 1);
720 ok(LOWORD(result) == expected, "EM_POSFROMCHAR reports x=%d, expected %d\n", LOWORD(result), expected);
721
722 /* Testing that vertical scrolling does, in fact, have an effect on EM_POSFROMCHAR */
723 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */
724 for (i = 0; i < 50; i++)
725 {
726 /* All the lines are 16 characters long */
727 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, i * 16, 0);
728 ok((signed short)(HIWORD(result)) == (i - 1) * height,
729 "EM_POSFROMCHAR reports y=%hd, expected %d\n",
730 (signed short)(HIWORD(result)), (i - 1) * height);
731 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
732 }
733
734 /* Testing position at end of text */
735 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 50 * 16, 0);
736 ok(HIWORD(result) == (50 - 1) * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), (50 - 1) * height);
737 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
738
739 /* Testing position way past end of text */
740 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 55 * 16, 0);
741 ok(HIWORD(result) == (50 - 1) * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), (50 - 1) * height);
742 expected = (rtl ? 8 : 1);
743 ok(LOWORD(result) == expected, "EM_POSFROMCHAR reports x=%d, expected %d\n", LOWORD(result), expected);
744
745 /* Testing that horizontal scrolling does, in fact, have an effect on EM_POSFROMCHAR */
746 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
747 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */
748
749 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 0, 0);
750 ok(HIWORD(result) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result));
751 ok(LOWORD(result) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
752 xpos = LOWORD(result);
753
754 SendMessageA(hwndRichEdit, WM_HSCROLL, SB_LINERIGHT, 0);
755 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 0, 0);
756 ok(HIWORD(result) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result));
757 ok((signed short)(LOWORD(result)) < xpos,
758 "EM_POSFROMCHAR reports x=%hd, expected value less than %d\n",
759 (signed short)(LOWORD(result)), xpos);
760 SendMessageA(hwndRichEdit, WM_HSCROLL, SB_LINELEFT, 0);
761
762 /* Test around end of text that doesn't end in a newline. */
763 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"12345678901234");
764 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt,
765 SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0)-1);
766 ok(pt.x > 1, "pt.x = %ld\n", pt.x);
767 xpos = pt.x;
768 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt,
769 SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0));
770 ok(pt.x > xpos, "pt.x = %ld\n", pt.x);
771 xpos = (rtl ? pt.x + 7 : pt.x);
772 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt,
773 SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0)+1);
774 ok(pt.x == xpos, "pt.x = %ld\n", pt.x);
775
776 /* Try a negative position. */
777 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt, -1);
778 ok(pt.x == 1, "pt.x = %ld\n", pt.x);
779
780 /* test negative indentation */
781 SendMessageA(hwndRichEdit, WM_SETTEXT, 0,
782 (LPARAM)"{\\rtf1\\pard\\fi-200\\li-200\\f1 TestSomeText\\par}");
783 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt, 0);
784 ok(pt.x == 1, "pt.x = %ld\n", pt.x);
785
786 fmt.cbSize = sizeof(fmt);
787 SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt);
788 ok(fmt.dxStartIndent == -400, "got %ld\n", fmt.dxStartIndent);
789 ok(fmt.dxOffset == 200, "got %ld\n", fmt.dxOffset);
790 ok(fmt.wAlignment == PFA_LEFT, "got %d\n", fmt.wAlignment);
791
792 DestroyWindow(hwndRichEdit);
793}
794
795static void test_EM_SETCHARFORMAT(void)
796{
797 HWND hwndRichEdit = new_richedit(NULL);
798 CHARFORMAT2A cf2;
799 CHARFORMAT2W cfW;
800 CHARFORMATA cf1a;
801 CHARFORMATW cf1w;
802 int rc = 0;
803 int tested_effects[] = {
804 CFE_BOLD,
809 CFE_LINK,
812 0
813 };
814 int i;
815 CHARRANGE cr;
816 LOCALESIGNATURE sig;
817 BOOL rtl;
818 DWORD expect_effects;
819
821 (LPSTR) &sig, sizeof(LOCALESIGNATURE)) &&
822 (sig.lsUsb[3] & 0x08000000) != 0);
823
824 /* check charformat defaults */
825 memset(&cf2, 0, sizeof(CHARFORMAT2A));
826 cf2.cbSize = sizeof(CHARFORMAT2A);
827 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
828 ok(cf2.dwMask == CFM_ALL2, "got %08lx\n", cf2.dwMask);
829 expect_effects = CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR;
830 if (cf2.wWeight > 550) expect_effects |= CFE_BOLD;
831 ok(cf2.dwEffects == expect_effects, "got %08lx\n", cf2.dwEffects);
832 ok(cf2.yOffset == 0, "got %ld\n", cf2.yOffset);
833 ok(cf2.sSpacing == 0, "got %d\n", cf2.sSpacing);
834 ok(cf2.lcid == GetSystemDefaultLCID(), "got %lx\n", cf2.lcid);
835 ok(cf2.sStyle == 0, "got %d\n", cf2.sStyle);
836 ok(cf2.wKerning == 0, "got %d\n", cf2.wKerning);
837 ok(cf2.bAnimation == 0, "got %d\n", cf2.bAnimation);
838 ok(cf2.bRevAuthor == 0, "got %d\n", cf2.bRevAuthor);
839
840 /* Invalid flags, CHARFORMAT2 structure blanked out */
841 memset(&cf2, 0, sizeof(cf2));
842 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)0xfffffff0, (LPARAM)&cf2);
843 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
844
845 /* A valid flag, CHARFORMAT2 structure blanked out */
846 memset(&cf2, 0, sizeof(cf2));
847 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2);
848 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
849
850 /* A valid flag, CHARFORMAT2 structure blanked out */
851 memset(&cf2, 0, sizeof(cf2));
852 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2);
853 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
854
855 /* A valid flag, CHARFORMAT2 structure blanked out */
856 memset(&cf2, 0, sizeof(cf2));
857 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_WORD, (LPARAM)&cf2);
858 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
859
860 /* A valid flag, CHARFORMAT2 structure blanked out */
861 memset(&cf2, 0, sizeof(cf2));
862 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2);
863 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
864
865 /* Invalid flags, CHARFORMAT2 structure minimally filled */
866 memset(&cf2, 0, sizeof(cf2));
867 cf2.cbSize = sizeof(CHARFORMAT2A);
868 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)0xfffffff0, (LPARAM)&cf2);
869 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
870 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
871 ok(rc == FALSE, "Should not be able to undo here.\n");
872 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0);
873
874 /* A valid flag, CHARFORMAT2 structure minimally filled */
875 memset(&cf2, 0, sizeof(cf2));
876 cf2.cbSize = sizeof(CHARFORMAT2A);
877 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2);
878 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
879 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
880 ok(rc == FALSE, "Should not be able to undo here.\n");
881 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0);
882
883 /* A valid flag, CHARFORMAT2 structure minimally filled */
884 memset(&cf2, 0, sizeof(cf2));
885 cf2.cbSize = sizeof(CHARFORMAT2A);
886 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2);
887 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
888 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
889 ok(rc == FALSE, "Should not be able to undo here.\n");
890 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0);
891
892 /* A valid flag, CHARFORMAT2 structure minimally filled */
893 memset(&cf2, 0, sizeof(cf2));
894 cf2.cbSize = sizeof(CHARFORMAT2A);
895 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_WORD, (LPARAM)&cf2);
896 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
897 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
898 todo_wine ok(rc == TRUE, "Should not be able to undo here.\n");
899 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0);
900
901 /* A valid flag, CHARFORMAT2 structure minimally filled */
902 memset(&cf2, 0, sizeof(cf2));
903 cf2.cbSize = sizeof(CHARFORMAT2A);
904 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2);
905 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
906 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
907 ok(rc == TRUE, "Should not be able to undo here.\n");
908 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0);
909
910 cf2.cbSize = sizeof(CHARFORMAT2A);
911 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2);
912
913 /* Test state of modify flag before and after valid EM_SETCHARFORMAT */
914 cf2.cbSize = sizeof(CHARFORMAT2A);
915 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2);
916 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
917 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
918
919 /* wParam==0 is default char format, does not set modify */
920 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
921 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
922 ok(rc == 0, "Text marked as modified, expected not modified!\n");
923 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, 0, (LPARAM)&cf2);
924 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
925 if (! rtl)
926 {
927 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
928 ok(rc == 0, "Text marked as modified, expected not modified!\n");
929 }
930 else
931 skip("RTL language found\n");
932
933 /* wParam==SCF_SELECTION sets modify if nonempty selection */
934 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
935 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
936 ok(rc == 0, "Text marked as modified, expected not modified!\n");
937 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
938 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
939 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
940 ok(rc == 0, "Text marked as modified, expected not modified!\n");
941
942 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
943 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
944 ok(rc == 0, "Text marked as modified, expected not modified!\n");
945 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
946 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
947 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
948 ok(rc == 0, "Text marked as modified, expected not modified!\n");
949 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2);
950 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
951 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
952 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
953 ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc);
954
955 /* wParam==SCF_ALL sets modify regardless of whether text is present */
956 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
957 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
958 ok(rc == 0, "Text marked as modified, expected not modified!\n");
959 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2);
960 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
961 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
962 ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc);
963
964 DestroyWindow(hwndRichEdit);
965
966 /* EM_GETCHARFORMAT tests */
967 for (i = 0; tested_effects[i]; i++)
968 {
969 hwndRichEdit = new_richedit(NULL);
970 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
971
972 /* Need to set a TrueType font to get consistent CFM_BOLD results */
973 memset(&cf2, 0, sizeof(CHARFORMAT2A));
974 cf2.cbSize = sizeof(CHARFORMAT2A);
976 cf2.dwEffects = 0;
977 strcpy(cf2.szFaceName, "Courier New");
978 cf2.wWeight = FW_DONTCARE;
979 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2);
980
981 memset(&cf2, 0, sizeof(CHARFORMAT2A));
982 cf2.cbSize = sizeof(CHARFORMAT2A);
983 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 4);
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) == CFM_SUPERSCRIPT)
987 ||
988 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
989 "%d, cf2.dwMask == 0x%08lx expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
990 ok((cf2.dwEffects & tested_effects[i]) == 0,
991 "%d, cf2.dwEffects == 0x%08lx expected effect 0x%08x clear\n", i, cf2.dwEffects, tested_effects[i]);
992
993 memset(&cf2, 0, sizeof(CHARFORMAT2A));
994 cf2.cbSize = sizeof(CHARFORMAT2A);
995 cf2.dwMask = tested_effects[i];
996 if (cf2.dwMask == CFE_SUBSCRIPT || cf2.dwMask == CFE_SUPERSCRIPT)
997 cf2.dwMask = CFM_SUPERSCRIPT;
998 cf2.dwEffects = tested_effects[i];
999 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2);
1000 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1001
1002 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1003 cf2.cbSize = sizeof(CHARFORMAT2A);
1004 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2);
1005 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1006 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
1007 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
1008 ||
1009 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
1010 "%d, cf2.dwMask == 0x%08lx expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
1011 ok((cf2.dwEffects & tested_effects[i]) == tested_effects[i],
1012 "%d, cf2.dwEffects == 0x%08lx expected effect 0x%08x\n", i, cf2.dwEffects, tested_effects[i]);
1013
1014 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1015 cf2.cbSize = sizeof(CHARFORMAT2A);
1016 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 4);
1017 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1018 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
1019 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
1020 ||
1021 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
1022 "%d, cf2.dwMask == 0x%08lx expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
1023 ok((cf2.dwEffects & tested_effects[i]) == 0,
1024 "%d, cf2.dwEffects == 0x%08lx expected effect 0x%08x clear\n", i, cf2.dwEffects, tested_effects[i]);
1025
1026 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1027 cf2.cbSize = sizeof(CHARFORMAT2A);
1028 SendMessageA(hwndRichEdit, EM_SETSEL, 1, 3);
1029 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1030 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
1031 (cf2.dwMask & CFM_SUPERSCRIPT) == 0)
1032 ||
1033 (cf2.dwMask & tested_effects[i]) == 0),
1034 "%d, cf2.dwMask == 0x%08lx expected mask 0x%08x clear\n", i, cf2.dwMask, tested_effects[i]);
1035
1036 DestroyWindow(hwndRichEdit);
1037 }
1038
1039 for (i = 0; tested_effects[i]; i++)
1040 {
1041 hwndRichEdit = new_richedit(NULL);
1042 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1043
1044 /* Need to set a TrueType font to get consistent CFM_BOLD results */
1045 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1046 cf2.cbSize = sizeof(CHARFORMAT2A);
1048 cf2.dwEffects = 0;
1049 strcpy(cf2.szFaceName, "Courier New");
1050 cf2.wWeight = FW_DONTCARE;
1051 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2);
1052
1053 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1054 cf2.cbSize = sizeof(CHARFORMAT2A);
1055 cf2.dwMask = tested_effects[i];
1056 if (cf2.dwMask == CFE_SUBSCRIPT || cf2.dwMask == CFE_SUPERSCRIPT)
1057 cf2.dwMask = CFM_SUPERSCRIPT;
1058 cf2.dwEffects = tested_effects[i];
1059 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 4);
1060 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1061
1062 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1063 cf2.cbSize = sizeof(CHARFORMAT2A);
1064 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2);
1065 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1066 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
1067 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
1068 ||
1069 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
1070 "%d, cf2.dwMask == 0x%08lx expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
1071 ok((cf2.dwEffects & tested_effects[i]) == 0,
1072 "%d, cf2.dwEffects == 0x%08lx expected effect 0x%08x clear\n", i, cf2.dwEffects, tested_effects[i]);
1073
1074 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1075 cf2.cbSize = sizeof(CHARFORMAT2A);
1076 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 4);
1077 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1078 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
1079 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
1080 ||
1081 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
1082 "%d, cf2.dwMask == 0x%08lx expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
1083 ok((cf2.dwEffects & tested_effects[i]) == tested_effects[i],
1084 "%d, cf2.dwEffects == 0x%08lx expected effect 0x%08x\n", i, cf2.dwEffects, tested_effects[i]);
1085
1086 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1087 cf2.cbSize = sizeof(CHARFORMAT2A);
1088 SendMessageA(hwndRichEdit, EM_SETSEL, 1, 3);
1089 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1090 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
1091 (cf2.dwMask & CFM_SUPERSCRIPT) == 0)
1092 ||
1093 (cf2.dwMask & tested_effects[i]) == 0),
1094 "%d, cf2.dwMask == 0x%08lx expected mask 0x%08x clear\n", i, cf2.dwMask, tested_effects[i]);
1095 ok((cf2.dwEffects & tested_effects[i]) == tested_effects[i],
1096 "%d, cf2.dwEffects == 0x%08lx expected effect 0x%08x set\n", i, cf2.dwEffects, tested_effects[i]);
1097
1098 DestroyWindow(hwndRichEdit);
1099 }
1100
1101 /* Effects applied on an empty selection should take effect when selection is
1102 replaced with text */
1103 hwndRichEdit = new_richedit(NULL);
1104 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1105 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */
1106
1107 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1108 cf2.cbSize = sizeof(CHARFORMAT2A);
1109 cf2.dwMask = CFM_BOLD;
1110 cf2.dwEffects = CFE_BOLD;
1111 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1112
1113 /* Selection is now nonempty */
1114 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi");
1115
1116 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1117 cf2.cbSize = sizeof(CHARFORMAT2A);
1118 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 6);
1119 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1120
1121 ok (((cf2.dwMask & CFM_BOLD) == CFM_BOLD),
1122 "%d, cf2.dwMask == 0x%08lx expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD);
1123 ok((cf2.dwEffects & CFE_BOLD) == CFE_BOLD,
1124 "%d, cf2.dwEffects == 0x%08lx expected effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD);
1125
1126
1127 /* Set two effects on an empty selection */
1128 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1129 /* first clear bold, italic */
1130 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
1131 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1132 cf2.cbSize = sizeof(CHARFORMAT2A);
1133 cf2.dwMask = CFM_BOLD | CFM_ITALIC;
1134 cf2.dwEffects = 0;
1135 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1136
1137 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */
1138
1139 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1140 cf2.cbSize = sizeof(CHARFORMAT2A);
1141 cf2.dwMask = CFM_BOLD;
1142 cf2.dwEffects = CFE_BOLD;
1143 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1144 cf2.dwMask = CFM_ITALIC;
1145 cf2.dwEffects = CFE_ITALIC;
1146 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1147
1148 /* Selection is now nonempty */
1149 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi");
1150
1151 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1152 cf2.cbSize = sizeof(CHARFORMAT2A);
1153 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 6);
1154 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1155
1156 ok (((cf2.dwMask & (CFM_BOLD|CFM_ITALIC)) == (CFM_BOLD|CFM_ITALIC)),
1157 "%d, cf2.dwMask == 0x%08lx expected mask 0x%08x\n", i, cf2.dwMask, (CFM_BOLD|CFM_ITALIC));
1159 "%d, cf2.dwEffects == 0x%08lx expected effect 0x%08x\n", i, cf2.dwEffects, (CFE_BOLD|CFE_ITALIC));
1160
1161 /* Setting the (empty) selection to exactly the same place as before should
1162 NOT clear the insertion style! */
1163 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1164 /* first clear bold, italic */
1165 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
1166 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1167 cf2.cbSize = sizeof(CHARFORMAT2A);
1168 cf2.dwMask = CFM_BOLD | CFM_ITALIC;
1169 cf2.dwEffects = 0;
1170 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1171
1172 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */
1173
1174 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1175 cf2.cbSize = sizeof(CHARFORMAT2A);
1176 cf2.dwMask = CFM_BOLD;
1177 cf2.dwEffects = CFE_BOLD;
1178 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1179
1180 /* Empty selection in same place, insert style should NOT be forgotten here. */
1181 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2);
1182
1183 /* Selection is now nonempty */
1184 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi");
1185
1186 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1187 cf2.cbSize = sizeof(CHARFORMAT2A);
1188 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 6);
1189 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1190
1191 ok (((cf2.dwMask & CFM_BOLD) == CFM_BOLD),
1192 "%d, cf2.dwMask == 0x%08lx expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD);
1193 ok((cf2.dwEffects & CFE_BOLD) == CFE_BOLD,
1194 "%d, cf2.dwEffects == 0x%08lx expected effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD);
1195
1196 /* Moving the selection will clear the insertion style */
1197 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1198 /* first clear bold, italic */
1199 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
1200 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1201 cf2.cbSize = sizeof(CHARFORMAT2A);
1202 cf2.dwMask = CFM_BOLD | CFM_ITALIC;
1203 cf2.dwEffects = 0;
1204 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1205
1206 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */
1207
1208 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1209 cf2.cbSize = sizeof(CHARFORMAT2A);
1210 cf2.dwMask = CFM_BOLD;
1211 cf2.dwEffects = CFE_BOLD;
1212 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1213
1214 /* Move selection and then put it back, insert style should be forgotten here. */
1215 SendMessageA(hwndRichEdit, EM_SETSEL, 3, 3);
1216 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */
1217
1218 /* Selection is now nonempty */
1219 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi");
1220
1221 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1222 cf2.cbSize = sizeof(CHARFORMAT2A);
1223 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 6);
1224 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1225
1226 ok(((cf2.dwMask & CFM_BOLD) == CFM_BOLD),
1227 "%d, cf2.dwMask == 0x%08lx expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD);
1228 ok((cf2.dwEffects & CFE_BOLD) == 0,
1229 "%d, cf2.dwEffects == 0x%08lx not expecting effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD);
1230
1231 /* Ditto with EM_EXSETSEL */
1232 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1233 /* first clear bold, italic */
1234 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
1235 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1236 cf2.cbSize = sizeof(CHARFORMAT2A);
1237 cf2.dwMask = CFM_BOLD | CFM_ITALIC;
1238 cf2.dwEffects = 0;
1239 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1240
1241 cr.cpMin = 2; cr.cpMax = 2;
1242 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); /* Empty selection */
1243
1244 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1245 cf2.cbSize = sizeof(CHARFORMAT2A);
1246 cf2.dwMask = CFM_BOLD;
1247 cf2.dwEffects = CFE_BOLD;
1248 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1249
1250 /* Empty selection in same place, insert style should NOT be forgotten here. */
1251 cr.cpMin = 2; cr.cpMax = 2;
1252 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); /* Empty selection */
1253
1254 /* Selection is now nonempty */
1255 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi");
1256
1257 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1258 cf2.cbSize = sizeof(CHARFORMAT2A);
1259 cr.cpMin = 2; cr.cpMax = 6;
1260 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); /* Empty selection */
1261 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1262
1263 ok (((cf2.dwMask & CFM_BOLD) == CFM_BOLD),
1264 "%d, cf2.dwMask == 0x%08lx expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD);
1265 ok((cf2.dwEffects & CFE_BOLD) == CFE_BOLD,
1266 "%d, cf2.dwEffects == 0x%08lx expected effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD);
1267
1268 /* show that wWeight is at the correct offset in CHARFORMAT2A */
1269 memset(&cf2, 0, sizeof(cf2));
1270 cf2.cbSize = sizeof(cf2);
1271 cf2.dwMask = CFM_WEIGHT;
1272 cf2.wWeight = 100;
1273 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1274 memset(&cf2, 0, sizeof(cf2));
1275 cf2.cbSize = sizeof(cf2);
1276 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1277 ok(cf2.wWeight == 100, "got %d\n", cf2.wWeight);
1278
1279 memset(&cf2, 0, sizeof(cf2));
1280 cf2.cbSize = sizeof(cf2);
1281 cf2.dwMask = CFM_SPACING;
1282 cf2.sSpacing = 10;
1283 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1284 memset(&cf2, 0, sizeof(cf2));
1285 cf2.cbSize = sizeof(cf2);
1286 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1287 ok(cf2.sSpacing == 10, "got %d\n", cf2.sSpacing);
1288
1289 /* show that wWeight is at the correct offset in CHARFORMAT2W */
1290 memset(&cfW, 0, sizeof(cfW));
1291 cfW.cbSize = sizeof(cfW);
1292 cfW.dwMask = CFM_WEIGHT;
1293 cfW.wWeight = 100;
1294 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfW);
1295 memset(&cfW, 0, sizeof(cfW));
1296 cfW.cbSize = sizeof(cfW);
1297 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfW);
1298 ok(cfW.wWeight == 100, "got %d\n", cfW.wWeight);
1299
1300 memset(&cfW, 0, sizeof(cfW));
1301 cfW.cbSize = sizeof(cfW);
1302 cfW.dwMask = CFM_SPACING;
1303 cfW.sSpacing = 10;
1304 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfW);
1305 memset(&cfW, 0, sizeof(cfW));
1306 cfW.cbSize = sizeof(cfW);
1307 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfW);
1308 ok(cfW.sSpacing == 10, "got %d\n", cfW.sSpacing);
1309
1310 /* test CFE_UNDERLINE and bUnderlineType interaction */
1311 /* clear bold, italic */
1312 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
1313 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1314 cf2.cbSize = sizeof(CHARFORMAT2A);
1315 cf2.dwMask = CFM_BOLD | CFM_ITALIC;
1316 cf2.dwEffects = 0;
1317 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1318
1319 /* check CFE_UNDERLINE is clear and bUnderlineType is CFU_UNDERLINE */
1320 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1321 cf2.cbSize = sizeof(CHARFORMAT2A);
1322 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1324 "got %08lx\n", cf2.dwMask);
1325 ok(!(cf2.dwEffects & CFE_UNDERLINE), "got %08lx\n", cf2.dwEffects);
1326 ok(cf2.bUnderlineType == CFU_UNDERLINE, "got %x\n", cf2.bUnderlineType);
1327
1328 /* simply touching bUnderlineType will toggle CFE_UNDERLINE */
1331 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1332 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1333 cf2.cbSize = sizeof(CHARFORMAT2A);
1334 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1336 "got %08lx\n", cf2.dwMask);
1337 ok(cf2.dwEffects & CFE_UNDERLINE, "got %08lx\n", cf2.dwEffects);
1338 ok(cf2.bUnderlineType == CFU_UNDERLINE, "got %x\n", cf2.bUnderlineType);
1339
1340 /* setting bUnderline to CFU_UNDERLINENONE clears CFE_UNDERLINE */
1343 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1344 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1345 cf2.cbSize = sizeof(CHARFORMAT2A);
1346 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1348 "got %08lx\n", cf2.dwMask);
1349 ok(!(cf2.dwEffects & CFE_UNDERLINE), "got %08lx\n", cf2.dwEffects);
1350 ok(cf2.bUnderlineType == CFU_UNDERLINENONE, "got %x\n", cf2.bUnderlineType);
1351
1352 /* another underline type also sets CFE_UNDERLINE */
1355 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1356 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1357 cf2.cbSize = sizeof(CHARFORMAT2A);
1358 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1360 "got %08lx\n", cf2.dwMask);
1361 ok(cf2.dwEffects & CFE_UNDERLINE, "got %08lx\n", cf2.dwEffects);
1362 ok(cf2.bUnderlineType == CFU_UNDERLINEDOUBLE, "got %x\n", cf2.bUnderlineType);
1363
1364 /* However explicitly clearing CFE_UNDERLINE results in it remaining cleared */
1367 cf2.dwEffects = 0;
1368 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1369 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1370 cf2.cbSize = sizeof(CHARFORMAT2A);
1371 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1373 "got %08lx\n", cf2.dwMask);
1374 ok(!(cf2.dwEffects & CFE_UNDERLINE), "got %08lx\n", cf2.dwEffects);
1375 ok(cf2.bUnderlineType == CFU_UNDERLINEDOUBLE, "got %x\n", cf2.bUnderlineType);
1376
1377 /* And turing it back on again by just setting CFE_UNDERLINE */
1378 cf2.dwMask = CFM_UNDERLINE;
1380 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1381 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1382 cf2.cbSize = sizeof(CHARFORMAT2A);
1383 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1385 "got %08lx\n", cf2.dwMask);
1386 ok(cf2.dwEffects & CFE_UNDERLINE, "got %08lx\n", cf2.dwEffects);
1387 ok(cf2.bUnderlineType == CFU_UNDERLINEDOUBLE, "got %x\n", cf2.bUnderlineType);
1388
1389 /* Check setting CFM_ALL2/CFM_EFFECTS2 in CHARFORMAT(A/W). */
1390 memset(&cf1a, 0, sizeof(CHARFORMATA));
1391 memset(&cf1w, 0, sizeof(CHARFORMATW));
1392 cf1a.cbSize = sizeof(CHARFORMATA);
1393 cf1w.cbSize = sizeof(CHARFORMATW);
1394 cf1a.dwMask = cf1w.dwMask = CFM_ALL2;
1395 cf1a.dwEffects = cf1w.dwEffects = CFM_EFFECTS2;
1396 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf1a);
1397 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf1a);
1398 /* flags only valid for CHARFORMAT2 should be masked out */
1399 ok((cf1a.dwMask & (CFM_ALL2 & ~CFM_ALL)) == 0, "flags were not masked out\n");
1400 ok((cf1a.dwEffects & (CFM_EFFECTS2 & ~CFM_EFFECTS)) == 0, "flags were not masked out\n");
1401 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf1w);
1402 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf1w);
1403 ok((cf1w.dwMask & (CFM_ALL2 & ~CFM_ALL)) == 0, "flags were not masked out\n");
1404 ok((cf1w.dwEffects & (CFM_EFFECTS2 & ~CFM_EFFECTS)) == 0, "flags were not masked out\n");
1405
1406 DestroyWindow(hwndRichEdit);
1407}
1408
1409/* As the clipboard is a shared resource, it happens (on Windows) that the WM_PASTE
1410 * is a no-op; likely because another app has opened the clipboard for inspection.
1411 * In this case, WM_PASTE does nothing, and doesn't return an error code.
1412 * So retry pasting a couple of times.
1413 * Don't use this function if the paste operation shouldn't change the content of the
1414 * editor (clipboard is empty without selection, edit control is read only...).
1415 * Also impact on undo stack is not managed.
1416 */
1417#define send_paste(a) _send_paste(__LINE__, (a))
1418static void _send_paste(unsigned int line, HWND wnd)
1419{
1420 int retries;
1421
1423
1424 for (retries = 0; retries < 7; retries++)
1425 {
1426 if (retries) Sleep(15);
1427 SendMessageA(wnd, WM_PASTE, 0, 0);
1428 if (SendMessageA(wnd, EM_GETMODIFY, 0, 0)) return;
1429 }
1430 ok_(__FILE__, line)(0, "Failed to paste clipboard content\n");
1431 {
1432 char classname[256];
1433 HWND clipwnd = GetOpenClipboardWindow();
1434 /* Provide a hint as to the source of interference:
1435 * - The class name would typically be CLIPBRDWNDCLASS if the
1436 * clipboard was opened by a Windows application using the
1437 * ole32 API.
1438 * - And it would be __wine_clipboard_manager if it was opened in
1439 * response to a native application.
1440 */
1442 trace("%p (%s) opened the clipboard\n", clipwnd, classname);
1443 }
1444}
1445
1446static void test_EM_SETTEXTMODE(void)
1447{
1448 HWND hwndRichEdit = new_richedit(NULL);
1449 CHARFORMAT2A cf2, cf2test;
1450 unsigned int len;
1451 CHARRANGE cr;
1452 int rc = 0;
1453
1454 /*Attempt to use mutually exclusive modes*/
1456 ok(rc == E_INVALIDARG,
1457 "EM_SETTEXTMODE: using mutually exclusive mode flags - returned: %x\n", rc);
1458
1459 /*Test that EM_SETTEXTMODE fails if text exists within the control*/
1460 /*Insert text into the control*/
1461
1462 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1463
1464 /*Attempt to change the control to plain text mode*/
1465 rc = SendMessageA(hwndRichEdit, EM_SETTEXTMODE, (WPARAM)TM_PLAINTEXT, 0);
1466 ok(rc == E_UNEXPECTED,
1467 "EM_SETTEXTMODE: changed text mode in control containing text - returned: %x\n", rc);
1468
1469 /*Test that EM_SETTEXTMODE does not allow rich edit text to be pasted.
1470 If rich text is pasted, it should have the same formatting as the rest
1471 of the text in the control*/
1472
1473 /*Italicize the text
1474 *NOTE: If the default text was already italicized, the test will simply
1475 reverse; in other words, it will copy a regular "wine" into a plain
1476 text window that uses an italicized format*/
1477 cf2.cbSize = sizeof(CHARFORMAT2A);
1478 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2);
1479
1480 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
1481 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
1482
1483 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
1484 ok(rc == 0, "Text marked as modified, expected not modified!\n");
1485
1486 /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine;
1487 however, SCF_ALL has been implemented*/
1488 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2);
1489 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
1490
1491 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
1492 ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc);
1493
1494 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1495
1496 /*Select the string "wine"*/
1497 cr.cpMin = 0;
1498 cr.cpMax = 4;
1499 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1500
1501 /*Copy the italicized "wine" to the clipboard*/
1502 SendMessageA(hwndRichEdit, WM_COPY, 0, 0);
1503
1504 /*Reset the formatting to default*/
1505 cf2.dwEffects = CFE_ITALIC^cf2.dwEffects;
1506 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2);
1507 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
1508
1509 /*Clear the text in the control*/
1510 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
1511
1512 /*Switch to Plain Text Mode*/
1513 rc = SendMessageA(hwndRichEdit, EM_SETTEXTMODE, (WPARAM)TM_PLAINTEXT, 0);
1514 ok(rc == 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control: returned: %d\n", rc);
1515
1516 /*Input "wine" again in normal format*/
1517 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1518
1519 /*Paste the italicized "wine" into the control*/
1520 send_paste(hwndRichEdit);
1521
1522 len = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
1523 ok(len == 8 /*winewine*/, "Unexpected text length %u\n", len);
1524
1525 /*Select a character from the first "wine" string*/
1526 cr.cpMin = 2;
1527 cr.cpMax = 3;
1528 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1529
1530 /*Retrieve its formatting*/
1532
1533 /*Select a character from the second "wine" string*/
1534 cr.cpMin = 5;
1535 cr.cpMax = 6;
1536 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1537
1538 /*Retrieve its formatting*/
1539 cf2test.cbSize = sizeof(CHARFORMAT2A);
1540 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2test);
1541
1542 /*Compare the two formattings*/
1543 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
1544 "two formats found in plain text mode - cf2.dwEffects: %lx cf2test.dwEffects: %lx\n",
1545 cf2.dwEffects, cf2test.dwEffects);
1546 /*Test TM_RICHTEXT by: switching back to Rich Text mode
1547 printing "wine" in the current format(normal)
1548 pasting "wine" from the clipboard(italicized)
1549 comparing the two formats(should differ)*/
1550
1551 /*Attempt to switch with text in control*/
1552 rc = SendMessageA(hwndRichEdit, EM_SETTEXTMODE, (WPARAM)TM_RICHTEXT, 0);
1553 ok(rc != 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc);
1554
1555 /*Clear control*/
1556 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
1557
1558 /*Switch into Rich Text mode*/
1559 rc = SendMessageA(hwndRichEdit, EM_SETTEXTMODE, (WPARAM)TM_RICHTEXT, 0);
1560 ok(rc == 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc);
1561
1562 /*Print "wine" in normal formatting into the control*/
1563 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1564
1565 /*Paste italicized "wine" into the control*/
1566 send_paste(hwndRichEdit);
1567
1568 /*Select text from the first "wine" string*/
1569 cr.cpMin = 1;
1570 cr.cpMax = 3;
1571 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1572
1573 /*Retrieve its formatting*/
1575
1576 /*Select text from the second "wine" string*/
1577 cr.cpMin = 6;
1578 cr.cpMax = 7;
1579 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1580
1581 /*Retrieve its formatting*/
1582 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2test);
1583
1584 /*Test that the two formattings are not the same*/
1585 todo_wine ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects != cf2test.dwEffects),
1586 "expected different formats - cf2.dwMask: %lx, cf2test.dwMask: %lx, cf2.dwEffects: %lx, cf2test.dwEffects: %lx\n",
1587 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
1588
1589 DestroyWindow(hwndRichEdit);
1590}
1591
1592static void test_SETPARAFORMAT(void)
1593{
1594 HWND hwndRichEdit = new_richedit(NULL);
1596 HRESULT ret;
1597 LONG expectedMask = PFM_ALL2 & ~PFM_TABLEROWDELIMITER;
1598 fmt.cbSize = sizeof(PARAFORMAT2);
1599 fmt.dwMask = PFM_ALIGNMENT;
1600 fmt.wAlignment = PFA_LEFT;
1601
1602 ret = SendMessageA(hwndRichEdit, EM_SETPARAFORMAT, 0, (LPARAM)&fmt);
1603 ok(ret != 0, "expected non-zero got %ld\n", ret);
1604
1605 fmt.cbSize = sizeof(PARAFORMAT2);
1606 fmt.dwMask = -1;
1607 ret = SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt);
1608 /* Ignore the PFM_TABLEROWDELIMITER bit because it changes
1609 * between richedit different native builds of riched20.dll
1610 * used on different Windows versions. */
1611 ret &= ~PFM_TABLEROWDELIMITER;
1612 fmt.dwMask &= ~PFM_TABLEROWDELIMITER;
1613
1614 ok(ret == expectedMask, "expected %lx got %lx\n", expectedMask, ret);
1615 ok(fmt.dwMask == expectedMask, "expected %lx got %lx\n", expectedMask, fmt.dwMask);
1616
1617 /* Test some other paraformat field defaults */
1618 ok( fmt.wNumbering == 0, "got %d\n", fmt.wNumbering );
1619 ok( fmt.wNumberingStart == 0, "got %d\n", fmt.wNumberingStart );
1620 ok( fmt.wNumberingStyle == 0, "got %04x\n", fmt.wNumberingStyle );
1621 ok( fmt.wNumberingTab == 0, "got %d\n", fmt.wNumberingTab );
1622
1623 DestroyWindow(hwndRichEdit);
1624}
1625
1626static void test_TM_PLAINTEXT(void)
1627{
1628 /*Tests plain text properties*/
1629
1630 HWND hwndRichEdit = new_richedit(NULL);
1631 CHARFORMAT2A cf2, cf2test;
1632 CHARRANGE cr;
1633 int rc = 0;
1634
1635 /*Switch to plain text mode*/
1636
1637 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
1638 SendMessageA(hwndRichEdit, EM_SETTEXTMODE, TM_PLAINTEXT, 0);
1639
1640 /*Fill control with text*/
1641
1642 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"Is Wine an emulator? No it's not");
1643
1644 /*Select some text and bold it*/
1645
1646 cr.cpMin = 10;
1647 cr.cpMax = 20;
1648 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1649 cf2.cbSize = sizeof(CHARFORMAT2A);
1650 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2);
1651
1652 cf2.dwMask = CFM_BOLD | cf2.dwMask;
1653 cf2.dwEffects = CFE_BOLD ^ cf2.dwEffects;
1654
1655 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1656 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
1657
1658 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_WORD | SCF_SELECTION, (LPARAM)&cf2);
1659 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
1660
1661 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2);
1662 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
1663
1664 /*Get the formatting of those characters*/
1665
1666 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1667
1668 /*Get the formatting of some other characters*/
1669 cf2test.cbSize = sizeof(CHARFORMAT2A);
1670 cr.cpMin = 21;
1671 cr.cpMax = 30;
1672 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1673 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2test);
1674
1675 /*Test that they are the same as plain text allows only one formatting*/
1676
1677 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
1678 "two selections' formats differ - cf2.dwMask: %lx, cf2test.dwMask %lx, cf2.dwEffects: %lx, cf2test.dwEffects: %lx\n",
1679 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
1680
1681 /*Fill the control with a "wine" string, which when inserted will be bold*/
1682
1683 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1684
1685 /*Copy the bolded "wine" string*/
1686
1687 cr.cpMin = 0;
1688 cr.cpMax = 4;
1689 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1690 SendMessageA(hwndRichEdit, WM_COPY, 0, 0);
1691
1692 /*Swap back to rich text*/
1693
1694 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
1695 SendMessageA(hwndRichEdit, EM_SETTEXTMODE, TM_RICHTEXT, 0);
1696
1697 /*Set the default formatting to bold italics*/
1698
1699 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2);
1700 cf2.dwMask |= CFM_ITALIC;
1701 cf2.dwEffects ^= CFE_ITALIC;
1702 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2);
1703 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
1704
1705 /*Set the text in the control to "wine", which will be bold and italicized*/
1706
1707 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1708
1709 /*Paste the plain text "wine" string, which should take the insert
1710 formatting, which at the moment is bold italics*/
1711
1712 send_paste(hwndRichEdit);
1713
1714 /*Select the first "wine" string and retrieve its formatting*/
1715
1716 cr.cpMin = 1;
1717 cr.cpMax = 3;
1718 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1719 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1720
1721 /*Select the second "wine" string and retrieve its formatting*/
1722
1723 cr.cpMin = 5;
1724 cr.cpMax = 7;
1725 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1726 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2test);
1727
1728 /*Compare the two formattings. They should be the same.*/
1729
1730 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
1731 "Copied text retained formatting - cf2.dwMask: %lx, cf2test.dwMask: %lx, cf2.dwEffects: %lx, cf2test.dwEffects: %lx\n",
1732 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
1733 DestroyWindow(hwndRichEdit);
1734}
1735
1736static void test_WM_GETTEXT(void)
1737{
1738 HWND hwndRichEdit = new_richedit(NULL);
1739 static const char text[] = "Hello. My name is RichEdit!";
1740 static const char text2[] = "Hello. My name is RichEdit!\r";
1741 static const char text2_after[] = "Hello. My name is RichEdit!\r\n";
1742 char buffer[1024] = {0};
1743 int result;
1744
1745 /* Baseline test with normal-sized buffer */
1746 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
1747 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
1749 "WM_GETTEXT returned %d, expected %d\n", result, lstrlenA(buffer));
1750 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
1752 ok(result == 0,
1753 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
1754
1755 /* Test for returned value of WM_GETTEXTLENGTH */
1756 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
1757 ok(result == lstrlenA(text),
1758 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
1759 result, lstrlenA(text));
1760
1761 /* Test for behavior in overflow case */
1762 memset(buffer, 0, 1024);
1763 result = SendMessageA(hwndRichEdit, WM_GETTEXT, strlen(text), (LPARAM)buffer);
1764 ok(result == 0 ||
1765 result == lstrlenA(text) - 1, /* XP, win2k3 */
1766 "WM_GETTEXT returned %d, expected 0 or %d\n", result, lstrlenA(text) - 1);
1768 if (result)
1769 result = strncmp(buffer, text, lstrlenA(text) - 1); /* XP, win2k3 */
1770 ok(result == 0,
1771 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
1772
1773 /* Baseline test with normal-sized buffer and carriage return */
1774 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
1775 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
1777 "WM_GETTEXT returned %d, expected %d\n", result, lstrlenA(buffer));
1778 result = strcmp(buffer,text2_after);
1779 ok(result == 0,
1780 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
1781
1782 /* Test for returned value of WM_GETTEXTLENGTH */
1783 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
1784 ok(result == lstrlenA(text2_after),
1785 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
1786 result, lstrlenA(text2_after));
1787
1788 /* Test for behavior of CRLF conversion in case of overflow */
1789 memset(buffer, 0, 1024);
1790 result = SendMessageA(hwndRichEdit, WM_GETTEXT, strlen(text2), (LPARAM)buffer);
1791 ok(result == 0 ||
1792 result == lstrlenA(text2) - 1, /* XP, win2k3 */
1793 "WM_GETTEXT returned %d, expected 0 or %d\n", result, lstrlenA(text2) - 1);
1794 result = strcmp(buffer,text2);
1795 if (result)
1796 result = strncmp(buffer, text2, lstrlenA(text2) - 1); /* XP, win2k3 */
1797 ok(result == 0,
1798 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
1799
1800 DestroyWindow(hwndRichEdit);
1801}
1802
1803static void test_EM_GETTEXTRANGE(void)
1804{
1805 HWND hwndRichEdit = new_richedit(NULL);
1806 const char * text1 = "foo bar\r\nfoo bar";
1807 const char * text2 = "foo bar\rfoo bar";
1808 const char * expect = "bar\rfoo";
1809 char buffer[1024] = {0};
1811 TEXTRANGEA textRange;
1812
1813 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
1814
1815 textRange.lpstrText = buffer;
1816 textRange.chrg.cpMin = 4;
1817 textRange.chrg.cpMax = 11;
1818 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1819 ok(result == 7, "EM_GETTEXTRANGE returned %Id\n", result);
1820 ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1821
1822 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
1823
1824 textRange.lpstrText = buffer;
1825 textRange.chrg.cpMin = 4;
1826 textRange.chrg.cpMax = 11;
1827 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1828 ok(result == 7, "EM_GETTEXTRANGE returned %Id\n", result);
1829 ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1830
1831 /* cpMax of text length is used instead of -1 in this case */
1832 textRange.lpstrText = buffer;
1833 textRange.chrg.cpMin = 0;
1834 textRange.chrg.cpMax = -1;
1835 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1836 ok(result == strlen(text2), "EM_GETTEXTRANGE returned %Id\n", result);
1837 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1838
1839 /* cpMin < 0 causes no text to be copied, and 0 to be returned */
1840 textRange.lpstrText = buffer;
1841 textRange.chrg.cpMin = -1;
1842 textRange.chrg.cpMax = 1;
1843 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1844 ok(result == 0, "EM_GETTEXTRANGE returned %Id\n", result);
1845 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1846
1847 /* cpMax of -1 is not replaced with text length if cpMin != 0 */
1848 textRange.lpstrText = buffer;
1849 textRange.chrg.cpMin = 1;
1850 textRange.chrg.cpMax = -1;
1851 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1852 ok(result == 0, "EM_GETTEXTRANGE returned %Id\n", result);
1853 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1854
1855 /* no end character is copied if cpMax - cpMin < 0 */
1856 textRange.lpstrText = buffer;
1857 textRange.chrg.cpMin = 5;
1858 textRange.chrg.cpMax = 5;
1859 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1860 ok(result == 0, "EM_GETTEXTRANGE returned %Id\n", result);
1861 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1862
1863 /* cpMax of text length is used if cpMax > text length*/
1864 textRange.lpstrText = buffer;
1865 textRange.chrg.cpMin = 0;
1866 textRange.chrg.cpMax = 1000;
1867 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1868 ok(result == strlen(text2), "EM_GETTEXTRANGE returned %Id\n", result);
1869 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1870
1871 /* Test with multibyte character */
1872 if (!is_lang_japanese)
1873 skip("Skip multibyte character tests on non-Japanese platform\n");
1874 else
1875 {
1876 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk");
1877 textRange.chrg.cpMin = 4;
1878 textRange.chrg.cpMax = 8;
1879 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1880 ok(result == 5, "EM_GETTEXTRANGE returned %Id\n", result);
1881 ok(!strcmp("ef\x8e\xf0g", buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1882 }
1883
1884 DestroyWindow(hwndRichEdit);
1885}
1886
1887static void test_EM_GETSELTEXT(void)
1888{
1889 HWND hwndRichEdit = new_richedit(NULL);
1890 const char * text1 = "foo bar\r\nfoo bar";
1891 const char * text2 = "foo bar\rfoo bar";
1892 const char * expect = "bar\rfoo";
1893 char buffer[1024] = {0};
1895 BOOL bad_getsel;
1896 DWORD gle;
1897
1898 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
1899 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
1900 SetLastError(0xdeadbeef);
1901 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
1902 gle = GetLastError();
1903 ok((result > 0 && gle == 0xdeadbeef) ||
1904 broken(result == 0 && gle == ERROR_INVALID_PARAMETER /* Hindi */),
1905 "EM_GETSELTEXT returned %Id gle=%lu\n", result, gle);
1906 bad_getsel = (gle != 0xdeadbeef);
1907 if (bad_getsel)
1908 trace("EM_GETSELTEXT is broken, some tests will be ignored\n");
1909
1910 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
1911
1912 SendMessageA(hwndRichEdit, EM_SETSEL, 4, 11);
1913 SetLastError(0xdeadbeef);
1914 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
1915 gle = GetLastError();
1916 ok(result == 7 || broken(bad_getsel && result == 0),
1917 "EM_GETSELTEXT returned %Id gle=%lu\n", result, gle);
1918 ok(!strcmp(expect, buffer) || broken(bad_getsel && !*buffer),
1919 "EM_GETSELTEXT filled %s gle=%lu\n", buffer, gle);
1920
1921 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
1922
1923 SendMessageA(hwndRichEdit, EM_SETSEL, 4, 11);
1924 SetLastError(0xdeadbeef);
1925 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
1926 ok(result == 7 || broken(bad_getsel && result == 0),
1927 "EM_GETSELTEXT returned %Id gle=%lu\n", result, gle);
1928 ok(!strcmp(expect, buffer) || broken(bad_getsel && !*buffer),
1929 "EM_GETSELTEXT filled %s gle=%lu\n", buffer, gle);
1930
1931 /* Test with multibyte character */
1932 if (!is_lang_japanese)
1933 skip("Skip multibyte character tests on non-Japanese platform\n");
1934 else
1935 {
1936 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk");
1937 SendMessageA(hwndRichEdit, EM_SETSEL, 4, 8);
1938 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
1939 ok(result == 5, "EM_GETSELTEXT returned %Id\n", result);
1940 ok(!strcmp("ef\x8e\xf0g", buffer), "EM_GETSELTEXT filled %s\n", buffer);
1941 }
1942
1943 DestroyWindow(hwndRichEdit);
1944}
1945
1946/* FIXME: need to test unimplemented options and robustly test wparam */
1947static void test_EM_SETOPTIONS(void)
1948{
1949 HWND hwndRichEdit;
1950 static const char text[] = "Hello. My name is RichEdit!";
1951 char buffer[1024] = {0};
1952 DWORD dwStyle, options, oldOptions;
1956
1957 /* Test initial options. */
1959 0, 0, 200, 60, NULL, NULL,
1961 ok(hwndRichEdit != NULL, "class: %s, error: %d\n",
1963 options = SendMessageA(hwndRichEdit, EM_GETOPTIONS, 0, 0);
1964 ok(options == 0, "Incorrect initial options %lx\n", options);
1965 DestroyWindow(hwndRichEdit);
1966
1967 hwndRichEdit = CreateWindowA(RICHEDIT_CLASS20A, NULL,
1969 0, 0, 200, 60, NULL, NULL,
1971 ok(hwndRichEdit != NULL, "class: %s, error: %d\n",
1973 disable_beep( hwndRichEdit );
1974 options = SendMessageA(hwndRichEdit, EM_GETOPTIONS, 0, 0);
1975 /* WS_[VH]SCROLL cause the ECO_AUTO[VH]SCROLL options to be set */
1977 "Incorrect initial options %lx\n", options);
1978
1979 /* NEGATIVE TESTING - NO OPTIONS SET */
1980 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
1981 SendMessageA(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, 0);
1982
1983 /* testing no readonly by sending 'a' to the control*/
1984 SendMessageA(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
1985 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
1986 ok(buffer[0]=='a',
1987 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text, buffer);
1988 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
1989
1990 /* READONLY - sending 'a' to the control */
1991 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
1993 SendMessageA(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
1994 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
1995 ok(buffer[0]==text[0],
1996 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer);
1997
1998 /* EM_SETOPTIONS changes the window style, but changing the
1999 * window style does not change the options. */
2000 dwStyle = GetWindowLongA(hwndRichEdit, GWL_STYLE);
2001 ok(dwStyle & ES_READONLY, "Readonly style not set by EM_SETOPTIONS\n");
2002 SetWindowLongA(hwndRichEdit, GWL_STYLE, dwStyle & ~ES_READONLY);
2003 options = SendMessageA(hwndRichEdit, EM_GETOPTIONS, 0, 0);
2004 ok(options & ES_READONLY, "Readonly option set by SetWindowLong\n");
2005 /* Confirm that the text is still read only. */
2006 SendMessageA(hwndRichEdit, WM_CHAR, 'a', ('a' << 16) | 0x0001);
2007 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
2008 ok(buffer[0]==text[0],
2009 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer);
2010
2011 oldOptions = options;
2012 SetWindowLongA(hwndRichEdit, GWL_STYLE, dwStyle|optionStyles);
2013 options = SendMessageA(hwndRichEdit, EM_GETOPTIONS, 0, 0);
2014 ok(options == oldOptions,
2015 "Options set by SetWindowLong (%lx -> %lx)\n", oldOptions, options);
2016
2017 DestroyWindow(hwndRichEdit);
2018}
2019
2020static BOOL check_CFE_LINK_selection(HWND hwnd, int sel_start, int sel_end)
2021{
2022 CHARFORMAT2A text_format;
2023 text_format.cbSize = sizeof(text_format);
2024 SendMessageA(hwnd, EM_SETSEL, sel_start, sel_end);
2026 return (text_format.dwEffects & CFE_LINK) != 0;
2027}
2028
2029static void check_CFE_LINK_rcvd(HWND hwnd, BOOL is_url, const char * url)
2030{
2031 BOOL link_present = FALSE;
2032
2033 link_present = check_CFE_LINK_selection(hwnd, 0, 1);
2034 if (is_url)
2035 { /* control text is url; should get CFE_LINK */
2036 ok(link_present, "URL Case: CFE_LINK not set for [%s].\n", url);
2037 }
2038 else
2039 {
2040 ok(!link_present, "Non-URL Case: CFE_LINK set for [%s].\n", url);
2041 }
2042}
2043
2045 return new_window("Static", 0, parent);
2046}
2047
2048static void test_EM_AUTOURLDETECT(void)
2049{
2050 /* DO NOT change the properties of the first two elements. To shorten the
2051 tests, all tests after WM_SETTEXT test just the first two elements -
2052 one non-URL and one URL */
2053 struct urls_s {
2054 const char *text;
2055 BOOL is_url;
2056 } urls[12] = {
2057 {"winehq.org", FALSE},
2058 {"http://www.winehq.org", TRUE},
2059 {"http//winehq.org", FALSE},
2060 {"ww.winehq.org", FALSE},
2061 {"www.winehq.org", TRUE},
2062 {"ftp://192.168.1.1", TRUE},
2063 {"ftp//192.168.1.1", FALSE},
2064 {"mailto:your@email.com", TRUE},
2065 {"prospero:prosperoserver", TRUE},
2066 {"telnet:test", TRUE},
2067 {"news:newserver", TRUE},
2068 {"wais:waisserver", TRUE}
2069 };
2070
2071 int i, j;
2072 int urlRet=-1;
2073 HWND hwndRichEdit, parent;
2074
2075 /* All of the following should cause the URL to be detected */
2076 const char * templates_delim[] = {
2077 "This is some text with X on it",
2078 "This is some text with (X) on it",
2079 "This is some text with X\r on it",
2080 "This is some text with ---X--- on it",
2081 "This is some text with \"X\" on it",
2082 "This is some text with 'X' on it",
2083 "This is some text with 'X' on it",
2084 "This is some text with :X: on it",
2085
2086 "This text ends with X",
2087
2088 "This is some text with X) on it",
2089 "This is some text with X--- on it",
2090 "This is some text with X\" on it",
2091 "This is some text with X' on it",
2092 "This is some text with X: on it",
2093
2094 "This is some text with (X on it",
2095 "This is some text with \rX on it",
2096 "This is some text with ---X on it",
2097 "This is some text with \"X on it",
2098 "This is some text with 'X on it",
2099 "This is some text with :X on it",
2100 };
2101 /* None of these should cause the URL to be detected */
2102 const char * templates_non_delim[] = {
2103 "This is some text with |X| on it",
2104 "This is some text with *X* on it",
2105 "This is some text with /X/ on it",
2106 "This is some text with +X+ on it",
2107 "This is some text with %X% on it",
2108 "This is some text with #X# on it",
2109 "This is some text with @X@ on it",
2110 "This is some text with \\X\\ on it",
2111 "This is some text with |X on it",
2112 "This is some text with *X on it",
2113 "This is some text with /X on it",
2114 "This is some text with +X on it",
2115 "This is some text with %X on it",
2116 "This is some text with #X on it",
2117 "This is some text with @X on it",
2118 "This is some text with \\X on it",
2119 "This is some text with _X on it",
2120 };
2121 /* All of these cause the URL detection to be extended by one more byte,
2122 thus demonstrating that the tested character is considered as part
2123 of the URL. */
2124 const char * templates_xten_delim[] = {
2125 "This is some text with X| on it",
2126 "This is some text with X* on it",
2127 "This is some text with X/ on it",
2128 "This is some text with X+ on it",
2129 "This is some text with X% on it",
2130 "This is some text with X# on it",
2131 "This is some text with X@ on it",
2132 "This is some text with X\\ on it",
2133 "This is some text with X_ on it",
2134 };
2135 /* These delims act as neutral breaks. Whether the url is ended
2136 or not depends on the next non-neutral character. We'll test
2137 with Y unchanged, in which case the url should include the
2138 deliminator and the Y. We'll also test with the Y changed
2139 to a space, in which case the url stops before the
2140 deliminator. */
2141 const char * templates_neutral_delim[] = {
2142 "This is some text with X-Y on it",
2143 "This is some text with X--Y on it",
2144 "This is some text with X!Y on it",
2145 "This is some text with X[Y on it",
2146 "This is some text with X]Y on it",
2147 "This is some text with X{Y on it",
2148 "This is some text with X}Y on it",
2149 "This is some text with X(Y on it",
2150 "This is some text with X)Y on it",
2151 "This is some text with X\"Y on it",
2152 "This is some text with X;Y on it",
2153 "This is some text with X:Y on it",
2154 "This is some text with X'Y on it",
2155 "This is some text with X?Y on it",
2156 "This is some text with X<Y on it",
2157 "This is some text with X>Y on it",
2158 "This is some text with X.Y on it",
2159 "This is some text with X,Y on it",
2160 };
2161 char buffer[1024];
2162
2164 hwndRichEdit = new_richedit(parent);
2165 /* Try and pass EM_AUTOURLDETECT some test wParam values */
2166 urlRet=SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
2167 ok(urlRet==0, "Good wParam: urlRet is: %d\n", urlRet);
2168 urlRet=SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, 1, 0);
2169 ok(urlRet==0, "Good wParam2: urlRet is: %d\n", urlRet);
2170 /* Windows returns -2147024809 (0x80070057) on bad wParam values */
2171 urlRet=SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, 8, 0);
2172 ok(urlRet==E_INVALIDARG, "Bad wParam: urlRet is: %d\n", urlRet);
2173 urlRet=SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, (WPARAM)"h", (LPARAM)"h");
2174 ok(urlRet==E_INVALIDARG, "Bad wParam2: urlRet is: %d\n", urlRet);
2175 /* for each url, check the text to see if CFE_LINK effect is present */
2176 for (i = 0; i < ARRAY_SIZE(urls); i++) {
2177
2178 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
2179 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)urls[i].text);
2180 check_CFE_LINK_rcvd(hwndRichEdit, FALSE, urls[i].text);
2181
2182 /* Link detection should happen immediately upon WM_SETTEXT */
2183 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2184 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)urls[i].text);
2185 check_CFE_LINK_rcvd(hwndRichEdit, urls[i].is_url, urls[i].text);
2186 }
2187 DestroyWindow(hwndRichEdit);
2188
2189 /* Test detection of URLs within normal text - WM_SETTEXT case. */
2190 for (i = 0; i < ARRAY_SIZE(urls); i++) {
2191 hwndRichEdit = new_richedit(parent);
2192
2193 for (j = 0; j < ARRAY_SIZE(templates_delim); j++) {
2194 char * at_pos;
2195 int at_offset;
2196 int end_offset;
2197
2198 at_pos = strchr(templates_delim[j], 'X');
2199 at_offset = at_pos - templates_delim[j];
2200 memcpy(buffer, templates_delim[j], at_offset);
2201 buffer[at_offset] = '\0';
2202 strcat(buffer, urls[i].text);
2203 strcat(buffer, templates_delim[j] + at_offset + 1);
2204 end_offset = at_offset + strlen(urls[i].text);
2205
2206 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2207 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer);
2208
2209 /* This assumes no templates start with the URL itself, and that they
2210 have at least two characters before the URL text */
2211 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2212 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2213 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2214 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2215 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2216 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2217
2218 if (urls[i].is_url)
2219 {
2220 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2221 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2222 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2223 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2224 }
2225 else
2226 {
2227 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2228 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2229 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2230 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2231 }
2232 if (buffer[end_offset] != '\0')
2233 {
2234 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2235 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2236 if (buffer[end_offset +1] != '\0')
2237 {
2238 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2239 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2240 }
2241 }
2242 }
2243
2244 for (j = 0; j < ARRAY_SIZE(templates_non_delim); j++) {
2245 char * at_pos;
2246 int at_offset;
2247 int end_offset;
2248
2249 at_pos = strchr(templates_non_delim[j], 'X');
2250 at_offset = at_pos - templates_non_delim[j];
2251 memcpy(buffer, templates_non_delim[j], at_offset);
2252 buffer[at_offset] = '\0';
2253 strcat(buffer, urls[i].text);
2254 strcat(buffer, templates_non_delim[j] + at_offset + 1);
2255 end_offset = at_offset + strlen(urls[i].text);
2256
2257 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2258 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer);
2259
2260 /* This assumes no templates start with the URL itself, and that they
2261 have at least two characters before the URL text */
2262 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2263 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2264 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2265 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2266 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2267 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2268
2269 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2270 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2271 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2272 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2273 if (buffer[end_offset] != '\0')
2274 {
2275 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2276 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2277 if (buffer[end_offset +1] != '\0')
2278 {
2279 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2280 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2281 }
2282 }
2283 }
2284
2285 for (j = 0; j < ARRAY_SIZE(templates_xten_delim); j++) {
2286 char * at_pos;
2287 int at_offset;
2288 int end_offset;
2289
2290 at_pos = strchr(templates_xten_delim[j], 'X');
2291 at_offset = at_pos - templates_xten_delim[j];
2292 memcpy(buffer, templates_xten_delim[j], at_offset);
2293 buffer[at_offset] = '\0';
2294 strcat(buffer, urls[i].text);
2295 strcat(buffer, templates_xten_delim[j] + at_offset + 1);
2296 end_offset = at_offset + strlen(urls[i].text);
2297
2298 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2299 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer);
2300
2301 /* This assumes no templates start with the URL itself, and that they
2302 have at least two characters before the URL text */
2303 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2304 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2305 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2306 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2307 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2308 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2309
2310 if (urls[i].is_url)
2311 {
2312 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2313 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2314 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2315 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2316 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2317 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer);
2318 }
2319 else
2320 {
2321 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2322 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2323 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2324 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2325 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2326 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer);
2327 }
2328 if (buffer[end_offset +1] != '\0')
2329 {
2330 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2331 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset + 2, buffer);
2332 if (buffer[end_offset +2] != '\0')
2333 {
2334 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +2, end_offset +3),
2335 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +2, end_offset +3, buffer);
2336 }
2337 }
2338 }
2339
2340 for (j = 0; j < ARRAY_SIZE(templates_neutral_delim); j++) {
2341 char * at_pos, * end_pos;
2342 int at_offset;
2343 int end_offset;
2344
2345 if (!urls[i].is_url) continue;
2346
2347 at_pos = strchr(templates_neutral_delim[j], 'X');
2348 at_offset = at_pos - templates_neutral_delim[j];
2349 memcpy(buffer, templates_neutral_delim[j], at_offset);
2350 buffer[at_offset] = '\0';
2351 strcat(buffer, urls[i].text);
2352 strcat(buffer, templates_neutral_delim[j] + at_offset + 1);
2353
2354 end_pos = strchr(buffer, 'Y');
2355 end_offset = end_pos - buffer;
2356
2357 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2358 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer);
2359
2360 /* This assumes no templates start with the URL itself, and that they
2361 have at least two characters before the URL text */
2362 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2363 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2364 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2365 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2366 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2367 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2368
2369 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2370 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2371 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2372 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2373 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2374 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer);
2375
2376 *end_pos = ' ';
2377
2378 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2379 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer);
2380
2381 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2382 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2383 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2384 "CFE_LINK set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2385 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2386 "CFE_LINK set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer);
2387 }
2388
2389 DestroyWindow(hwndRichEdit);
2390 hwndRichEdit = NULL;
2391 }
2392
2393 /* Test detection of URLs within normal text - WM_CHAR case. */
2394 /* Test only the first two URL examples for brevity */
2395 for (i = 0; i < 2; i++) {
2396 hwndRichEdit = new_richedit(parent);
2397
2398 /* Also for brevity, test only the first three delimiters */
2399 for (j = 0; j < 3; j++) {
2400 char * at_pos;
2401 int at_offset;
2402 int end_offset;
2403 int u, v;
2404
2405 at_pos = strchr(templates_delim[j], 'X');
2406 at_offset = at_pos - templates_delim[j];
2407 end_offset = at_offset + strlen(urls[i].text);
2408
2409 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2410 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
2411 for (u = 0; templates_delim[j][u]; u++) {
2412 if (templates_delim[j][u] == '\r') {
2413 simulate_typing_characters(hwndRichEdit, "\r");
2414 } else if (templates_delim[j][u] != 'X') {
2415 SendMessageA(hwndRichEdit, WM_CHAR, templates_delim[j][u], 1);
2416 } else {
2417 for (v = 0; urls[i].text[v]; v++) {
2418 SendMessageA(hwndRichEdit, WM_CHAR, urls[i].text[v], 1);
2419 }
2420 }
2421 }
2422 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2423
2424 /* This assumes no templates start with the URL itself, and that they
2425 have at least two characters before the URL text */
2426 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2427 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2428 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2429 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2430 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2431 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2432
2433 if (urls[i].is_url)
2434 {
2435 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2436 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2437 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2438 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2439 }
2440 else
2441 {
2442 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2443 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2444 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2445 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2446 }
2447 if (buffer[end_offset] != '\0')
2448 {
2449 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2450 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2451 if (buffer[end_offset +1] != '\0')
2452 {
2453 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2454 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2455 }
2456 }
2457
2458 /* The following will insert a paragraph break after the first character
2459 of the URL candidate, thus breaking the URL. It is expected that the
2460 CFE_LINK attribute should break across both pieces of the URL */
2461 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset+1, at_offset+1);
2462 simulate_typing_characters(hwndRichEdit, "\r");
2463 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2464
2465 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2466 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2467 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2468 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2469 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2470 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2471
2472 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2473 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2474 /* end_offset moved because of paragraph break */
2475 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2476 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset+1, buffer);
2477 ok(buffer[end_offset], "buffer \"%s\" ended prematurely. Is it missing a newline character?\n", buffer);
2478 if (buffer[end_offset] != 0 && buffer[end_offset+1] != '\0')
2479 {
2480 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset+1, end_offset +2),
2481 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset+1, end_offset +2, buffer);
2482 if (buffer[end_offset +2] != '\0')
2483 {
2484 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +2, end_offset +3),
2485 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +2, end_offset +3, buffer);
2486 }
2487 }
2488
2489 /* The following will remove the just-inserted paragraph break, thus
2490 restoring the URL */
2491 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset+2, at_offset+2);
2492 simulate_typing_characters(hwndRichEdit, "\b");
2493 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2494
2495 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2496 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2497 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2498 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2499 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2500 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2501
2502 if (urls[i].is_url)
2503 {
2504 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2505 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2506 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2507 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2508 }
2509 else
2510 {
2511 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2512 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2513 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2514 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2515 }
2516 if (buffer[end_offset] != '\0')
2517 {
2518 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2519 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2520 if (buffer[end_offset +1] != '\0')
2521 {
2522 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2523 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2524 }
2525 }
2526 }
2527 DestroyWindow(hwndRichEdit);
2528 hwndRichEdit = NULL;
2529 }
2530
2531 /* Test detection of URLs within normal text - EM_SETTEXTEX case. */
2532 /* Test just the first two URL examples for brevity */
2533 for (i = 0; i < 2; i++) {
2534 SETTEXTEX st;
2535
2536 hwndRichEdit = new_richedit(parent);
2537
2538 /* There are at least three ways in which EM_SETTEXTEX must cause URLs to
2539 be detected:
2540 1) Set entire text, a la WM_SETTEXT
2541 2) Set a selection of the text to the URL
2542 3) Set a portion of the text at a time, which eventually results in
2543 an URL
2544 All of them should give equivalent results
2545 */
2546
2547 /* Set entire text in one go, like WM_SETTEXT */
2548 for (j = 0; j < ARRAY_SIZE(templates_delim); j++) {
2549 char * at_pos;
2550 int at_offset;
2551 int end_offset;
2552
2553 st.codepage = CP_ACP;
2554 st.flags = ST_DEFAULT;
2555
2556 at_pos = strchr(templates_delim[j], 'X');
2557 at_offset = at_pos - templates_delim[j];
2558 memcpy(buffer, templates_delim[j], at_offset);
2559 buffer[at_offset] = '\0';
2560 strcat(buffer, urls[i].text);
2561 strcat(buffer, templates_delim[j] + at_offset + 1);
2562 end_offset = at_offset + strlen(urls[i].text);
2563
2564 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2565 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)buffer);
2566
2567 /* This assumes no templates start with the URL itself, and that they
2568 have at least two characters before the URL text */
2569 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2570 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2571 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2572 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2573 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2574 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2575
2576 if (urls[i].is_url)
2577 {
2578 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2579 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2580 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2581 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2582 }
2583 else
2584 {
2585 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2586 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2587 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2588 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2589 }
2590 if (buffer[end_offset] != '\0')
2591 {
2592 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2593 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2594 if (buffer[end_offset +1] != '\0')
2595 {
2596 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2597 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2598 }
2599 }
2600 }
2601
2602 /* Set selection with X to the URL */
2603 for (j = 0; j < ARRAY_SIZE(templates_delim); j++) {
2604 char * at_pos;
2605 int at_offset;
2606 int end_offset;
2607
2608 at_pos = strchr(templates_delim[j], 'X');
2609 at_offset = at_pos - templates_delim[j];
2610 end_offset = at_offset + strlen(urls[i].text);
2611
2612 st.codepage = CP_ACP;
2613 st.flags = ST_DEFAULT;
2614 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2615 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)templates_delim[j]);
2616 st.flags = ST_SELECTION;
2617 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1);
2618 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)urls[i].text);
2619 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2620
2621 /* This assumes no templates start with the URL itself, and that they
2622 have at least two characters before the URL text */
2623 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2624 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2625 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2626 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2627 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2628 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2629
2630 if (urls[i].is_url)
2631 {
2632 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2633 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2634 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2635 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2636 }
2637 else
2638 {
2639 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2640 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2641 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2642 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2643 }
2644 if (buffer[end_offset] != '\0')
2645 {
2646 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2647 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2648 if (buffer[end_offset +1] != '\0')
2649 {
2650 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2651 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2652 }
2653 }
2654 }
2655
2656 /* Set selection with X to the first character of the URL, then the rest */
2657 for (j = 0; j < ARRAY_SIZE(templates_delim); j++) {
2658 char * at_pos;
2659 int at_offset;
2660 int end_offset;
2661
2662 at_pos = strchr(templates_delim[j], 'X');
2663 at_offset = at_pos - templates_delim[j];
2664 end_offset = at_offset + strlen(urls[i].text);
2665
2666 strcpy(buffer, "YY");
2667 buffer[0] = urls[i].text[0];
2668
2669 st.codepage = CP_ACP;
2670 st.flags = ST_DEFAULT;
2671 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2672 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)templates_delim[j]);
2673 st.flags = ST_SELECTION;
2674 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1);
2675 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)buffer);
2676 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset+1, at_offset+2);
2677 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)(urls[i].text + 1));
2678 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2679
2680 /* This assumes no templates start with the URL itself, and that they
2681 have at least two characters before the URL text */
2682 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2683 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2684 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2685 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2686 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2687 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2688
2689 if (urls[i].is_url)
2690 {
2691 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2692 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2693 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2694 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2695 }
2696 else
2697 {
2698 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2699 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2700 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2701 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2702 }
2703 if (buffer[end_offset] != '\0')
2704 {
2705 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2706 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2707 if (buffer[end_offset +1] != '\0')
2708 {
2709 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2710 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2711 }
2712 }
2713 }
2714
2715 DestroyWindow(hwndRichEdit);
2716 hwndRichEdit = NULL;
2717 }
2718
2719 /* Test detection of URLs within normal text - EM_REPLACESEL case. */
2720 /* Test just the first two URL examples for brevity */
2721 for (i = 0; i < 2; i++) {
2722 hwndRichEdit = new_richedit(parent);
2723
2724 /* Set selection with X to the URL */
2725 for (j = 0; j < ARRAY_SIZE(templates_delim); j++) {
2726 char * at_pos;
2727 int at_offset;
2728 int end_offset;
2729
2730 at_pos = strchr(templates_delim[j], 'X');
2731 at_offset = at_pos - templates_delim[j];
2732 end_offset = at_offset + strlen(urls[i].text);
2733
2734 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2735 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)templates_delim[j]);
2736 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1);
2737 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)urls[i].text);
2738 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2739
2740 /* This assumes no templates start with the URL itself, and that they
2741 have at least two characters before the URL text */
2742 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2743 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2744 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2745 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2746 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2747 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2748
2749 if (urls[i].is_url)
2750 {
2751 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2752 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2753 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2754 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2755 }
2756 else
2757 {
2758 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2759 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2760 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2761 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2762 }
2763 if (buffer[end_offset] != '\0')
2764 {
2765 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2766 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2767 if (buffer[end_offset +1] != '\0')
2768 {
2769 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2770 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2771 }
2772 }
2773 }
2774
2775 /* Set selection with X to the first character of the URL, then the rest */
2776 for (j = 0; j < ARRAY_SIZE(templates_delim); j++) {
2777 char * at_pos;
2778 int at_offset;
2779 int end_offset;
2780
2781 at_pos = strchr(templates_delim[j], 'X');
2782 at_offset = at_pos - templates_delim[j];
2783 end_offset = at_offset + strlen(urls[i].text);
2784
2785 strcpy(buffer, "YY");
2786 buffer[0] = urls[i].text[0];
2787
2788 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2789 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)templates_delim[j]);
2790 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1);
2791 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)buffer);
2792 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset+1, at_offset+2);
2793 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)(urls[i].text + 1));
2794 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2795
2796 /* This assumes no templates start with the URL itself, and that they
2797 have at least two characters before the URL text */
2798 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2799 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2800 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2801 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2802 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2803 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2804
2805 if (urls[i].is_url)
2806 {
2807 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2808 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2809 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2810 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2811 }
2812 else
2813 {
2814 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2815 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2816 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2817 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2818 }
2819 if (buffer[end_offset] != '\0')
2820 {
2821 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2822 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2823 if (buffer[end_offset +1] != '\0')
2824 {
2825 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2826 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2827 }
2828 }
2829 }
2830
2831 DestroyWindow(hwndRichEdit);
2832 hwndRichEdit = NULL;
2833 }
2834
2836}
2837
2838static void test_EM_SCROLL(void)
2839{
2840 int i, j;
2841 int r; /* return value */
2842 int expr; /* expected return value */
2843 HWND hwndRichEdit = new_richedit(NULL);
2844 int y_before, y_after; /* units of lines of text */
2845
2846 /* test a richedit box containing a single line of text */
2847 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");/* one line of text */
2848 expr = 0x00010000;
2849 for (i = 0; i < 4; i++) {
2850 static const int cmd[4] = { SB_PAGEDOWN, SB_PAGEUP, SB_LINEDOWN, SB_LINEUP };
2851
2852 r = SendMessageA(hwndRichEdit, EM_SCROLL, cmd[i], 0);
2853 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2854 ok(expr == r, "EM_SCROLL improper return value returned (i == %d). "
2855 "Got 0x%08x, expected 0x%08x\n", i, r, expr);
2856 ok(y_after == 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 "
2857 "(i == %d)\n", y_after, i);
2858 }
2859
2860 /*
2861 * test a richedit box that will scroll. There are two general
2862 * cases: the case without any long lines and the case with a long
2863 * line.
2864 */
2865 for (i = 0; i < 2; i++) { /* iterate through different bodies of text */
2866 if (i == 0)
2867 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a\nb\nc\nd\ne");
2868 else
2869 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)
2870 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
2871 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
2872 "LONG LINE \nb\nc\nd\ne");
2873 for (j = 0; j < 12; j++) /* reset scroll position to top */
2874 SendMessageA(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0);
2875
2876 /* get first visible line */
2877 y_before = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2878 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0); /* page down */
2879
2880 /* get new current first visible line */
2881 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2882
2883 ok(((r & 0xffffff00) == 0x00010000) &&
2884 ((r & 0x000000ff) != 0x00000000),
2885 "EM_SCROLL page down didn't scroll by a small positive number of "
2886 "lines (r == 0x%08x)\n", r);
2887 ok(y_after > y_before, "EM_SCROLL page down not functioning "
2888 "(line %d scrolled to line %d\n", y_before, y_after);
2889
2890 y_before = y_after;
2891
2892 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0); /* page up */
2893 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2894 ok(((r & 0xffffff00) == 0x0001ff00),
2895 "EM_SCROLL page up didn't scroll by a small negative number of lines "
2896 "(r == 0x%08x)\n", r);
2897 ok(y_after < y_before, "EM_SCROLL page up not functioning (line "
2898 "%d scrolled to line %d\n", y_before, y_after);
2899
2900 y_before = y_after;
2901
2902 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */
2903
2904 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2905
2906 ok(r == 0x00010001, "EM_SCROLL line down didn't scroll by one line "
2907 "(r == 0x%08x)\n", r);
2908 ok(y_after -1 == y_before, "EM_SCROLL line down didn't go down by "
2909 "1 line (%d scrolled to %d)\n", y_before, y_after);
2910
2911 y_before = y_after;
2912
2913 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */
2914
2915 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2916
2917 ok(r == 0x0001ffff, "EM_SCROLL line up didn't scroll by one line "
2918 "(r == 0x%08x)\n", r);
2919 ok(y_after +1 == y_before, "EM_SCROLL line up didn't go up by 1 "
2920 "line (%d scrolled to %d)\n", y_before, y_after);
2921
2922 y_before = y_after;
2923
2924 r = SendMessageA(hwndRichEdit, EM_SCROLL,
2925 SB_LINEUP, 0); /* lineup beyond top */
2926
2927 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2928
2929 ok(r == 0x00010000,
2930 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r);
2931 ok(y_before == y_after,
2932 "EM_SCROLL line up beyond top worked (%d)\n", y_after);
2933
2934 y_before = y_after;
2935
2936 r = SendMessageA(hwndRichEdit, EM_SCROLL,
2937 SB_PAGEUP, 0);/*page up beyond top */
2938
2939 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2940
2941 ok(r == 0x00010000,
2942 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r);
2943 ok(y_before == y_after,
2944 "EM_SCROLL page up beyond top worked (%d)\n", y_after);
2945
2946 for (j = 0; j < 12; j++) /* page down all the way to the bottom */
2947 SendMessageA(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0);
2948 y_before = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2949 r = SendMessageA(hwndRichEdit, EM_SCROLL,
2950 SB_PAGEDOWN, 0); /* page down beyond bot */
2951 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2952
2953 ok(r == 0x00010000,
2954 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r);
2955 ok(y_before == y_after,
2956 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n",
2957 y_before, y_after);
2958
2959 y_before = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2960 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down beyond bot */
2961 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2962
2963 ok(r == 0x00010000,
2964 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r);
2965 ok(y_before == y_after,
2966 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n",
2967 y_before, y_after);
2968 }
2969 DestroyWindow(hwndRichEdit);
2970}
2971
2972static unsigned int recursionLevel = 0;
2973static unsigned int WM_SIZE_recursionLevel = 0;
2976
2978{
2979 LRESULT r;
2980
2981 if (bailedOutOfRecursion) return 0;
2982 if (recursionLevel >= 32) {
2984 return 0;
2985 }
2986
2988 switch (message) {
2989 case WM_SIZE:
2991 r = richeditProc(hwnd, message, wParam, lParam);
2992 /* Because, uhhhh... I never heard of ES_DISABLENOSCROLL */
2995 break;
2996 default:
2997 r = richeditProc(hwnd, message, wParam, lParam);
2998 break;
2999 }
3001 return r;
3002}
3003
3005{
3006 HWND hwndRichEdit;
3007 const char * text="a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n";
3008 SCROLLINFO si;
3009 WNDCLASSA cls;
3010 BOOL r;
3011
3012 /* These tests show that richedit should temporarily refrain from automatically
3013 hiding or showing its scrollbars (vertical at least) when an explicit request
3014 is made via ShowScrollBar() or similar, outside of standard richedit logic.
3015 Some applications depend on forced showing (when otherwise richedit would
3016 hide the vertical scrollbar) and are thrown on an endless recursive loop
3017 if richedit auto-hides the scrollbar again. Apparently they never heard of
3018 the ES_DISABLENOSCROLL style... */
3019
3020 hwndRichEdit = new_richedit(NULL);
3021
3022 /* Test default scrollbar visibility behavior */
3023 memset(&si, 0, sizeof(si));
3024 si.cbSize = sizeof(si);
3025 si.fMask = SIF_PAGE | SIF_RANGE;
3026 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3027 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3028 "Vertical scrollbar is visible, should be invisible.\n");
3029 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3030 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3031 si.nPage, si.nMin, si.nMax);
3032
3033 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3034 memset(&si, 0, sizeof(si));
3035 si.cbSize = sizeof(si);
3036 si.fMask = SIF_PAGE | SIF_RANGE;
3037 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3038 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3039 "Vertical scrollbar is visible, should be invisible.\n");
3040 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3041 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3042 si.nPage, si.nMin, si.nMax);
3043
3044 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
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 != 0,
3052 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3053 si.nPage, si.nMin, si.nMax);
3054
3055 /* Oddly, setting text to NULL does *not* reset the scrollbar range,
3056 even though it hides the scrollbar */
3057 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3058 memset(&si, 0, sizeof(si));
3059 si.cbSize = sizeof(si);
3060 si.fMask = SIF_PAGE | SIF_RANGE;
3061 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3062 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3063 "Vertical scrollbar is visible, should be invisible.\n");
3064 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3065 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3066 si.nPage, si.nMin, si.nMax);
3067
3068 /* Setting non-scrolling text again does *not* reset scrollbar range */
3069 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
3070 memset(&si, 0, sizeof(si));
3071 si.cbSize = sizeof(si);
3072 si.fMask = SIF_PAGE | SIF_RANGE;
3073 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3074 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3075 "Vertical scrollbar is visible, should be invisible.\n");
3076 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3077 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3078 si.nPage, si.nMin, si.nMax);
3079
3080 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3081 memset(&si, 0, sizeof(si));
3082 si.cbSize = sizeof(si);
3083 si.fMask = SIF_PAGE | SIF_RANGE;
3084 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3085 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3086 "Vertical scrollbar is visible, should be invisible.\n");
3087 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3088 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3089 si.nPage, si.nMin, si.nMax);
3090
3091 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
3092 memset(&si, 0, sizeof(si));
3093 si.cbSize = sizeof(si);
3094 si.fMask = SIF_PAGE | SIF_RANGE;
3095 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3096 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3097 "Vertical scrollbar is visible, should be invisible.\n");
3098 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3099 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3100 si.nPage, si.nMin, si.nMax);
3101
3102 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
3103 memset(&si, 0, sizeof(si));
3104 si.cbSize = sizeof(si);
3105 si.fMask = SIF_PAGE | SIF_RANGE;
3106 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3107 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3108 "Vertical scrollbar is visible, should be invisible.\n");
3109 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3110 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3111 si.nPage, si.nMin, si.nMax);
3112
3113 DestroyWindow(hwndRichEdit);
3114
3115 /* Test again, with ES_DISABLENOSCROLL style */
3117
3118 /* Test default scrollbar visibility behavior */
3119 memset(&si, 0, sizeof(si));
3120 si.cbSize = sizeof(si);
3121 si.fMask = SIF_PAGE | SIF_RANGE;
3122 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3123 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3124 "Vertical scrollbar is invisible, should be visible.\n");
3125 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 1,
3126 "reported page/range is %d (%d..%d) expected 0 (0..1)\n",
3127 si.nPage, si.nMin, si.nMax);
3128
3129 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3130 memset(&si, 0, sizeof(si));
3131 si.cbSize = sizeof(si);
3132 si.fMask = SIF_PAGE | SIF_RANGE;
3133 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3134 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3135 "Vertical scrollbar is invisible, should be visible.\n");
3136 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 1,
3137 "reported page/range is %d (%d..%d) expected 0 (0..1)\n",
3138 si.nPage, si.nMin, si.nMax);
3139
3140 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
3141 memset(&si, 0, sizeof(si));
3142 si.cbSize = sizeof(si);
3143 si.fMask = SIF_PAGE | SIF_RANGE;
3144 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3145 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3146 "Vertical scrollbar is invisible, should be visible.\n");
3147 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
3148 "reported page/range is %d (%d..%d)\n",
3149 si.nPage, si.nMin, si.nMax);
3150
3151 /* Oddly, setting text to NULL does *not* reset the scrollbar range */
3152 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3153 memset(&si, 0, sizeof(si));
3154 si.cbSize = sizeof(si);
3155 si.fMask = SIF_PAGE | SIF_RANGE;
3156 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3157 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3158 "Vertical scrollbar is invisible, should be visible.\n");
3159 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
3160 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3161 si.nPage, si.nMin, si.nMax);
3162
3163 /* Setting non-scrolling text again does *not* reset scrollbar range */
3164 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
3165 memset(&si, 0, sizeof(si));
3166 si.cbSize = sizeof(si);
3167 si.fMask = SIF_PAGE | SIF_RANGE;
3168 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3169 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3170 "Vertical scrollbar is invisible, should be visible.\n");
3171 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
3172 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3173 si.nPage, si.nMin, si.nMax);
3174
3175 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3176 memset(&si, 0, sizeof(si));
3177 si.cbSize = sizeof(si);
3178 si.fMask = SIF_PAGE | SIF_RANGE;
3179 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3180 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3181 "Vertical scrollbar is invisible, should be visible.\n");
3182 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
3183 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3184 si.nPage, si.nMin, si.nMax);
3185
3186 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
3187 memset(&si, 0, sizeof(si));
3188 si.cbSize = sizeof(si);
3189 si.fMask = SIF_PAGE | SIF_RANGE;
3190 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3191 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3192 "Vertical scrollbar is invisible, should be visible.\n");
3193 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
3194 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3195 si.nPage, si.nMin, si.nMax);
3196
3197 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
3198 memset(&si, 0, sizeof(si));
3199 si.cbSize = sizeof(si);
3200 si.fMask = SIF_PAGE | SIF_RANGE;
3201 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3202 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3203 "Vertical scrollbar is invisible, should be visible.\n");
3204 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
3205 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3206 si.nPage, si.nMin, si.nMax);
3207
3208 DestroyWindow(hwndRichEdit);
3209
3210 /* Test behavior with explicit visibility request, using ShowScrollBar() */
3211 hwndRichEdit = new_richedit(NULL);
3212
3213 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */
3214 ShowScrollBar(hwndRichEdit, SB_VERT, TRUE);
3215 memset(&si, 0, sizeof(si));
3216 si.cbSize = sizeof(si);
3217 si.fMask = SIF_PAGE | SIF_RANGE;
3218 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3219 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3220 "Vertical scrollbar is invisible, should be visible.\n");
3221 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
3222 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
3223 si.nPage, si.nMin, si.nMax);
3224
3225 /* Ditto, see above */
3226 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3227 memset(&si, 0, sizeof(si));
3228 si.cbSize = sizeof(si);
3229 si.fMask = SIF_PAGE | SIF_RANGE;
3230 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3231 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3232 "Vertical scrollbar is invisible, should be visible.\n");
3233 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
3234 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
3235 si.nPage, si.nMin, si.nMax);
3236
3237 /* Ditto, see above */
3238 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
3239 memset(&si, 0, sizeof(si));
3240 si.cbSize = sizeof(si);
3241 si.fMask = SIF_PAGE | SIF_RANGE;
3242 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3243 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3244 "Vertical scrollbar is invisible, should be visible.\n");
3245 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
3246 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
3247 si.nPage, si.nMin, si.nMax);
3248
3249 /* Ditto, see above */
3250 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a\na");
3251 memset(&si, 0, sizeof(si));
3252 si.cbSize = sizeof(si);
3253 si.fMask = SIF_PAGE | SIF_RANGE;
3254 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3255 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3256 "Vertical scrollbar is invisible, should be visible.\n");
3257 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
3258 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
3259 si.nPage, si.nMin, si.nMax);
3260
3261 /* Ditto, see above */
3262 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3263 memset(&si, 0, sizeof(si));
3264 si.cbSize = sizeof(si);
3265 si.fMask = SIF_PAGE | SIF_RANGE;
3266 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3267 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3268 "Vertical scrollbar is invisible, should be visible.\n");
3269 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
3270 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
3271 si.nPage, si.nMin, si.nMax);
3272
3273 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
3274 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3275 memset(&si, 0, sizeof(si));
3276 si.cbSize = sizeof(si);
3277 si.fMask = SIF_PAGE | SIF_RANGE;
3278 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3279 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3280 "Vertical scrollbar is visible, should be invisible.\n");
3281 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3282 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3283 si.nPage, si.nMin, si.nMax);
3284
3285 DestroyWindow(hwndRichEdit);
3286
3287 hwndRichEdit = new_richedit(NULL);
3288
3289 ShowScrollBar(hwndRichEdit, SB_VERT, FALSE);
3290 memset(&si, 0, sizeof(si));
3291 si.cbSize = sizeof(si);
3292 si.fMask = SIF_PAGE | SIF_RANGE;
3293 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3294 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3295 "Vertical scrollbar is visible, should be invisible.\n");
3296 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3297 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3298 si.nPage, si.nMin, si.nMax);
3299
3300 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3301 memset(&si, 0, sizeof(si));
3302 si.cbSize = sizeof(si);
3303 si.fMask = SIF_PAGE | SIF_RANGE;
3304 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3305 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3306 "Vertical scrollbar is visible, should be invisible.\n");
3307 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3308 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3309 si.nPage, si.nMin, si.nMax);
3310
3311 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
3312 memset(&si, 0, sizeof(si));
3313 si.cbSize = sizeof(si);
3314 si.fMask = SIF_PAGE | SIF_RANGE;
3315 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3316 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3317 "Vertical scrollbar is visible, should be invisible.\n");
3318 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3319 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3320 si.nPage, si.nMin, si.nMax);
3321
3322 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3323 memset(&si, 0, sizeof(si));
3324 si.cbSize = sizeof(si);
3325 si.fMask = SIF_PAGE | SIF_RANGE;
3326 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3327 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3328 "Vertical scrollbar is visible, should be invisible.\n");
3329 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3330 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3331 si.nPage, si.nMin, si.nMax);
3332
3333 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
3334 memset(&si, 0, sizeof(si));
3335 si.cbSize = sizeof(si);
3336 si.fMask = SIF_PAGE | SIF_RANGE;
3337 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3338 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3339 "Vertical scrollbar is invisible, should be visible.\n");
3340 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3341 "reported page/range is %d (%d..%d)\n",
3342 si.nPage, si.nMin, si.nMax);
3343
3344 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */
3345 ShowScrollBar(hwndRichEdit, SB_VERT, FALSE);
3346 memset(&si, 0, sizeof(si));
3347 si.cbSize = sizeof(si);
3348 si.fMask = SIF_PAGE | SIF_RANGE;
3349 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3350 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3351 "Vertical scrollbar is visible, should be invisible.\n");
3352 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3353 "reported page/range is %d (%d..%d)\n",
3354 si.nPage, si.nMin, si.nMax);
3355
3356 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
3357 memset(&si, 0, sizeof(si));
3358 si.cbSize = sizeof(si);
3359 si.fMask = SIF_PAGE | SIF_RANGE;
3360 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3361 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3362 "Vertical scrollbar is visible, should be invisible.\n");
3363 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3364 "reported page/range is %d (%d..%d)\n",
3365 si.nPage, si.nMin, si.nMax);
3366
3367 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that
3368 EM_SCROLL will make visible any forcefully invisible scrollbar */
3369 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0);
3370 memset(&si, 0, sizeof(si));
3371 si.cbSize = sizeof(si);
3372 si.fMask = SIF_PAGE | SIF_RANGE;
3373 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3374 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3375 "Vertical scrollbar is invisible, should be visible.\n");
3376 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3377 "reported page/range is %d (%d..%d)\n",
3378 si.nPage, si.nMin, si.nMax);
3379
3380 ShowScrollBar(hwndRichEdit, SB_VERT, FALSE);
3381 memset(&si, 0, sizeof(si));
3382 si.cbSize = sizeof(si);
3383 si.fMask = SIF_PAGE | SIF_RANGE;
3384 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3385 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3386 "Vertical scrollbar is visible, should be invisible.\n");
3387 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3388 "reported page/range is %d (%d..%d)\n",
3389 si.nPage, si.nMin, si.nMax);
3390
3391 /* Again, EM_SCROLL, with SB_LINEUP */
3392 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0);
3393 memset(&si, 0, sizeof(si));
3394 si.cbSize = sizeof(si);
3395 si.fMask = SIF_PAGE | SIF_RANGE;
3396 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3397 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3398 "Vertical scrollbar is invisible, should be visible.\n");
3399 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3400 "reported page/range is %d (%d..%d)\n",
3401 si.nPage, si.nMin, si.nMax);
3402
3403 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3404 memset(&si, 0, sizeof(si));
3405 si.cbSize = sizeof(si);
3406 si.fMask = SIF_PAGE | SIF_RANGE;
3407 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3408 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3409 "Vertical scrollbar is visible, should be invisible.\n");
3410 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3411 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3412 si.nPage, si.nMin, si.nMax);
3413
3414 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
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 invisible, should be visible.\n");
3421 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3422 "reported page/range is %d (%d..%d)\n",
3423 si.nPage, si.nMin, si.nMax);
3424
3425 DestroyWindow(hwndRichEdit);
3426
3427
3428 /* Test behavior with explicit visibility request, using SetWindowLongA()() */
3429 hwndRichEdit = new_richedit(NULL);
3430
3431#define ENABLE_WS_VSCROLL(hwnd) \
3432 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) | WS_VSCROLL)
3433#define DISABLE_WS_VSCROLL(hwnd) \
3434 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) & ~WS_VSCROLL)
3435
3436 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */
3437 ENABLE_WS_VSCROLL(hwndRichEdit);
3438 memset(&si, 0, sizeof(si));
3439 si.cbSize = sizeof(si);
3440 si.fMask = SIF_PAGE | SIF_RANGE;
3441 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3442 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3443 "Vertical scrollbar is invisible, should be visible.\n");
3444 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3445 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3446 si.nPage, si.nMin, si.nMax);
3447
3448 /* Ditto, see above */
3449 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3450 memset(&si, 0, sizeof(si));
3451 si.cbSize = sizeof(si);
3452 si.fMask = SIF_PAGE | SIF_RANGE;
3453 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3454 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3455 "Vertical scrollbar is invisible, should be visible.\n");
3456 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3457 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3458 si.nPage, si.nMin, si.nMax);
3459
3460 /* Ditto, see above */
3461 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
3462 memset(&si, 0, sizeof(si));
3463 si.cbSize = sizeof(si);
3464 si.fMask = SIF_PAGE | SIF_RANGE;
3465 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3466 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3467 "Vertical scrollbar is invisible, should be visible.\n");
3468 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3469 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3470 si.nPage, si.nMin, si.nMax);
3471
3472 /* Ditto, see above */
3473 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a\na");
3474 memset(&si, 0, sizeof(si));
3475 si.cbSize = sizeof(si);
3476 si.fMask = SIF_PAGE | SIF_RANGE;
3477 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3478 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3479 "Vertical scrollbar is invisible, should be visible.\n");
3480 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3481 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3482 si.nPage, si.nMin, si.nMax);
3483
3484 /* Ditto, see above */
3485 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3486 memset(&si, 0, sizeof(si));
3487 si.cbSize = sizeof(si);
3488 si.fMask = SIF_PAGE | SIF_RANGE;
3489 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3490 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3491 "Vertical scrollbar is invisible, should be visible.\n");
3492 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3493 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3494 si.nPage, si.nMin, si.nMax);
3495
3496 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
3497 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3498 memset(&si, 0, sizeof(si));
3499 si.cbSize = sizeof(si);
3500 si.fMask = SIF_PAGE | SIF_RANGE;
3501 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3502 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3503 "Vertical scrollbar is visible, should be invisible.\n");
3504 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3505 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3506 si.nPage, si.nMin, si.nMax);
3507
3508 DestroyWindow(hwndRichEdit);
3509
3510 hwndRichEdit = new_richedit(NULL);
3511
3512 DISABLE_WS_VSCROLL(hwndRichEdit);
3513 memset(&si, 0, sizeof(si));
3514 si.cbSize = sizeof(si);
3515 si.fMask = SIF_PAGE | SIF_RANGE;
3516 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3517 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3518 "Vertical scrollbar is visible, should be invisible.\n");
3519 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3520 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3521 si.nPage, si.nMin, si.nMax);
3522
3523 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3524 memset(&si, 0, sizeof(si));
3525 si.cbSize = sizeof(si);
3526 si.fMask = SIF_PAGE | SIF_RANGE;
3527 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3528 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3529 "Vertical scrollbar is visible, should be invisible.\n");
3530 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3531 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3532 si.nPage, si.nMin, si.nMax);
3533
3534 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
3535 memset(&si, 0, sizeof(si));
3536 si.cbSize = sizeof(si);
3537 si.fMask = SIF_PAGE | SIF_RANGE;
3538 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3539 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3540 "Vertical scrollbar is visible, should be invisible.\n");
3541 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3542 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3543 si.nPage, si.nMin, si.nMax);
3544
3545 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3546 memset(&si, 0, sizeof(si));
3547 si.cbSize = sizeof(si);
3548 si.fMask = SIF_PAGE | SIF_RANGE;
3549 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3550 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3551 "Vertical scrollbar is visible, should be invisible.\n");
3552 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3553 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3554 si.nPage, si.nMin, si.nMax);
3555
3556 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
3557 memset(&si, 0, sizeof(si));
3558 si.cbSize = sizeof(si);
3559 si.fMask = SIF_PAGE | SIF_RANGE;
3560 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3561 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3562 "Vertical scrollbar is invisible, should be visible.\n");
3563 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3564 "reported page/range is %d (%d..%d)\n",
3565 si.nPage, si.nMin, si.nMax);
3566
3567 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */
3568 DISABLE_WS_VSCROLL(hwndRichEdit);
3569 memset(&si, 0, sizeof(si));
3570 si.cbSize = sizeof(si);
3571 si.fMask = SIF_PAGE | SIF_RANGE;
3572 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3573 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3574 "Vertical scrollbar is visible, should be invisible.\n");
3575 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3576 "reported page/range is %d (%d..%d)\n",
3577 si.nPage, si.nMin, si.nMax);
3578
3579 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3580 memset(&si, 0, sizeof(si));
3581 si.cbSize = sizeof(si);
3582 si.fMask = SIF_PAGE | SIF_RANGE;
3583 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3584 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3585 "Vertical scrollbar is visible, should be invisible.\n");
3586 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3587 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3588 si.nPage, si.nMin, si.nMax);
3589
3590 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
3591 memset(&si, 0, sizeof(si));
3592 si.cbSize = sizeof(si);
3593 si.fMask = SIF_PAGE | SIF_RANGE;
3594 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3595 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3596 "Vertical scrollbar is invisible, should be visible.\n");
3597 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3598 "reported page/range is %d (%d..%d)\n",
3599 si.nPage, si.nMin, si.nMax);
3600
3601 DISABLE_WS_VSCROLL(hwndRichEdit);
3602 memset(&si, 0, sizeof(si));
3603 si.cbSize = sizeof(si);
3604 si.fMask = SIF_PAGE | SIF_RANGE;
3605 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3606 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3607 "Vertical scrollbar is visible, should be invisible.\n");
3608 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3609 "reported page/range is %d (%d..%d)\n",
3610 si.nPage, si.nMin, si.nMax);
3611
3612 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that
3613 EM_SCROLL will make visible any forcefully invisible scrollbar */
3614 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0);
3615 memset(&si, 0, sizeof(si));
3616 si.cbSize = sizeof(si);
3617 si.fMask = SIF_PAGE | SIF_RANGE;
3618 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3619 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3620 "Vertical scrollbar is invisible, should be visible.\n");
3621 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3622 "reported page/range is %d (%d..%d)\n",
3623 si.nPage, si.nMin, si.nMax);
3624
3625 DISABLE_WS_VSCROLL(hwndRichEdit);
3626 memset(&si, 0, sizeof(si));
3627 si.cbSize = sizeof(si);
3628 si.fMask = SIF_PAGE | SIF_RANGE;
3629 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3630 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3631 "Vertical scrollbar is visible, should be invisible.\n");
3632 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3633 "reported page/range is %d (%d..%d)\n",
3634 si.nPage, si.nMin, si.nMax);
3635
3636 /* Again, EM_SCROLL, with SB_LINEUP */
3637 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0);
3638 memset(&si, 0, sizeof(si));
3639 si.cbSize = sizeof(si);
3640 si.fMask = SIF_PAGE | SIF_RANGE;
3641 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3642 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3643 "Vertical scrollbar is invisible, should be visible.\n");
3644 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3645 "reported page/range is %d (%d..%d)\n",
3646 si.nPage, si.nMin, si.nMax);
3647
3648 DestroyWindow(hwndRichEdit);
3649
3650 /* This window proc models what is going on with Corman Lisp 3.0.
3651 At WM_SIZE, this proc unconditionally calls ShowScrollBar() to
3652 force the scrollbar into visibility. Recursion should NOT happen
3653 as a result of this action.
3654 */
3656 if (r) {
3657 richeditProc = cls.lpfnWndProc;
3659 cls.lpszClassName = "RicheditStupidOverride";
3660 if(!RegisterClassA(&cls)) assert(0);
3661
3662 recursionLevel = 0;
3665 hwndRichEdit = new_window(cls.lpszClassName, ES_MULTILINE, NULL);
3667 "WM_SIZE/scrollbar mutual recursion detected, expected none!\n");
3668
3669 recursionLevel = 0;
3672 MoveWindow(hwndRichEdit, 0, 0, 250, 100, TRUE);
3674 "WM_SIZE/scrollbar mutual recursion detected, expected none!\n");
3675
3676 /* Unblock window in order to process WM_DESTROY */
3677 recursionLevel = 0;
3680 DestroyWindow(hwndRichEdit);
3681 }
3682}
3683
3684static void test_EM_SETUNDOLIMIT(void)
3685{
3686 /* cases we test for:
3687 * default behaviour - limiting at 100 undo's
3688 * undo disabled - setting a limit of 0
3689 * undo limited - undo limit set to some to some number, like 2
3690 * bad input - sending a negative number should default to 100 undo's */
3691
3692 HWND hwndRichEdit = new_richedit(NULL);
3693 CHARRANGE cr;
3694 int i;
3695 int result;
3696
3697 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"x");
3698 cr.cpMin = 0;
3699 cr.cpMax = -1;
3700 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
3701
3702 SendMessageA(hwndRichEdit, WM_COPY, 0, 0);
3703 /*Load "x" into the clipboard. Paste is an easy, undo'able operation.
3704 also, multiple pastes don't combine like WM_CHAR would */
3705
3706 /* first case - check the default */
3707 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
3708 for (i=0; i<101; i++) /* Put 101 undo's on the stack */
3709 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
3710 for (i=0; i<100; i++) /* Undo 100 of them */
3711 SendMessageA(hwndRichEdit, WM_UNDO, 0, 0);
3712 ok(!SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0),
3713 "EM_SETUNDOLIMIT allowed more than a hundred undo's by default.\n");
3714
3715 /* second case - cannot undo */
3716 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0);
3717 SendMessageA(hwndRichEdit, EM_SETUNDOLIMIT, 0, 0);
3718 SendMessageA(hwndRichEdit,
3719 WM_PASTE, 0, 0); /* Try to put something in the undo stack */
3720 ok(!SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0),
3721 "EM_SETUNDOLIMIT allowed undo with UNDOLIMIT set to 0\n");
3722
3723 /* third case - set it to an arbitrary number */
3724 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0);
3725 SendMessageA(hwndRichEdit, EM_SETUNDOLIMIT, 2, 0);
3726 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
3727 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
3728 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
3729 /* If SETUNDOLIMIT is working, there should only be two undo's after this */
3730 ok(SendMessageA(hwndRichEdit, EM_CANUNDO, 0,0),
3731 "EM_SETUNDOLIMIT didn't allow the first undo with UNDOLIMIT set to 2\n");
3732 SendMessageA(hwndRichEdit, WM_UNDO, 0, 0);
3733 ok(SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0),
3734 "EM_SETUNDOLIMIT didn't allow a second undo with UNDOLIMIT set to 2\n");
3735 SendMessageA(hwndRichEdit, WM_UNDO, 0, 0);
3736 ok(!SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0),
3737 "EM_SETUNDOLIMIT allowed a third undo with UNDOLIMIT set to 2\n");
3738
3739 /* fourth case - setting negative numbers should default to 100 undos */
3740 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
3741 result = SendMessageA(hwndRichEdit, EM_SETUNDOLIMIT, -1, 0);
3742 ok (result == 100,
3743 "EM_SETUNDOLIMIT returned %d when set to -1, instead of 100\n",result);
3744
3745 DestroyWindow(hwndRichEdit);
3746}
3747
3748static void test_ES_PASSWORD(void)
3749{
3750 /* This isn't hugely testable, so we're just going to run it through its paces */
3751
3752 HWND hwndRichEdit = new_richedit(NULL);
3753 WCHAR result;
3754
3755 /* First, check the default of a regular control */
3756 result = SendMessageA(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
3757 ok (result == 0,
3758 "EM_GETPASSWORDCHAR returned %c by default, instead of NULL\n",result);
3759
3760 /* Now, set it to something normal */
3761 SendMessageA(hwndRichEdit, EM_SETPASSWORDCHAR, 'x', 0);
3762 result = SendMessageA(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
3763 ok (result == 120,
3764 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result);
3765
3766 /* Now, set it to something odd */
3767 SendMessageA(hwndRichEdit, EM_SETPASSWORDCHAR, (WCHAR)1234, 0);
3768 result = SendMessageA(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
3769 ok (result == 1234,
3770 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result);
3771 DestroyWindow(hwndRichEdit);
3772}
3773
3775
3777 LPBYTE pbBuff,
3778 LONG cb,
3779 LONG *pcb)
3780{
3781 char** str = (char**)dwCookie;
3782 *pcb = cb;
3783 if (*pcb > 0) {
3784 memcpy(*str, pbBuff, *pcb);
3785 *str += *pcb;
3786 }
3787 streamout_written = *pcb;
3788 return 0;
3789}
3790
3791static void test_WM_SETTEXT(void)
3792{
3793 HWND hwndRichEdit = new_richedit(NULL);
3794 const char * TestItem1 = "TestSomeText";
3795 const char * TestItem2 = "TestSomeText\r";
3796 const char * TestItem2_after = "TestSomeText\r\n";
3797 const char * TestItem3 = "TestSomeText\rSomeMoreText\r";
3798 const char * TestItem3_after = "TestSomeText\r\nSomeMoreText\r\n";
3799 const char * TestItem4 = "TestSomeText\n\nTestSomeText";
3800 const char * TestItem4_after = "TestSomeText\r\n\r\nTestSomeText";
3801 const char * TestItem5 = "TestSomeText\r\r\nTestSomeText";
3802 const char * TestItem5_after = "TestSomeText TestSomeText";
3803 const char * TestItem6 = "TestSomeText\r\r\n\rTestSomeText";
3804 const char * TestItem6_after = "TestSomeText \r\nTestSomeText";
3805 const char * TestItem7 = "TestSomeText\r\n\r\r\n\rTestSomeText";
3806 const char * TestItem7_after = "TestSomeText\r\n \r\nTestSomeText";
3807
3808 const char rtftextA[] = "{\\rtf sometext}";
3809 const char urtftextA[] = "{\\urtf sometext}";
3810 const WCHAR rtftextW[] = {'{','\\','r','t','f',' ','s','o','m','e','t','e','x','t','}',0};
3811 const WCHAR urtftextW[] = {'{','\\','u','r','t','f',' ','s','o','m','e','t','e','x','t','}',0};
3812 const WCHAR sometextW[] = {'s','o','m','e','t','e','x','t',0};
3813
3814 char buf[1024] = {0};
3815 WCHAR bufW[1024] = {0};
3817
3818 /* This test attempts to show that WM_SETTEXT on a riched20 control causes
3819 any solitary \r to be converted to \r\n on return. Properly paired
3820 \r\n are not affected. It also shows that the special sequence \r\r\n
3821 gets converted to a single space.
3822 */
3823
3824#define TEST_SETTEXT(a, b) \
3825 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)a); \
3826 ok (result == 1, "WM_SETTEXT returned %Id instead of 1\n", result); \
3827 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf); \
3828 ok (result == lstrlenA(buf), \
3829 "WM_GETTEXT returned %Id instead of expected %u\n", \
3830 result, lstrlenA(buf)); \
3831 result = strcmp(b, buf); \
3832 ok(result == 0, \
3833 "WM_SETTEXT round trip: strcmp = %Id, text=\"%s\"\n", result, buf);
3834
3835 TEST_SETTEXT(TestItem1, TestItem1)
3836 TEST_SETTEXT(TestItem2, TestItem2_after)
3837 TEST_SETTEXT(TestItem3, TestItem3_after)
3838 TEST_SETTEXT(TestItem3_after, TestItem3_after)
3839 TEST_SETTEXT(TestItem4, TestItem4_after)
3840 TEST_SETTEXT(TestItem5, TestItem5_after)
3841 TEST_SETTEXT(TestItem6, TestItem6_after)
3842 TEST_SETTEXT(TestItem7, TestItem7_after)
3843
3844 /* The following tests demonstrate that WM_SETTEXT supports RTF strings */
3845 TEST_SETTEXT(rtftextA, "sometext") /* interpreted as ascii rtf */
3846 TEST_SETTEXT(urtftextA, "sometext") /* interpreted as ascii rtf */
3847 TEST_SETTEXT(rtftextW, "{") /* interpreted as ascii text */
3848 TEST_SETTEXT(urtftextW, "{") /* interpreted as ascii text */
3849 DestroyWindow(hwndRichEdit);
3850#undef TEST_SETTEXT
3851
3852#define TEST_SETTEXTW(a, b) \
3853 result = SendMessageW(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)a); \
3854 ok (result == 1, "WM_SETTEXT returned %Id instead of 1\n", result); \
3855 result = SendMessageW(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufW); \
3856 ok (result == lstrlenW(bufW), \
3857 "WM_GETTEXT returned %Id instead of expected %u\n", \
3858 result, lstrlenW(bufW)); \
3859 result = lstrcmpW(b, bufW); \
3860 ok(result == 0, "WM_SETTEXT round trip: strcmp = %Id\n", result);
3861
3862 hwndRichEdit = CreateWindowW(RICHEDIT_CLASS20W, NULL,
3864 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
3865 ok(hwndRichEdit != NULL, "class: RichEdit20W, error: %d\n", (int) GetLastError());
3866 TEST_SETTEXTW(rtftextA, sometextW) /* interpreted as ascii rtf */
3867 TEST_SETTEXTW(urtftextA, sometextW) /* interpreted as ascii rtf */
3868 TEST_SETTEXTW(rtftextW, rtftextW) /* interpreted as ascii text */
3869 TEST_SETTEXTW(urtftextW, urtftextW) /* interpreted as ascii text */
3870 DestroyWindow(hwndRichEdit);
3871#undef TEST_SETTEXTW
3872
3873 /* Single-line richedit */
3874 hwndRichEdit = new_richedit_with_style(NULL, 0);
3875 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"line1\r\nline2");
3876 ok(result == 1, "WM_SETTEXT returned %Id, expected 12\n", result);
3877 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf);
3878 ok(result == 5, "WM_GETTEXT returned %Id, expected 5\n", result);
3879 ok(!strcmp(buf, "line1"), "WM_GETTEXT returned incorrect string '%s'\n", buf);
3880 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"{\\rtf1 ABC\\rtlpar\\par DEF\\par HIJ\\pard\\par}");
3881 ok(result == 1, "WM_SETTEXT returned %Id, expected 1\n", result);
3882 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf);
3883 ok(result == 3, "WM_GETTEXT returned %Id, expected 3\n", result);
3884 ok(!strcmp(buf, "ABC"), "WM_GETTEXT returned incorrect string '%s'\n", buf);
3885 DestroyWindow(hwndRichEdit);
3886}
3887
3888/* Set *pcb to one to show that the remaining cb-1 bytes are not
3889 resent to the callkack. */
3891 LPBYTE pbBuff,
3892 LONG cb,
3893 LONG *pcb)
3894{
3895 char** str = (char**)dwCookie;
3896 ok(*pcb == cb || *pcb == 0, "cb %ld, *pcb %ld\n", cb, *pcb);
3897 *pcb = 0;
3898 if (cb > 0) {
3899 memcpy(*str, pbBuff, cb);
3900 *str += cb;
3901 *pcb = 1;
3902 }
3903 return 0;
3904}
3905
3906static int count_pars(const char *buf)
3907{
3908 const char *p = buf;
3909 int count = 0;
3910 while ((p = strstr( p, "\\par" )) != NULL)
3911 {
3912 if (!isalpha( p[4] ))
3913 count++;
3914 p++;
3915 }
3916 return count;
3917}
3918
3919static void test_EM_STREAMOUT(void)
3920{
3921 HWND hwndRichEdit = new_richedit(NULL);
3922 int r;
3923 EDITSTREAM es;
3924 char buf[1024] = {0};
3925 char * p;
3927
3928 const char * TestItem1 = "TestSomeText";
3929 const char * TestItem2 = "TestSomeText\r";
3930 const char * TestItem3 = "TestSomeText\r\n";
3931
3932 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem1);
3933 p = buf;
3934 es.dwCookie = (DWORD_PTR)&p;
3935 es.dwError = 0;
3936 es.pfnCallback = test_WM_SETTEXT_esCallback;
3937 memset(buf, 0, sizeof(buf));
3938 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_TEXT, (LPARAM)&es);
3939 r = strlen(buf);
3940 ok(r == 12, "streamed text length is %d, expecting 12\n", r);
3941 ok(strcmp(buf, TestItem1) == 0,
3942 "streamed text different, got %s\n", buf);
3943 ok(result == streamout_written, "got %Id expected %ld\n", result, streamout_written);
3944
3945 /* RTF mode writes the final end of para \r if it's part of the selection */
3946 p = buf;
3947 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF, (LPARAM)&es);
3948 ok (count_pars(buf) == 1, "got %s\n", buf);
3949 ok(result == streamout_written, "got %Id expected %ld\n", result, streamout_written);
3950 p = buf;
3951 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 12);
3953 ok (count_pars(buf) == 0, "got %s\n", buf);
3954 ok(result == streamout_written, "got %Id expected %ld\n", result, streamout_written);
3955 p = buf;
3956 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
3958 ok (count_pars(buf) == 1, "got %s\n", buf);
3959 ok(result == streamout_written, "got %Id expected %ld\n", result, streamout_written);
3960
3961 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem2);
3962 p = buf;
3963 es.dwCookie = (DWORD_PTR)&p;
3964 es.dwError = 0;
3965 es.pfnCallback = test_WM_SETTEXT_esCallback;
3966 memset(buf, 0, sizeof(buf));
3967 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_TEXT, (LPARAM)&es);
3968 ok(result == streamout_written, "got %Id expected %ld\n", result, streamout_written);
3969 r = strlen(buf);
3970 /* Here again, \r gets converted to \r\n, like WM_GETTEXT */
3971 ok(r == 14, "streamed text length is %d, expecting 14\n", r);
3972 ok(strcmp(buf, TestItem3) == 0,
3973 "streamed text different from, got %s\n", buf);
3974
3975 /* And again RTF mode writes the final end of para \r if it's part of the selection */
3976 p = buf;
3977 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF, (LPARAM)&es);
3978 ok (count_pars(buf) == 2, "got %s\n", buf);
3979 ok(result == streamout_written, "got %Id expected %ld\n", result, streamout_written);
3980 p = buf;
3981 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 13);
3983 ok (count_pars(buf) == 1, "got %s\n", buf);
3984 ok(result == streamout_written, "got %Id expected %ld\n", result, streamout_written);
3985 p = buf;
3986 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
3988 ok (count_pars(buf) == 2, "got %s\n", buf);
3989 ok(result == streamout_written, "got %Id expected %ld\n", result, streamout_written);
3990
3991 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem3);
3992 p = buf;
3993 es.dwCookie = (DWORD_PTR)&p;
3994 es.dwError = 0;
3995 es.pfnCallback = test_WM_SETTEXT_esCallback;
3996 memset(buf, 0, sizeof(buf));
3997 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_TEXT, (LPARAM)&es);
3998 ok(result == streamout_written, "got %Id expected %ld\n", result, streamout_written);
3999 r = strlen(buf);
4000 ok(r == 14, "streamed text length is %d, expecting 14\n", r);
4001 ok(strcmp(buf, TestItem3) == 0,
4002 "streamed text different, got %s\n", buf);
4003
4004 /* Use a callback that sets *pcb to one */
4005 p = buf;
4006 es.dwCookie = (DWORD_PTR)&p;
4007 es.dwError = 0;
4008 es.pfnCallback = test_esCallback_written_1;
4009 memset(buf, 0, sizeof(buf));
4010 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_TEXT, (LPARAM)&es);
4011 r = strlen(buf);
4012 ok(r == 14, "streamed text length is %d, expecting 14\n", r);
4013 ok(strcmp(buf, TestItem3) == 0,
4014 "streamed text different, got %s\n", buf);
4015 ok(result == 0, "got %Id expected 0\n", result);
4016
4017
4018 DestroyWindow(hwndRichEdit);
4019}
4020
4022{
4023 HWND hwndRichEdit = new_richedit(NULL);
4024 EDITSTREAM es;
4025 char buf[1024] = {0};
4026 char * p;
4027 char * fontTbl;
4028 int brackCount;
4029
4030 const char * TestItem = "TestSomeText";
4031
4032 /* fills in the richedit control with some text */
4033 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem);
4034
4035 /* streams out the text in rtf format */
4036 p = buf;
4037 es.dwCookie = (DWORD_PTR)&p;
4038 es.dwError = 0;
4039 es.pfnCallback = test_WM_SETTEXT_esCallback;
4040 memset(buf, 0, sizeof(buf));
4041 SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF, (LPARAM)&es);
4042
4043 /* scans for \fonttbl, error if not found */
4044 fontTbl = strstr(buf, "\\fonttbl");
4045 ok(fontTbl != NULL, "missing \\fonttbl section\n");
4046 if(fontTbl)
4047 {
4048 /* scans for terminating closing bracket */
4049 brackCount = 1;
4050 while(*fontTbl && brackCount)
4051 {
4052 if(*fontTbl == '{')
4053 brackCount++;
4054 else if(*fontTbl == '}')
4055 brackCount--;
4056 fontTbl++;
4057 }
4058 /* checks whether closing bracket is ok */
4059 ok(brackCount == 0, "missing closing bracket in \\fonttbl block\n");
4060 if(!brackCount)
4061 {
4062 /* char before closing fonttbl block should be a closed bracket */
4063 fontTbl -= 2;
4064 ok(*fontTbl == '}', "spurious character '%02x' before \\fonttbl closing bracket\n", *fontTbl);
4065
4066 /* char after fonttbl block should be a crlf */
4067 fontTbl += 2;
4068 ok(*fontTbl == 0x0d && *(fontTbl+1) == 0x0a, "missing crlf after \\fonttbl block\n");
4069 }
4070 }
4071 DestroyWindow(hwndRichEdit);
4072}
4073
4075{
4077 char buf[1024], *p = buf;
4078 EDITSTREAM es;
4079
4081
4082 memset(buf, 0, sizeof(buf));
4083 es.dwCookie = (DWORD_PTR)&p;
4084 es.dwError = 0;
4085 es.pfnCallback = test_WM_SETTEXT_esCallback;
4086
4088 ok((p = strstr(buf, "\\pard")) != NULL, "missing \\pard\n");
4089 ok(((p = strstr(p, "\\fs")) && isdigit(p[3])), "missing \\fs\n");
4090
4092}
4093
4094static void test_EM_SETTEXTEX(void)
4095{
4096 HWND hwndRichEdit, parent;
4097 SCROLLINFO si;
4098 int sel_start, sel_end;
4099 SETTEXTEX setText;
4100 GETTEXTEX getText;
4101 WCHAR TestItem1[] = {'T', 'e', 's', 't',
4102 'S', 'o', 'm', 'e',
4103 'T', 'e', 'x', 't', 0};
4104 WCHAR TestItem1alt[] = {'T', 'T', 'e', 's',
4105 't', 'S', 'o', 'm',
4106 'e', 'T', 'e', 'x',
4107 't', 't', 'S', 'o',
4108 'm', 'e', 'T', 'e',
4109 'x', 't', 0};
4110 WCHAR TestItem1altn[] = {'T','T','e','s','t','S','o','m','e','T','e','x','t',
4111 '\r','t','S','o','m','e','T','e','x','t',0};
4112 WCHAR TestItem2[] = {'T', 'e', 's', 't',
4113 'S', 'o', 'm', 'e',
4114 'T', 'e', 'x', 't',
4115 '\r', 0};
4116 const char * TestItem2_after = "TestSomeText\r\n";
4117 WCHAR TestItem3[] = {'T', 'e', 's', 't',
4118 'S', 'o', 'm', 'e',
4119 'T', 'e', 'x', 't',
4120 '\r','\n','\r','\n', 0};
4121 WCHAR TestItem3alt[] = {'T', 'e', 's', 't',
4122 'S', 'o', 'm', 'e',
4123 'T', 'e', 'x', 't',
4124 '\n','\n', 0};
4125 WCHAR TestItem3_after[] = {'T', 'e', 's', 't',
4126 'S', 'o', 'm', 'e',
4127 'T', 'e', 'x', 't',
4128 '\r','\r', 0};
4129 WCHAR TestItem4[] = {'T', 'e', 's', 't',
4130 'S', 'o', 'm', 'e',
4131 'T', 'e', 'x', 't',
4132 '\r','\r','\n','\r',
4133 '\n', 0};
4134 WCHAR TestItem4_after[] = {'T', 'e', 's', 't',
4135 'S', 'o', 'm', 'e',
4136 'T', 'e', 'x', 't',
4137 ' ','\r', 0};
4138#define MAX_BUF_LEN 1024
4140 char bufACP[MAX_BUF_LEN];
4141 char * p;
4142 int result;
4143 CHARRANGE cr;
4144 EDITSTREAM es;
4145 WNDCLASSA cls;
4146
4147 /* Test the scroll position with and without a parent window.
4148 *
4149 * For some reason the scroll position is 0 after EM_SETTEXTEX
4150 * with the ST_SELECTION flag only when the control has a parent
4151 * window, even though the selection is at the end. */
4152 cls = make_simple_class(DefWindowProcA, "ParentTestClass");
4153 if(!RegisterClassA(&cls)) assert(0);
4154
4156 0, 0, 200, 60, NULL, NULL, NULL, NULL);
4157 ok (parent != 0, "Failed to create parent window\n");
4158
4159 hwndRichEdit = CreateWindowExA(0,
4162 0, 0, 200, 60, parent, NULL,
4164
4165 setText.codepage = CP_ACP;
4166 setText.flags = ST_SELECTION;
4167 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText,
4168 (LPARAM)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
4169 todo_wine ok(result == 18, "EM_SETTEXTEX returned %d, expected 18\n", result);
4170 si.cbSize = sizeof(si);
4171 si.fMask = SIF_ALL;
4172 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
4173 todo_wine ok(si.nPos == 0, "Position is incorrectly at %d\n", si.nPos);
4174 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
4175 ok(sel_start == 18, "Selection start incorrectly at %d\n", sel_start);
4176 ok(sel_end == 18, "Selection end incorrectly at %d\n", sel_end);
4177
4179
4180 /* Test without a parent window */
4181 hwndRichEdit = new_richedit(NULL);
4182 setText.codepage = CP_ACP;
4183 setText.flags = ST_SELECTION;
4184 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText,
4185 (LPARAM)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
4186 todo_wine ok(result == 18, "EM_SETTEXTEX returned %d, expected 18\n", result);
4187 si.cbSize = sizeof(si);
4188 si.fMask = SIF_ALL;
4189 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
4190 ok(si.nPos != 0, "Position is incorrectly at %d\n", si.nPos);
4191 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
4192 ok(sel_start == 18, "Selection start incorrectly at %d\n", sel_start);
4193 ok(sel_end == 18, "Selection end incorrectly at %d\n", sel_end);
4194
4195 /* The scroll position should also be 0 after EM_SETTEXTEX with ST_DEFAULT,
4196 * but this time it is because the selection is at the beginning. */
4197 setText.codepage = CP_ACP;
4198 setText.flags = ST_DEFAULT;
4199 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText,
4200 (LPARAM)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
4201 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4202 si.cbSize = sizeof(si);
4203 si.fMask = SIF_ALL;
4204 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
4205 ok(si.nPos == 0, "Position is incorrectly at %d\n", si.nPos);
4206 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
4207 ok(sel_start == 0, "Selection start incorrectly at %d\n", sel_start);
4208 ok(sel_end == 0, "Selection end incorrectly at %d\n", sel_end);
4209
4210 setText.codepage = 1200; /* no constant for unicode */
4211 getText.codepage = 1200; /* no constant for unicode */
4212 getText.cb = MAX_BUF_LEN;
4213 getText.flags = GT_DEFAULT;
4214 getText.lpDefaultChar = NULL;
4215 getText.lpUsedDefChar = NULL;
4216
4217 setText.flags = 0;
4218 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
4219 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4220 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4221 ok(lstrcmpW(buf, TestItem1) == 0,
4222 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
4223
4224 /* Unlike WM_SETTEXT/WM_GETTEXT pair, EM_SETTEXTEX/EM_GETTEXTEX does not
4225 convert \r to \r\n on return: !ST_SELECTION && Unicode && !\rtf
4226 */
4227 setText.codepage = 1200; /* no constant for unicode */
4228 getText.codepage = 1200; /* no constant for unicode */
4229 getText.cb = MAX_BUF_LEN;
4230 getText.flags = GT_DEFAULT;
4231 getText.lpDefaultChar = NULL;
4232 getText.lpUsedDefChar = NULL;
4233 setText.flags = 0;
4234 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem2);
4235 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4236 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4237 ok(lstrcmpW(buf, TestItem2) == 0,
4238 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
4239
4240 /* However, WM_GETTEXT *does* see \r\n where EM_GETTEXTEX would see \r */
4241 SendMessageA(hwndRichEdit, WM_GETTEXT, MAX_BUF_LEN, (LPARAM)buf);
4242 ok(strcmp((const char *)buf, TestItem2_after) == 0,
4243 "WM_GETTEXT did *not* see \\r converted to \\r\\n pairs.\n");
4244
4245 /* Baseline test for just-enough buffer space for string */
4246 getText.cb = (lstrlenW(TestItem2) + 1) * sizeof(WCHAR);
4247 getText.codepage = 1200; /* no constant for unicode */
4248 getText.flags = GT_DEFAULT;
4249 getText.lpDefaultChar = NULL;
4250 getText.lpUsedDefChar = NULL;
4251 memset(buf, 0, sizeof(buf));
4252 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4253 ok(lstrcmpW(buf, TestItem2) == 0,
4254 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
4255
4256 /* When there is enough space for one character, but not both, of the CRLF
4257 pair at the end of the string, the CR is not copied at all. That is,
4258 the caller must not see CRLF pairs truncated to CR at the end of the
4259 string.
4260 */
4261 getText.cb = (lstrlenW(TestItem2) + 1) * sizeof(WCHAR);
4262 getText.codepage = 1200; /* no constant for unicode */
4263 getText.flags = GT_USECRLF; /* <-- asking for CR -> CRLF conversion */
4264 getText.lpDefaultChar = NULL;
4265 getText.lpUsedDefChar = NULL;
4266 memset(buf, 0, sizeof(buf));
4267 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4268 ok(lstrcmpW(buf, TestItem1) == 0,
4269 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
4270
4271
4272 /* \r\n pairs get changed into \r: !ST_SELECTION && Unicode && !\rtf */
4273 setText.codepage = 1200; /* no constant for unicode */
4274 getText.codepage = 1200; /* no constant for unicode */
4275 getText.cb = MAX_BUF_LEN;
4276 getText.flags = GT_DEFAULT;
4277 getText.lpDefaultChar = NULL;
4278 getText.lpUsedDefChar = NULL;
4279 setText.flags = 0;
4280 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem3);
4281 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4282 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4283 ok(lstrcmpW(buf, TestItem3_after) == 0,
4284 "EM_SETTEXTEX did not convert properly\n");
4285
4286 /* \n also gets changed to \r: !ST_SELECTION && Unicode && !\rtf */
4287 setText.codepage = 1200; /* no constant for unicode */
4288 getText.codepage = 1200; /* no constant for unicode */
4289 getText.cb = MAX_BUF_LEN;
4290 getText.flags = GT_DEFAULT;
4291 getText.lpDefaultChar = NULL;
4292 getText.lpUsedDefChar = NULL;
4293 setText.flags = 0;
4294 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem3alt);
4295 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4296 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4297 ok(lstrcmpW(buf, TestItem3_after) == 0,
4298 "EM_SETTEXTEX did not convert properly\n");
4299
4300 /* \r\r\n gets changed into single space: !ST_SELECTION && Unicode && !\rtf */
4301 setText.codepage = 1200; /* no constant for unicode */
4302 getText.codepage = 1200; /* no constant for unicode */
4303 getText.cb = MAX_BUF_LEN;
4304 getText.flags = GT_DEFAULT;
4305 getText.lpDefaultChar = NULL;
4306 getText.lpUsedDefChar = NULL;
4307 setText.flags = 0;
4308 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem4);
4309 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4310 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4311 ok(lstrcmpW(buf, TestItem4_after) == 0,
4312 "EM_SETTEXTEX did not convert properly\n");
4313
4314 /* !ST_SELECTION && Unicode && !\rtf */
4315 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, 0);
4316 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4317
4318 ok (result == 1,
4319 "EM_SETTEXTEX returned %d, instead of 1\n",result);
4320 ok(!buf[0], "EM_SETTEXTEX with NULL lParam should clear rich edit.\n");
4321
4322 /* put some text back: !ST_SELECTION && Unicode && !\rtf */
4323 setText.flags = 0;
4324 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
4325 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4326 /* select some text */
4327 cr.cpMax = 1;
4328 cr.cpMin = 3;
4329 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
4330 /* replace current selection: ST_SELECTION && Unicode && !\rtf */
4331 setText.flags = ST_SELECTION;
4332 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, 0);
4333 ok(result == 0,
4334 "EM_SETTEXTEX with NULL lParam to replace selection"
4335 " with no text should return 0. Got %i\n",
4336 result);
4337
4338 /* put some text back: !ST_SELECTION && Unicode && !\rtf */
4339 setText.flags = 0;
4340 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
4341 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4342 /* select some text */
4343 cr.cpMax = 1;
4344 cr.cpMin = 3;
4345 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
4346 /* replace current selection: ST_SELECTION && Unicode && !\rtf */
4347 setText.flags = ST_SELECTION;
4348 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
4349 /* get text */
4350 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4351 ok(result == lstrlenW(TestItem1),
4352 "EM_SETTEXTEX with NULL lParam to replace selection"
4353 " with no text should return 0. Got %i\n",
4354 result);
4355 ok(lstrlenW(buf) == 22,
4356 "EM_SETTEXTEX to replace selection with more text failed: %i.\n",
4357 lstrlenW(buf) );
4358
4359 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings */
4360 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"TestSomeText"); /* TestItem1 */
4361 p = (char *)buf;
4362 es.dwCookie = (DWORD_PTR)&p;
4363 es.dwError = 0;
4364 es.pfnCallback = test_WM_SETTEXT_esCallback;
4365 memset(buf, 0, sizeof(buf));
4366 SendMessageA(hwndRichEdit, EM_STREAMOUT,
4367 (WPARAM)(SF_RTF), (LPARAM)&es);
4368 trace("EM_STREAMOUT produced:\n%s\n", (char *)buf);
4369
4370 /* !ST_SELECTION && !Unicode && \rtf */
4371 setText.codepage = CP_ACP;/* EM_STREAMOUT saved as ANSI string */
4372 getText.codepage = 1200; /* no constant for unicode */
4373 getText.cb = MAX_BUF_LEN;
4374 getText.flags = GT_DEFAULT;
4375 getText.lpDefaultChar = NULL;
4376 getText.lpUsedDefChar = NULL;
4377
4378 setText.flags = 0;
4379 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)buf);
4380 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4381 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4382 ok(lstrcmpW(buf, TestItem1) == 0,
4383 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
4384
4385 /* The following test demonstrates that EM_SETTEXTEX treats text as ASCII if it
4386 * starts with ASCII characters "{\rtf" even when the codepage is unicode. */
4387 setText.codepage = 1200; /* Lie about code page (actual ASCII) */
4388 getText.codepage = CP_ACP;
4389 getText.cb = MAX_BUF_LEN;
4390 getText.flags = GT_DEFAULT;
4391 getText.lpDefaultChar = NULL;
4392 getText.lpUsedDefChar = NULL;
4393
4394 setText.flags = ST_SELECTION;
4395 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
4396 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"{\\rtf not unicode}");
4397 todo_wine ok(result == 11, "EM_SETTEXTEX incorrectly returned %d\n", result);
4398 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)bufACP);
4399 ok(lstrcmpA(bufACP, "not unicode") == 0, "'%s' != 'not unicode'\n", bufACP);
4400
4401 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings with a selection */
4402 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"TestSomeText"); /* TestItem1 */
4403 p = (char *)buf;
4404 es.dwCookie = (DWORD_PTR)&p;
4405 es.dwError = 0;
4406 es.pfnCallback = test_WM_SETTEXT_esCallback;
4407 memset(buf, 0, sizeof(buf));
4408 SendMessageA(hwndRichEdit, EM_STREAMOUT,
4409 (WPARAM)(SF_RTF), (LPARAM)&es);
4410 trace("EM_STREAMOUT produced:\n%s\n", (char *)buf);
4411
4412 /* select some text */
4413 cr.cpMax = 1;
4414 cr.cpMin = 3;
4415 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
4416
4417 /* ST_SELECTION && !Unicode && \rtf */
4418 setText.codepage = CP_ACP;/* EM_STREAMOUT saved as ANSI string */
4419 getText.codepage = 1200; /* no constant for unicode */
4420 getText.cb = MAX_BUF_LEN;
4421 getText.flags = GT_DEFAULT;
4422 getText.lpDefaultChar = NULL;
4423 getText.lpUsedDefChar = NULL;
4424
4425 setText.flags = ST_SELECTION;
4426 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)buf);
4427 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4428 ok_w3("Expected \"%s\" or \"%s\", got \"%s\"\n", TestItem1alt, TestItem1altn, buf);
4429
4430 /* The following test demonstrates that EM_SETTEXTEX replacing a selection */
4431 setText.codepage = 1200; /* no constant for unicode */
4432 getText.codepage = CP_ACP;
4433 getText.cb = MAX_BUF_LEN;
4434
4435 setText.flags = 0;
4436 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1); /* TestItem1 */
4437 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)bufACP);
4438
4439 /* select some text */
4440 cr.cpMax = 1;
4441 cr.cpMin = 3;
4442 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
4443
4444 /* ST_SELECTION && !Unicode && !\rtf */
4445 setText.codepage = CP_ACP;
4446 getText.codepage = 1200; /* no constant for unicode */
4447 getText.cb = MAX_BUF_LEN;
4448 getText.flags = GT_DEFAULT;
4449 getText.lpDefaultChar = NULL;
4450 getText.lpUsedDefChar = NULL;
4451
4452 setText.flags = ST_SELECTION;
4453 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)bufACP);
4454 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4455 ok(lstrcmpW(buf, TestItem1alt) == 0,
4456 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX when"
4457 " using ST_SELECTION and non-Unicode\n");
4458
4459 /* Test setting text using rich text format */
4460 setText.flags = 0;
4461 setText.codepage = CP_ACP;
4462 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"{\\rtf richtext}");
4463 getText.codepage = CP_ACP;
4464 getText.cb = MAX_BUF_LEN;
4465 getText.flags = GT_DEFAULT;
4466 getText.lpDefaultChar = NULL;
4467 getText.lpUsedDefChar = NULL;
4468 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)bufACP);
4469 ok(!strcmp(bufACP, "richtext"), "expected 'richtext' but got '%s'\n", bufACP);
4470
4471 setText.flags = 0;
4472 setText.codepage = CP_ACP;
4473 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"{\\urtf morerichtext}");
4474 getText.codepage = CP_ACP;
4475 getText.cb = MAX_BUF_LEN;
4476 getText.flags = GT_DEFAULT;
4477 getText.lpDefaultChar = NULL;
4478 getText.lpUsedDefChar = NULL;
4479 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)bufACP);
4480 ok(!strcmp(bufACP, "morerichtext"), "expected 'morerichtext' but got '%s'\n", bufACP);
4481
4482 /* test for utf8 text with BOM */
4483 setText.flags = 0;
4484 setText.codepage = CP_ACP;
4485 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"\xef\xbb\xbfTestUTF8WithBOM");
4486 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP);
4487 ok(result == 15, "EM_SETTEXTEX: Test UTF8 with BOM returned %d, expected 15\n", result);
4488 result = strcmp(bufACP, "TestUTF8WithBOM");
4489 ok(result == 0, "EM_SETTEXTEX: Test UTF8 with BOM set wrong text: Result: %s\n", bufACP);
4490
4491 setText.flags = 0;
4492 setText.codepage = CP_UTF8;
4493 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"\xef\xbb\xbfTestUTF8WithBOM");
4494 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP);
4495 ok(result == 15, "EM_SETTEXTEX: Test UTF8 with BOM returned %d, expected 15\n", result);
4496 result = strcmp(bufACP, "TestUTF8WithBOM");
4497 ok(result == 0, "EM_SETTEXTEX: Test UTF8 with BOM set wrong text: Result: %s\n", bufACP);
4498
4499 /* Test multibyte character */
4500 if (!is_lang_japanese)
4501 skip("Skip multibyte character tests on non-Japanese platform\n");
4502 else
4503 {
4504 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
4505 setText.flags = ST_SELECTION;
4506 setText.codepage = CP_ACP;
4507 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"abc\x8e\xf0");
4508 todo_wine ok(result == 5, "EM_SETTEXTEX incorrectly returned %d, expected 5\n", result);
4509 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP);
4510 ok(result == 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result);
4511 ok(!strcmp(bufACP, "abc\x8e\xf0"),
4512 "EM_SETTEXTEX: Test multibyte character set wrong text: Result: %s\n", bufACP);
4513
4514 setText.flags = ST_DEFAULT;
4515 setText.codepage = CP_ACP;
4516 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"abc\x8e\xf0");
4517 ok(result == 1, "EM_SETTEXTEX incorrectly returned %d, expected 1\n", result);
4518 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP);
4519 ok(result == 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result);
4520 ok(!strcmp(bufACP, "abc\x8e\xf0"),
4521 "EM_SETTEXTEX: Test multibyte character set wrong text: Result: %s\n", bufACP);
4522
4523 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
4524 setText.flags = ST_SELECTION;
4525 setText.codepage = CP_ACP;
4526 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"{\\rtf abc\x8e\xf0}");
4527 todo_wine ok(result == 4, "EM_SETTEXTEX incorrectly returned %d, expected 4\n", result);
4528 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP);
4529 ok(result == 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result);
4530 todo_wine ok(!strcmp(bufACP, "abc\x8e\xf0"),
4531 "EM_SETTEXTEX: Test multibyte character set wrong text: Result: %s\n", bufACP);
4532 }
4533
4534 DestroyWindow(hwndRichEdit);
4535
4536 /* Single-line richedit */
4537 hwndRichEdit = new_richedit_with_style(NULL, 0);
4538 setText.flags = ST_DEFAULT;
4539 setText.codepage = CP_ACP;
4540 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"line1\r\nline2");
4541 ok(result == 1, "EM_SETTEXTEX incorrectly returned %d, expected 1\n", result);
4542 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP);
4543 ok(result == 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result);
4544 ok(!strcmp(bufACP, "line1"), "EM_SETTEXTEX: Test single-line text: Result: %s\n", bufACP);
4545 DestroyWindow(hwndRichEdit);
4546}
4547
4548static void test_EM_LIMITTEXT(void)
4549{
4550 int ret;
4551
4552 HWND hwndRichEdit = new_richedit(NULL);
4553
4554 /* The main purpose of this test is to demonstrate that the nonsense in MSDN
4555 * about setting the length to -1 for multiline edit controls doesn't happen.
4556 */
4557
4558 /* Don't check default gettextlimit case. That's done in other tests */
4559
4560 /* Set textlimit to 100 */
4561 SendMessageA(hwndRichEdit, EM_LIMITTEXT, 100, 0);
4562 ret = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4563 ok (ret == 100,
4564 "EM_LIMITTEXT: set to 100, returned: %d, expected: 100\n", ret);
4565
4566 /* Set textlimit to 0 */
4567 SendMessageA(hwndRichEdit, EM_LIMITTEXT, 0, 0);
4568 ret = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4569 ok (ret == 65536,
4570 "EM_LIMITTEXT: set to 0, returned: %d, expected: 65536\n", ret);
4571
4572 /* Set textlimit to -1 */
4573 SendMessageA(hwndRichEdit, EM_LIMITTEXT, -1, 0);
4574 ret = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4575 ok (ret == -1,
4576 "EM_LIMITTEXT: set to -1, returned: %d, expected: -1\n", ret);
4577
4578 /* Set textlimit to -2 */
4579 SendMessageA(hwndRichEdit, EM_LIMITTEXT, -2, 0);
4580 ret = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4581 ok (ret == -2,
4582 "EM_LIMITTEXT: set to -2, returned: %d, expected: -2\n", ret);
4583
4584 DestroyWindow (hwndRichEdit);
4585}
4586
4587
4588static void test_EM_EXLIMITTEXT(void)
4589{
4590 int i, selBegin, selEnd, len1, len2;
4591 int result;
4592 char text[1024 + 1];
4593 char buffer[1024 + 1];
4594 int textlimit = 0; /* multiple of 100 */
4595 HWND hwndRichEdit = new_richedit(NULL);
4596
4597 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4598 ok(32767 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 32767, i); /* default */
4599
4600 textlimit = 256000;
4601 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
4602 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4603 /* set higher */
4604 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i);
4605
4606 textlimit = 1000;
4607 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
4608 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4609 /* set lower */
4610 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i);
4611
4612 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, 0);
4613 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4614 /* default for WParam = 0 */
4615 ok(65536 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 65536, i);
4616
4617 textlimit = sizeof(text)-1;
4618 memset(text, 'W', textlimit);
4619 text[sizeof(text)-1] = 0;
4620 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
4621 /* maxed out text */
4622 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
4623
4624 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); /* select everything */
4625 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
4626 len1 = selEnd - selBegin;
4627
4628 SendMessageA(hwndRichEdit, WM_KEYDOWN, VK_BACK, 1);
4629 SendMessageA(hwndRichEdit, WM_CHAR, VK_BACK, 1);
4630 SendMessageA(hwndRichEdit, WM_KEYUP, VK_BACK, 1);
4631 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
4632 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
4633 len2 = selEnd - selBegin;
4634
4635 ok(len1 != len2,
4636 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4637 len1,len2,i);
4638
4639 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'A', 1);
4640 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 1);
4641 SendMessageA(hwndRichEdit, WM_KEYUP, 'A', 1);
4642 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
4643 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
4644 len1 = selEnd - selBegin;
4645
4646 ok(len1 != len2,
4647 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4648 len1,len2,i);
4649
4650 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'A', 1);
4651 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 1);
4652 SendMessageA(hwndRichEdit, WM_KEYUP, 'A', 1); /* full; should be no effect */
4653 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
4654 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
4655 len2 = selEnd - selBegin;
4656
4657 ok(len1 == len2,
4658 "EM_EXLIMITTEXT: No Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4659 len1,len2,i);
4660
4661 /* set text up to the limit, select all the text, then add a char */
4662 textlimit = 5;
4663 memset(text, 'W', textlimit);
4664 text[textlimit] = 0;
4665 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
4666 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
4667 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
4668 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 1);
4669 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
4670 result = strcmp(buffer, "A");
4671 ok(0 == result, "got string = \"%s\"\n", buffer);
4672
4673 /* WM_SETTEXT not limited */
4674 textlimit = 10;
4675 memset(text, 'W', textlimit);
4676 text[textlimit] = 0;
4677 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit-5);
4678 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
4679 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
4680 i = strlen(buffer);
4681 ok(10 == i, "expected 10 chars\n");
4682 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4683 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
4684
4685 /* try inserting more text at end */
4686 i = SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0);
4687 ok(0 == i, "WM_CHAR wasn't processed\n");
4688 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
4689 i = strlen(buffer);
4690 ok(10 == i, "expected 10 chars, got %i\n", i);
4691 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4692 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
4693
4694 /* try inserting text at beginning */
4695 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 0);
4696 i = SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0);
4697 ok(0 == i, "WM_CHAR wasn't processed\n");
4698 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
4699 i = strlen(buffer);
4700 ok(10 == i, "expected 10 chars, got %i\n", i);
4701 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4702 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
4703
4704 /* WM_CHAR is limited */
4705 textlimit = 1;
4706 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
4707 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); /* select everything */
4708 i = SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0);
4709 ok(0 == i, "WM_CHAR wasn't processed\n");
4710 i = SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0);
4711 ok(0 == i, "WM_CHAR wasn't processed\n");
4712 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
4713 i = strlen(buffer);
4714 ok(1 == i, "expected 1 chars, got %i instead\n", i);
4715
4716 DestroyWindow(hwndRichEdit);
4717}
4718
4719static void test_EM_GETLIMITTEXT(void)
4720{
4721 int i;
4722 HWND hwndRichEdit = new_richedit(NULL);
4723
4724 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4725 ok(32767 == i, "expected: %d, actual: %d\n", 32767, i); /* default value */
4726
4727 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, 50000);
4728 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4729 ok(50000 == i, "expected: %d, actual: %d\n", 50000, i);
4730
4731 DestroyWindow(hwndRichEdit);
4732}
4733
4734static void test_WM_SETFONT(void)
4735{
4736 /* There is no invalid input or error conditions for this function.
4737 * NULL wParam and lParam just fall back to their default values
4738 * It should be noted that even if you use a gibberish name for your fonts
4739 * here, it will still work because the name is stored. They will display as
4740 * System, but will report their name to be whatever they were created as */
4741
4742 HWND hwndRichEdit = new_richedit(NULL);
4743 HFONT testFont1 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
4745 FF_DONTCARE, "Marlett");
4746 HFONT testFont2 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
4748 FF_DONTCARE, "MS Sans Serif");
4749 HFONT testFont3 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
4751 FF_DONTCARE, "Courier");
4752 LOGFONTA sentLogFont;
4753 CHARFORMAT2A returnedCF2A;
4754
4755 returnedCF2A.cbSize = sizeof(returnedCF2A);
4756
4757 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"x");
4758 SendMessageA(hwndRichEdit, WM_SETFONT, (WPARAM)testFont1, MAKELPARAM(TRUE, 0));
4759 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&returnedCF2A);
4760
4761 GetObjectA(testFont1, sizeof(LOGFONTA), &sentLogFont);
4762 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
4763 "EM_GETCHARFORMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n",
4764 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
4765
4766 SendMessageA(hwndRichEdit, WM_SETFONT, (WPARAM)testFont2, MAKELPARAM(TRUE, 0));
4767 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&returnedCF2A);
4768 GetObjectA(testFont2, sizeof(LOGFONTA), &sentLogFont);
4769 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
4770 "EM_GETCHARFORMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n",
4771 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
4772
4773 SendMessageA(hwndRichEdit, WM_SETFONT, (WPARAM)testFont3, MAKELPARAM(TRUE, 0));
4774 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&returnedCF2A);
4775 GetObjectA(testFont3, sizeof(LOGFONTA), &sentLogFont);
4776 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
4777 "EM_GETCHARFORMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n",
4778 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
4779
4780 /* This last test is special since we send in NULL. We clear the variables
4781 * and just compare to "System" instead of the sent in font name. */
4782 ZeroMemory(&returnedCF2A,sizeof(returnedCF2A));
4783 ZeroMemory(&sentLogFont,sizeof(sentLogFont));
4784 returnedCF2A.cbSize = sizeof(returnedCF2A);
4785
4786 SendMessageA(hwndRichEdit, WM_SETFONT, 0, MAKELPARAM((WORD) TRUE, 0));
4787 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&returnedCF2A);
4788 GetObjectA(NULL, sizeof(LOGFONTA), &sentLogFont);
4789 ok (!strcmp("System",returnedCF2A.szFaceName),
4790 "EM_GETCHARFORMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A.szFaceName);
4791
4792 DestroyWindow(hwndRichEdit);
4793}
4794
4795
4797 LPBYTE pbBuff,
4798 LONG cb,
4799 LONG *pcb)
4800{
4801 const char** str = (const char**)dwCookie;
4802 int size = strlen(*str);
4803 if(size > 3) /* let's make it piecemeal for fun */
4804 size = 3;
4805 *pcb = cb;
4806 if (*pcb > size) {
4807 *pcb = size;
4808 }
4809 if (*pcb > 0) {
4810 memcpy(pbBuff, *str, *pcb);
4811 *str += *pcb;
4812 }
4813 return 0;
4814}
4815
4816#define open_clipboard(hwnd) open_clipboard_(__LINE__, hwnd)
4818{
4820 while (1)
4821 {
4824 return ret;
4825 if (GetTickCount() - start > 100)
4826 {
4827 char classname[256];
4828 DWORD le = GetLastError();
4829 HWND clipwnd = GetOpenClipboardWindow();
4830 /* Provide a hint as to the source of interference:
4831 * - The class name would typically be CLIPBRDWNDCLASS if the
4832 * clipboard was opened by a Windows application using the
4833 * ole32 API.
4834 * - And it would be __wine_clipboard_manager if it was opened in
4835 * response to a native application.
4836 */
4838 trace_(__FILE__, line)("%p (%s) opened the clipboard\n", clipwnd, classname);
4839 SetLastError(le);
4840 return ret;
4841 }
4842 Sleep(15);
4843 }
4844}
4845
4846static void test_EM_GETMODIFY(void)
4847{
4848 HWND hwndRichEdit = new_richedit(NULL);
4850 SETTEXTEX setText;
4851 WCHAR TestItem1[] = {'T', 'e', 's', 't',
4852 'S', 'o', 'm', 'e',
4853 'T', 'e', 'x', 't', 0};
4854 WCHAR TestItem2[] = {'T', 'e', 's', 't',
4855 'S', 'o', 'm', 'e',
4856 'O', 't', 'h', 'e', 'r',
4857 'T', 'e', 'x', 't', 0};
4858 const char* streamText = "hello world";
4859 CHARFORMAT2A cf2;
4860 PARAFORMAT2 pf2;
4861 EDITSTREAM es;
4862 BOOL r;
4863 HANDLE hclip;
4864
4865 HFONT testFont = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
4867 FF_DONTCARE, "Courier");
4868
4869 setText.codepage = 1200; /* no constant for unicode */
4870 setText.flags = ST_KEEPUNDO;
4871
4872
4873 /* modify flag shouldn't be set when richedit is first created */
4874 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4875 ok (result == 0,
4876 "EM_GETMODIFY returned non-zero, instead of zero on create\n");
4877
4878 /* setting modify flag should actually set it */
4879 SendMessageA(hwndRichEdit, EM_SETMODIFY, TRUE, 0);
4880 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4881 ok (result != 0,
4882 "EM_GETMODIFY returned zero, instead of non-zero on EM_SETMODIFY\n");
4883
4884 /* clearing modify flag should actually clear it */
4885 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4886 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4887 ok (result == 0,
4888 "EM_GETMODIFY returned non-zero, instead of zero on EM_SETMODIFY\n");
4889
4890 /* setting font doesn't change modify flag */
4891 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4892 SendMessageA(hwndRichEdit, WM_SETFONT, (WPARAM)testFont, MAKELPARAM(TRUE, 0));
4893 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4894 ok (result == 0,
4895 "EM_GETMODIFY returned non-zero, instead of zero on setting font\n");
4896
4897 /* setting text should set modify flag */
4898 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4899 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
4900 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4901 ok (result != 0,
4902 "EM_GETMODIFY returned zero, instead of non-zero on setting text\n");
4903
4904 /* undo previous text doesn't reset modify flag */
4905 SendMessageA(hwndRichEdit, WM_UNDO, 0, 0);
4906 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4907 ok (result != 0,
4908 "EM_GETMODIFY returned zero, instead of non-zero on undo after setting text\n");
4909
4910 /* set text with no flag to keep undo stack should not set modify flag */
4911 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4912 setText.flags = 0;
4913 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
4914 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4915 ok (result == 0,
4916 "EM_GETMODIFY returned non-zero, instead of zero when setting text while not keeping undo stack\n");
4917
4918 /* WM_SETTEXT doesn't modify */
4919 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4920 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem2);
4921 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4922 ok (result == 0,
4923 "EM_GETMODIFY returned non-zero for WM_SETTEXT\n");
4924
4925 /* clear the text */
4926 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4927 SendMessageA(hwndRichEdit, WM_CLEAR, 0, 0);
4928 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4929 ok (result == 0,
4930 "EM_GETMODIFY returned non-zero, instead of zero for WM_CLEAR\n");
4931
4932 /* replace text */
4933 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4934 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
4935 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2);
4936 SendMessageA(hwndRichEdit, EM_REPLACESEL, TRUE, (LPARAM)TestItem2);
4937 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4938 ok (result != 0,
4939 "EM_GETMODIFY returned zero, instead of non-zero when replacing text\n");
4940
4941 /* copy/paste text 1 */
4942 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4943 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2);
4944 SendMessageA(hwndRichEdit, WM_COPY, 0, 0);
4945 send_paste(hwndRichEdit);
4946 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4947 ok (result != 0,
4948 "EM_GETMODIFY returned zero, instead of non-zero when pasting identical text\n");
4949
4950 /* copy/paste text 2 */
4951 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4952 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2);
4953 SendMessageA(hwndRichEdit, WM_COPY, 0, 0);
4954 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 3);
4955 send_paste(hwndRichEdit);
4956 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4957 ok (result != 0,
4958 "EM_GETMODIFY returned zero, instead of non-zero when pasting different text\n");
4959
4960 /* press char */
4961 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4962 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 1);
4963 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0);
4964 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4965 ok (result != 0,
4966 "EM_GETMODIFY returned zero, instead of non-zero for WM_CHAR\n");
4967
4968 /* press del */
4969 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0);
4970 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4971 SendMessageA(hwndRichEdit, WM_KEYDOWN, VK_BACK, 0);
4972 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4973 ok (result != 0,
4974 "EM_GETMODIFY returned zero, instead of non-zero for backspace\n");
4975
4976 /* set char format */
4977 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4978 cf2.cbSize = sizeof(CHARFORMAT2A);
4979 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2);
4980 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
4981 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
4982 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2);
4983 result = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2);
4984 ok(result == 1, "EM_SETCHARFORMAT returned %Id instead of 1\n", result);
4985 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4986 ok (result != 0,
4987 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETCHARFORMAT\n");
4988
4989 /* set para format */
4990 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4991 pf2.cbSize = sizeof(PARAFORMAT2);
4992 SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&pf2);
4993 pf2.dwMask = PFM_ALIGNMENT | pf2.dwMask;
4994 pf2.wAlignment = PFA_RIGHT;
4995 SendMessageA(hwndRichEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
4996 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4997 ok (result == 0,
4998 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETPARAFORMAT\n");
4999
5000 /* EM_STREAM */
5001 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
5002 es.dwCookie = (DWORD_PTR)&streamText;
5003 es.dwError = 0;
5004 es.pfnCallback = test_EM_GETMODIFY_esCallback;
5005 SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es);
5006 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
5007 ok (result != 0,
5008 "EM_GETMODIFY returned zero, instead of non-zero for EM_STREAM\n");
5009
5010 /* Check that the clipboard data is still available after destroying the
5011 * editor window.
5012 */
5013 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"Stayin' alive");
5014 SendMessageA(hwndRichEdit, EM_SETSEL, 8, -1);
5015 SendMessageA(hwndRichEdit, WM_COPY, 0, 0);
5016
5017 DestroyWindow(hwndRichEdit);
5018
5020 ok(r, "OpenClipboard failed le=%lu\n", GetLastError());
5021
5022 hclip = GetClipboardData(CF_TEXT);
5023 todo_wine ok(hclip != NULL, "GetClipboardData() failed le=%lu\n", GetLastError());
5024 if (hclip)
5025 {
5026 const char* str = GlobalLock(hclip);
5027 ok(strcmp(str, "alive") == 0, "unexpected clipboard content: %s\n", str);
5028 GlobalUnlock(hclip);
5029 }
5030
5032}
5033
5041};
5042
5043static const struct exsetsel_s exsetsel_tests[] = {
5044 /* sanity tests */
5045 {5, 10, 10, 5, 10 },
5046 {15, 17, 17, 15, 17 },
5047 /* test cpMax > strlen() */
5048 {0, 100, 18, 0, 18 },
5049 /* test cpMin < 0 && cpMax >= 0 after cpMax > strlen() */
5050 {-1, 1, 17, 17, 17 },
5051 /* test cpMin == cpMax */
5052 {5, 5, 5, 5, 5 },
5053 /* test cpMin < 0 && cpMax >= 0 (bug 4462) */
5054 {-1, 0, 5, 5, 5 },
5055 {-1, 17, 5, 5, 5 },
5056 {-1, 18, 5, 5, 5 },
5057 /* test cpMin < 0 && cpMax < 0 */
5058 {-1, -1, 17, 17, 17 },
5059 {-4, -5, 17, 17, 17 },
5060 /* test cpMin >=0 && cpMax < 0 (bug 6814) */
5061 {0, -1, 18, 0, 18 },
5062 {17, -5, 18, 17, 18 },
5063 {18, -3, 17, 17, 17 },
5064 /* test if cpMin > cpMax */
5065 {15, 19, 18, 15, 18 },
5066 {19, 15, 18, 15, 18 },
5067 /* cpMin == strlen() && cpMax > cpMin */
5068 {17, 18, 18, 17, 18 },
5069 {17, 50, 18, 17, 18 },
5070};
5071
5072static void check_EM_EXSETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) {
5073 CHARRANGE cr;
5075 int start, end;
5076
5077 cr.cpMin = setsel->min;
5078 cr.cpMax = setsel->max;
5080
5081 ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %Id actual: %Id\n", id, setsel->expected_retval, result);
5082
5084
5085 todo_wine_if (setsel->todo)
5086 ok(start == setsel->expected_getsel_start && end == setsel->expected_getsel_end, "EM_EXSETSEL(%d): expected (%d,%d) actual:(%d,%d)\n",
5087 id, setsel->expected_getsel_start, setsel->expected_getsel_end, start, end);
5088}
5089
5090static void test_EM_EXSETSEL(void)
5091{
5092 HWND hwndRichEdit = new_richedit(NULL);
5093 int i;
5094 const int num_tests = ARRAY_SIZE(exsetsel_tests);
5095
5096 /* sending some text to the window */
5097 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection");
5098 /* 01234567890123456*/
5099 /* 10 */
5100
5101 for (i = 0; i < num_tests; i++) {
5102 check_EM_EXSETSEL(hwndRichEdit, &exsetsel_tests[i], i);
5103 }
5104
5105 if (!is_lang_japanese)
5106 skip("Skip multibyte character tests on non-Japanese platform\n");
5107 else
5108 {
5109 CHARRANGE cr;
5110 char bufA[MAX_BUF_LEN] = {0};
5112
5113 /* Test with multibyte character */
5114 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk");
5115 /* 012345 6 78901 */
5116 cr.cpMin = 4; cr.cpMax = 8;
5117 result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
5118 ok(result == 8, "EM_EXSETSEL return %Id expected 8\n", result);
5119 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)bufA);
5120 ok(!strcmp(bufA, "ef\x8e\xf0g"), "EM_GETSELTEXT return incorrect string\n");
5121 SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5122 ok(cr.cpMin == 4, "Selection start incorrectly: %ld expected 4\n", cr.cpMin);
5123 ok(cr.cpMax == 8, "Selection end incorrectly: %ld expected 8\n", cr.cpMax);
5124 }
5125
5126 DestroyWindow(hwndRichEdit);
5127}
5128
5129static void check_EM_SETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) {
5131 int start, end;
5132
5133 result = SendMessageA(hwnd, EM_SETSEL, setsel->min, setsel->max);
5134
5135 ok(result == setsel->expected_retval, "EM_SETSEL(%d): expected: %Id actual: %Id\n", id, setsel->expected_retval, result);
5136
5138
5139 todo_wine_if (setsel->todo)
5140 ok(start == setsel->expected_getsel_start && end == setsel->expected_getsel_end, "EM_SETSEL(%d): expected (%d,%d) actual:(%d,%d)\n",
5141 id, setsel->expected_getsel_start, setsel->expected_getsel_end, start, end);
5142}
5143
5144/* When the selection is out of the windows view, the scrollbar should move. */
5146{
5147 int oldY;
5148 int curY;
5149 const char textwithlines[] = "This is a text\n"
5150 "with lines\n"
5151 "I expect this text\n"
5152 "to be\nlarge\nenough\n";
5153
5154 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)textwithlines);
5155 oldY = get_scroll_pos_y(hwnd);
5156 SendMessageA(hwnd, EM_SETSEL, 59, 59);
5157 curY = get_scroll_pos_y(hwnd);
5158 ok(oldY < curY, "oldY %d >= curY %d\n", oldY, curY);
5159}
5160
5161static void test_EM_SETSEL(void)
5162{
5163 char buffA[32] = {0};
5164 HWND hwndRichEdit = new_richedit(NULL);
5165 int i;
5166 const int num_tests = ARRAY_SIZE(exsetsel_tests);
5167
5168 /* sending some text to the window */
5169 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection");
5170 /* 01234567890123456*/
5171 /* 10 */
5172
5173 for (i = 0; i < num_tests; i++) {
5174 check_EM_SETSEL(hwndRichEdit, &exsetsel_tests[i], i);
5175 }
5176
5177 SendMessageA(hwndRichEdit, EM_SETSEL, 17, 18);
5178 buffA[0] = 123;
5179 SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffA);
5180 ok(buffA[0] == 0, "selection text %s\n", buffA);
5181
5182 if (!is_lang_japanese)
5183 skip("Skip multibyte character tests on non-Japanese platform\n");
5184 else
5185 {
5186 int sel_start, sel_end;
5187 LRESULT result;
5188
5189 /* Test with multibyte character */
5190 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk");
5191 /* 012345 6 78901 */
5192 result = SendMessageA(hwndRichEdit, EM_SETSEL, 4, 8);
5193 ok(result == 8, "EM_SETSEL return %Id expected 8\n", result);
5194 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffA);
5195 ok(!strcmp(buffA, "ef\x8e\xf0g"), "EM_GETSELTEXT return incorrect string\n");
5196 result = SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
5197 ok(sel_start == 4, "Selection start incorrectly: %d expected 4\n", sel_start);
5198 ok(sel_end == 8, "Selection end incorrectly: %d expected 8\n", sel_end);
5199 }
5200
5201 check_EM_SETSEL_multiline(hwndRichEdit);
5202
5203 DestroyWindow(hwndRichEdit);
5204}
5205
5206static void test_EM_REPLACESEL(int redraw)
5207{
5208 HWND hwndRichEdit = new_richedit(NULL);
5209 char buffer[1024] = {0};
5210 int r;
5211 GETTEXTEX getText;
5212 CHARRANGE cr;
5213 CHAR rtfstream[] = "{\\rtf1 TestSomeText}";
5214 CHAR urtfstream[] = "{\\urtf1 TestSomeText}";
5215
5216 /* sending some text to the window */
5217 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection");
5218 /* 01234567890123456*/
5219 /* 10 */
5220
5221 /* FIXME add more tests */
5222 SendMessageA(hwndRichEdit, EM_SETSEL, 7, 17);
5223 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, 0);
5224 ok(0 == r, "EM_REPLACESEL returned %d, expected 0\n", r);
5225 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5226 r = strcmp(buffer, "testing");
5227 ok(0 == r, "expected %d, got %d\n", 0, r);
5228
5229 DestroyWindow(hwndRichEdit);
5230
5231 hwndRichEdit = new_richedit(NULL);
5232
5233 trace("Testing EM_REPLACESEL behavior with redraw=%d\n", redraw);
5234 SendMessageA(hwndRichEdit, WM_SETREDRAW, redraw, 0);
5235
5236 /* Test behavior with carriage returns and newlines */
5237 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5238 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"RichEdit1");
5239 ok(9 == r, "EM_REPLACESEL returned %d, expected 9\n", r);
5240 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5241 r = strcmp(buffer, "RichEdit1");
5242 ok(0 == r, "expected %d, got %d\n", 0, r);
5243 getText.cb = 1024;
5244 getText.codepage = CP_ACP;
5245 getText.flags = GT_DEFAULT;
5246 getText.lpDefaultChar = NULL;
5247 getText.lpUsedDefChar = NULL;
5248 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5249 ok(strcmp(buffer, "RichEdit1") == 0,
5250 "EM_GETTEXTEX results not what was set by EM_REPLACESEL\n");
5251
5252 /* Test number of lines reported after EM_REPLACESEL */
5253 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5254 ok(r == 1, "EM_GETLINECOUNT returned %d, expected 1\n", r);
5255
5256 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5257 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"RichEdit1\r");
5258 ok(10 == r, "EM_REPLACESEL returned %d, expected 10\n", r);
5259 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5260 r = strcmp(buffer, "RichEdit1\r\n");
5261 ok(0 == r, "expected %d, got %d\n", 0, r);
5262 getText.cb = 1024;
5263 getText.codepage = CP_ACP;
5264 getText.flags = GT_DEFAULT;
5265 getText.lpDefaultChar = NULL;
5266 getText.lpUsedDefChar = NULL;
5267 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5268 ok(strcmp(buffer, "RichEdit1\r") == 0,
5269 "EM_GETTEXTEX returned incorrect string\n");
5270
5271 /* Test number of lines reported after EM_REPLACESEL */
5272 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5273 ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r);
5274
5275 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5276 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"RichEdit1\r\n");
5277 ok(r == 11, "EM_REPLACESEL returned %d, expected 11\n", r);
5278
5279 /* Test number of lines reported after EM_REPLACESEL */
5280 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5281 ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r);
5282
5283 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5284 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5285 ok(cr.cpMin == 10, "EM_EXGETSEL returned cpMin=%ld, expected 10\n", cr.cpMin);
5286 ok(cr.cpMax == 10, "EM_EXGETSEL returned cpMax=%ld, expected 10\n", cr.cpMax);
5287
5288 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5289 r = strcmp(buffer, "RichEdit1\r\n");
5290 ok(0 == r, "expected %d, got %d\n", 0, r);
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, "RichEdit1\r") == 0,
5298 "EM_GETTEXTEX returned incorrect string\n");
5299
5300 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5301 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5302 ok(cr.cpMin == 10, "EM_EXGETSEL returned cpMin=%ld, expected 10\n", cr.cpMin);
5303 ok(cr.cpMax == 10, "EM_EXGETSEL returned cpMax=%ld, expected 10\n", cr.cpMax);
5304
5305 /* The following tests show that richedit should handle the special \r\r\n
5306 sequence by turning it into a single space on insertion. However,
5307 EM_REPLACESEL on WinXP returns the number of characters in the original
5308 string.
5309 */
5310
5311 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5312 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r");
5313 ok(2 == r, "EM_REPLACESEL returned %d, expected 4\n", r);
5314 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5315 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5316 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%ld, expected 2\n", cr.cpMin);
5317 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%ld, expected 2\n", cr.cpMax);
5318
5319 /* Test the actual string */
5320 getText.cb = 1024;
5321 getText.codepage = CP_ACP;
5322 getText.flags = GT_DEFAULT;
5323 getText.lpDefaultChar = NULL;
5324 getText.lpUsedDefChar = NULL;
5325 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5326 ok(strcmp(buffer, "\r\r") == 0,
5327 "EM_GETTEXTEX returned incorrect string\n");
5328
5329 /* Test number of lines reported after EM_REPLACESEL */
5330 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5331 ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r);
5332
5333 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5334 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r\n");
5335 ok(r == 3, "EM_REPLACESEL returned %d, expected 3\n", r);
5336 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5337 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5338 ok(cr.cpMin == 1, "EM_EXGETSEL returned cpMin=%ld, expected 1\n", cr.cpMin);
5339 ok(cr.cpMax == 1, "EM_EXGETSEL returned cpMax=%ld, expected 1\n", cr.cpMax);
5340
5341 /* Test the actual string */
5342 getText.cb = 1024;
5343 getText.codepage = CP_ACP;
5344 getText.flags = GT_DEFAULT;
5345 getText.lpDefaultChar = NULL;
5346 getText.lpUsedDefChar = NULL;
5347 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5348 ok(strcmp(buffer, " ") == 0,
5349 "EM_GETTEXTEX returned incorrect string\n");
5350
5351 /* Test number of lines reported after EM_REPLACESEL */
5352 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5353 ok(r == 1, "EM_GETLINECOUNT returned %d, expected 1\n", r);
5354
5355 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5356 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r\r\r\r\n\r\r\r");
5357 ok(r == 9, "EM_REPLACESEL returned %d, expected 9\n", r);
5358 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5359 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5360 ok(cr.cpMin == 7, "EM_EXGETSEL returned cpMin=%ld, expected 7\n", cr.cpMin);
5361 ok(cr.cpMax == 7, "EM_EXGETSEL returned cpMax=%ld, expected 7\n", cr.cpMax);
5362
5363 /* Test the actual string */
5364 getText.cb = 1024;
5365 getText.codepage = CP_ACP;
5366 getText.flags = GT_DEFAULT;
5367 getText.lpDefaultChar = NULL;
5368 getText.lpUsedDefChar = NULL;
5369 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5370 ok(strcmp(buffer, "\r\r\r \r\r\r") == 0,
5371 "EM_GETTEXTEX returned incorrect string\n");
5372
5373 /* Test number of lines reported after EM_REPLACESEL */
5374 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5375 ok(r == 7, "EM_GETLINECOUNT returned %d, expected 7\n", r);
5376
5377 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5378 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r\n\r\n");
5379 ok(r == 5, "EM_REPLACESEL returned %d, expected 5\n", r);
5380 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5381 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5382 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%ld, expected 2\n", cr.cpMin);
5383 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%ld, expected 2\n", cr.cpMax);
5384
5385 /* Test the actual string */
5386 getText.cb = 1024;
5387 getText.codepage = CP_ACP;
5388 getText.flags = GT_DEFAULT;
5389 getText.lpDefaultChar = NULL;
5390 getText.lpUsedDefChar = NULL;
5391 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5392 ok(strcmp(buffer, " \r") == 0,
5393 "EM_GETTEXTEX returned incorrect string\n");
5394
5395 /* Test number of lines reported after EM_REPLACESEL */
5396 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5397 ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r);
5398
5399 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5400 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r\n\r\r");
5401 ok(r == 5, "EM_REPLACESEL returned %d, expected 5\n", r);
5402 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5403 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5404 ok(cr.cpMin == 3, "EM_EXGETSEL returned cpMin=%ld, expected 3\n", cr.cpMin);
5405 ok(cr.cpMax == 3, "EM_EXGETSEL returned cpMax=%ld, expected 3\n", cr.cpMax);
5406
5407 /* Test the actual string */
5408 getText.cb = 1024;
5409 getText.codepage = CP_ACP;
5410 getText.flags = GT_DEFAULT;
5411 getText.lpDefaultChar = NULL;
5412 getText.lpUsedDefChar = NULL;
5413 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5414 ok(strcmp(buffer, " \r\r") == 0,
5415 "EM_GETTEXTEX returned incorrect string\n");
5416
5417 /* Test number of lines reported after EM_REPLACESEL */
5418 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5419 ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r);
5420
5421 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5422 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\rX\r\n\r\r");
5423 ok(r == 6, "EM_REPLACESEL returned %d, expected 6\n", r);
5424 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5425 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5426 ok(cr.cpMin == 5, "EM_EXGETSEL returned cpMin=%ld, expected 5\n", cr.cpMin);
5427 ok(cr.cpMax == 5, "EM_EXGETSEL returned cpMax=%ld, expected 5\n", cr.cpMax);
5428
5429 /* Test the actual string */
5430 getText.cb = 1024;
5431 getText.codepage = CP_ACP;
5432 getText.flags = GT_DEFAULT;
5433 getText.lpDefaultChar = NULL;
5434 getText.lpUsedDefChar = NULL;
5435 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5436 ok(strcmp(buffer, "\rX\r\r\r") == 0,
5437 "EM_GETTEXTEX returned incorrect string\n");
5438
5439 /* Test number of lines reported after EM_REPLACESEL */
5440 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5441 ok(r == 5, "EM_GETLINECOUNT returned %d, expected 5\n", r);
5442
5443 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5444 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\n\n");
5445 ok(2 == r, "EM_REPLACESEL returned %d, expected 2\n", r);
5446 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5447 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5448 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%ld, expected 2\n", cr.cpMin);
5449 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%ld, expected 2\n", cr.cpMax);
5450
5451 /* Test the actual string */
5452 getText.cb = 1024;
5453 getText.codepage = CP_ACP;
5454 getText.flags = GT_DEFAULT;
5455 getText.lpDefaultChar = NULL;
5456 getText.lpUsedDefChar = NULL;
5457 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5458 ok(strcmp(buffer, "\r\r") == 0,
5459 "EM_GETTEXTEX returned incorrect string\n");
5460
5461 /* Test number of lines reported after EM_REPLACESEL */
5462 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5463 ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r);
5464
5465 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5466 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\n\n\n\n\r\r\r\r\n");
5467 ok(r == 9, "EM_REPLACESEL returned %d, expected 9\n", r);
5468 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5469 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5470 ok(cr.cpMin == 7, "EM_EXGETSEL returned cpMin=%ld, expected 7\n", cr.cpMin);
5471 ok(cr.cpMax == 7, "EM_EXGETSEL returned cpMax=%ld, expected 7\n", cr.cpMax);
5472
5473 /* Test the actual string */
5474 getText.cb = 1024;
5475 getText.codepage = CP_ACP;
5476 getText.flags = GT_DEFAULT;
5477 getText.lpDefaultChar = NULL;
5478 getText.lpUsedDefChar = NULL;
5479 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5480 ok(strcmp(buffer, "\r\r\r\r\r\r ") == 0,
5481 "EM_GETTEXTEX returned incorrect string\n");
5482
5483 /* Test number of lines reported after EM_REPLACESEL */
5484 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5485 ok(r == 7, "EM_GETLINECOUNT returned %d, expected 7\n", r);
5486
5487 /* Test with multibyte character */
5488 if (!is_lang_japanese)
5489 skip("Skip multibyte character tests on non-Japanese platform\n");
5490 else
5491 {
5492 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5493 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"abc\x8e\xf0");
5494 todo_wine ok(r == 5, "EM_REPLACESEL returned %d, expected 5\n", r);
5495 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5496 ok(r == 0, "EM_EXGETSEL returned %d, expected 0\n", r);
5497 ok(cr.cpMin == 4, "EM_EXGETSEL returned cpMin=%ld, expected 4\n", cr.cpMin);
5498 ok(cr.cpMax == 4, "EM_EXGETSEL returned cpMax=%ld, expected 4\n", cr.cpMax);
5499 r = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5500 ok(!strcmp(buffer, "abc\x8e\xf0"), "WM_GETTEXT returned incorrect string\n");
5501 ok(r == 5, "WM_GETTEXT returned %d, expected 5\n", r);
5502
5503 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5504 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"{\\rtf abc\x8e\xf0}");
5505 todo_wine ok(r == 4, "EM_REPLACESEL returned %d, expected 4\n", r);
5506 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5507 ok(r == 0, "EM_EXGETSEL returned %d, expected 0\n", r);
5508 todo_wine ok(cr.cpMin == 4, "EM_EXGETSEL returned cpMin=%ld, expected 4\n", cr.cpMin);
5509 todo_wine ok(cr.cpMax == 4, "EM_EXGETSEL returned cpMax=%ld, expected 4\n", cr.cpMax);
5510 r = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5511 todo_wine ok(!strcmp(buffer, "abc\x8e\xf0"), "WM_GETTEXT returned incorrect string\n");
5512 todo_wine ok(r == 5, "WM_GETTEXT returned %d, expected 5\n", r);
5513 }
5514
5515 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5516 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)rtfstream);
5517 todo_wine ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r);
5518 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5519 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5520 todo_wine ok(cr.cpMin == 12, "EM_EXGETSEL returned cpMin=%ld, expected 12\n", cr.cpMin);
5521 todo_wine ok(cr.cpMax == 12, "EM_EXGETSEL returned cpMax=%ld, expected 12\n", cr.cpMax);
5522 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5523 todo_wine ok(!strcmp(buffer, "TestSomeText"), "WM_GETTEXT returned incorrect string\n");
5524
5525 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5526 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)urtfstream);
5527 todo_wine ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r);
5528 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5529 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5530 todo_wine ok(cr.cpMin == 12, "EM_EXGETSEL returned cpMin=%ld, expected 12\n", cr.cpMin);
5531 todo_wine ok(cr.cpMax == 12, "EM_EXGETSEL returned cpMax=%ld, expected 12\n", cr.cpMax);
5532 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5533 todo_wine ok(!strcmp(buffer, "TestSomeText"), "WM_GETTEXT returned incorrect string\n");
5534
5535 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"Wine");
5536 SendMessageA(hwndRichEdit, EM_SETSEL, 1, 2);
5537 todo_wine r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)rtfstream);
5538 todo_wine ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r);
5539 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5540 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5541 todo_wine ok(cr.cpMin == 13, "EM_EXGETSEL returned cpMin=%ld, expected 13\n", cr.cpMin);
5542 todo_wine ok(cr.cpMax == 13, "EM_EXGETSEL returned cpMax=%ld, expected 13\n", cr.cpMax);
5543 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5544 todo_wine ok(!strcmp(buffer, "WTestSomeTextne"), "WM_GETTEXT returned incorrect string\n");
5545
5546 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"{\\rtf1 Wine}");
5547 SendMessageA(hwndRichEdit, EM_SETSEL, 1, 2);
5548 todo_wine r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)rtfstream);
5549 todo_wine ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r);
5550 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5551 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5552 todo_wine ok(cr.cpMin == 13, "EM_EXGETSEL returned cpMin=%ld, expected 13\n", cr.cpMin);
5553 todo_wine ok(cr.cpMax == 13, "EM_EXGETSEL returned cpMax=%ld, expected 13\n", cr.cpMax);
5554 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5555 todo_wine ok(!strcmp(buffer, "WTestSomeTextne"), "WM_GETTEXT returned incorrect string\n");
5556
5557 if (!redraw)
5558 /* This is needed to avoid interfering with keybd_event calls
5559 * on other tests that simulate keyboard events. */
5560 SendMessageA(hwndRichEdit, WM_SETREDRAW, TRUE, 0);
5561
5562 DestroyWindow(hwndRichEdit);
5563
5564 /* Single-line richedit */
5565 hwndRichEdit = new_richedit_with_style(NULL, 0);
5566 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"line1\r\nline2");
5567 ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r);
5568 r = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5569 ok(r == 5, "WM_GETTEXT returned %d, expected 5\n", r);
5570 ok(!strcmp(buffer, "line1"), "WM_GETTEXT returned incorrect string '%s'\n", buffer);
5571 DestroyWindow(hwndRichEdit);
5572}
5573
5574/* Native riched20 inspects the keyboard state (e.g. GetKeyState)
5575 * to test the state of the modifiers (Ctrl/Alt/Shift).
5576 *
5577 * Therefore Ctrl-<key> keystrokes need to be simulated with
5578 * keybd_event or by using SetKeyboardState to set the modifiers
5579 * and SendMessage to simulate the keystrokes.
5580 */
5581static LRESULT send_ctrl_key(HWND hwnd, UINT key)
5582{
5583 LRESULT result;
5584 hold_key(VK_CONTROL);
5585 result = SendMessageA(hwnd, WM_KEYDOWN, key, 1);
5586 release_key(VK_CONTROL);
5587 return result;
5588}
5589
5590static void test_WM_PASTE(void)
5591{
5592 int result;
5593 char buffer[1024] = {0};
5594 const char* text1 = "testing paste\r";
5595 const char* text1_step1 = "testing paste\r\ntesting paste\r\n";
5596 const char* text1_after = "testing paste\r\n";
5597 const char* text2 = "testing paste\r\rtesting paste";
5598 const char* text2_after = "testing paste\r\n\r\ntesting paste";
5599 const char* text3 = "testing paste\r\npaste\r\ntesting paste";
5600 HWND hwndRichEdit = new_richedit(NULL);
5601
5602 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
5603 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 14);
5604
5605 send_ctrl_key(hwndRichEdit, 'C'); /* Copy */
5606 SendMessageA(hwndRichEdit, EM_SETSEL, 14, 14);
5607 send_ctrl_key(hwndRichEdit, 'V'); /* Paste */
5608 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5609 /* Pasted text should be visible at this step */
5610 ok(strcmp(text1_step1, buffer) == 0, "1:Ctrl-V %s\n", wine_dbgstr_a(buffer));
5611
5612 send_ctrl_key(hwndRichEdit, 'Z'); /* Undo */
5613 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5614 /* Text should be the same as before (except for \r -> \r\n conversion) */
5615 ok(strcmp(text1_after, buffer) == 0, "1:Ctrl-Z %s\n", wine_dbgstr_a(buffer));
5616
5617 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
5618 SendMessageA(hwndRichEdit, EM_SETSEL, 8, 13);
5619 send_ctrl_key(hwndRichEdit, 'C'); /* Copy */
5620 SendMessageA(hwndRichEdit, EM_SETSEL, 14, 14);
5621 send_ctrl_key(hwndRichEdit, 'V'); /* Paste */
5622 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5623 /* Pasted text should be visible at this step */
5624 ok(strcmp(text3, buffer) == 0, "2:Ctrl-V %s\n", wine_dbgstr_a(buffer));
5625 send_ctrl_key(hwndRichEdit, 'Z'); /* Undo */
5626 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5627 /* Text should be the same as before (except for \r -> \r\n conversion) */
5628 ok(strcmp(text2_after, buffer) == 0, "2:Ctrl-Z %s\n", wine_dbgstr_a(buffer));
5629 send_ctrl_key(hwndRichEdit, 'Y'); /* Redo */
5630 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5631 /* Text should revert to post-paste state */
5632 ok(strcmp(buffer,text3) == 0, "2:Ctrl-Y %s\n", wine_dbgstr_a(buffer));
5633
5634 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5635 /* Send WM_CHAR to simulate Ctrl-V */
5636 SendMessageA(hwndRichEdit, WM_CHAR, 22,
5637 (MapVirtualKeyA('V', MAPVK_VK_TO_VSC) << 16) | 1);
5638 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5639 /* Shouldn't paste because pasting is handled by WM_KEYDOWN */
5640 ok(strcmp(buffer, "") == 0, "3:Ctrl-V %s\n", wine_dbgstr_a(buffer));
5641
5642 /* Send keystrokes with WM_KEYDOWN after setting the modifiers
5643 * with SetKeyboard state. */
5644
5645 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5646 /* Simulates paste (Ctrl-V) */
5647 hold_key(VK_CONTROL);
5648 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'V',
5649 (MapVirtualKeyA('V', MAPVK_VK_TO_VSC) << 16) | 1);
5650 release_key(VK_CONTROL);
5651 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5652 ok(strcmp(buffer, "paste") == 0, "VK:Ctrl-V %s\n", wine_dbgstr_a(buffer));
5653
5654 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
5655 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 7);
5656 /* Simulates copy (Ctrl-C) */
5657 hold_key(VK_CONTROL);
5658 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'C',
5659 (MapVirtualKeyA('C', MAPVK_VK_TO_VSC) << 16) | 1);
5660 release_key(VK_CONTROL);
5661 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5662 send_paste(hwndRichEdit);
5663 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5664 ok(strcmp(buffer, "testing") == 0, "VK:Ctrl-C %s\n", wine_dbgstr_a(buffer));
5665
5666 /* Cut with WM_KEYDOWN to simulate Ctrl-X */
5667 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"cut");
5668 /* Simulates select all (Ctrl-A) */
5669 hold_key(VK_CONTROL);
5670 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'A',
5671 (MapVirtualKeyA('A', MAPVK_VK_TO_VSC) << 16) | 1);
5672 /* Simulates select cut (Ctrl-X) */
5673 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'X',
5674 (MapVirtualKeyA('X', MAPVK_VK_TO_VSC) << 16) | 1);
5675 release_key(VK_CONTROL);
5676 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5677 ok(strcmp(buffer, "") == 0, "VK:Ctrl-A,X %s\n", wine_dbgstr_a(buffer));
5678 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5679 send_paste(hwndRichEdit);
5680 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5681 ok(strcmp(buffer, "cut\r\n") == 0, "VK:paste %s\n", wine_dbgstr_a(buffer));
5682 /* Simulates undo (Ctrl-Z) */
5683 hold_key(VK_CONTROL);
5684 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'Z',
5685 (MapVirtualKeyA('Z', MAPVK_VK_TO_VSC) << 16) | 1);
5686 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5687 ok(strcmp(buffer, "") == 0, "VK:Ctrl-Z %s\n", wine_dbgstr_a(buffer));
5688 /* Simulates redo (Ctrl-Y) */
5689 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'Y',
5690 (MapVirtualKeyA('Y', MAPVK_VK_TO_VSC) << 16) | 1);
5691 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5692 ok(strcmp(buffer, "cut\r\n") == 0, "VK:Ctrl-Y %s\n", wine_dbgstr_a(buffer));
5693 release_key(VK_CONTROL);
5694
5695 /* Copy multiline text to clipboard for future use */
5696 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text3);
5697 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
5698 SendMessageA(hwndRichEdit, WM_COPY, 0, 0);
5699 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 0);
5700
5701 /* Paste into read-only control */
5702 result = SendMessageA(hwndRichEdit, EM_SETREADONLY, TRUE, 0);
5703 ok(result, "ro:set failed\n");
5704 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
5705 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5706 ok(strcmp(buffer, text3) == 0, "ro:paste %s\n", wine_dbgstr_a(buffer));
5707
5708 /* Cut from read-only control */
5709 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
5710 SendMessageA(hwndRichEdit, WM_CUT, 0, 0);
5711 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5712 ok(strcmp(buffer, text3) == 0, "ro:cut %s\n", wine_dbgstr_a(buffer));
5713
5714 /* FIXME: Wine doesn't flush Ole clipboard when window is destroyed so do it manually */
5715 OleFlushClipboard();
5716 DestroyWindow(hwndRichEdit);
5717
5718 /* Paste multi-line text into single-line control */
5719 hwndRichEdit = new_richedit_with_style(NULL, 0);
5720 send_paste(hwndRichEdit);
5721 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5722 ok(strcmp(buffer, "testing paste") == 0, "multi:paste %s\n", wine_dbgstr_a(buffer));
5723 DestroyWindow(hwndRichEdit);
5724}
5725
5726static void test_EM_FORMATRANGE(void)
5727{
5728 int r, i, tpp_x, tpp_y;
5729 HDC hdc;
5730 HWND hwndRichEdit = new_richedit(NULL);
5731 FORMATRANGE fr;
5732 BOOL skip_non_english;
5733 static const struct {
5734 const char *string; /* The string */
5735 int first; /* First 'pagebreak', 0 for don't care */
5736 int second; /* Second 'pagebreak', 0 for don't care */
5737 } fmtstrings[] = {
5738 {"WINE wine", 0, 0},
5739 {"WINE wineWine", 0, 0},
5740 {"WINE\r\nwine\r\nwine", 5, 10},
5741 {"WINE\r\nWINEwine\r\nWINEwine", 5, 14},
5742 {"WINE\r\n\r\nwine\r\nwine", 5, 6}
5743 };
5744
5745 skip_non_english = (PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH);
5746 if (skip_non_english)
5747 skip("Skipping some tests on non-English platform\n");
5748
5749 hdc = GetDC(hwndRichEdit);
5750 ok(hdc != NULL, "Could not get HDC\n");
5751
5752 /* Calculate the twips per pixel */
5753 tpp_x = 1440 / GetDeviceCaps(hdc, LOGPIXELSX);
5754 tpp_y = 1440 / GetDeviceCaps(hdc, LOGPIXELSY);
5755
5756 /* Test the simple case where all the text fits in the page rect. */
5757 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
5758 fr.hdc = fr.hdcTarget = hdc;
5759 fr.rc.top = fr.rcPage.top = fr.rc.left = fr.rcPage.left = 0;
5760 fr.rc.right = fr.rcPage.right = 500 * tpp_x;
5761 fr.rc.bottom = fr.rcPage.bottom = 500 * tpp_y;
5762 fr.chrg.cpMin = 0;
5763 fr.chrg.cpMax = -1;
5764 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, FALSE, (LPARAM)&fr);
5765 todo_wine ok(r == 2, "r=%d expected r=2\n", r);
5766
5767 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"ab");
5768 fr.rc.bottom = fr.rcPage.bottom;
5769 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, FALSE, (LPARAM)&fr);
5770 todo_wine ok(r == 3, "r=%d expected r=3\n", r);
5771
5772 SendMessageA(hwndRichEdit, EM_FORMATRANGE, FALSE, 0);
5773
5774 for (i = 0; i < ARRAY_SIZE(fmtstrings); i++)
5775 {
5776 GETTEXTLENGTHEX gtl;
5777 SIZE stringsize;
5778 int len;
5779
5780 winetest_push_context("%d", i);
5781 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)fmtstrings[i].string);
5782
5783 gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
5784 gtl.codepage = CP_ACP;
5785 len = SendMessageA(hwndRichEdit, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
5786
5787 /* Get some size information for the string */
5788 GetTextExtentPoint32A(hdc, fmtstrings[i].string, strlen(fmtstrings[i].string), &stringsize);
5789
5790 /* Define the box to be half the width needed and a bit larger than the height.
5791 * Changes to the width means we have at least 2 pages. Changes to the height
5792 * is done so we can check the changing of fr.rc.bottom.
5793 */
5794 fr.hdc = fr.hdcTarget = hdc;
5795 fr.rc.top = fr.rcPage.top = fr.rc.left = fr.rcPage.left = 0;
5796 fr.rc.right = fr.rcPage.right = (stringsize.cx / 2) * tpp_x;
5797 fr.rc.bottom = fr.rcPage.bottom = (stringsize.cy + 10) * tpp_y;
5798
5799 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, TRUE, 0);
5800 todo_wine {
5801 ok(r == len, "Expected %d, got %d\n", len, r);
5802 }
5803
5804 /* We know that the page can't hold the full string. See how many characters
5805 * are on the first one
5806 */
5807 fr.chrg.cpMin = 0;
5808 fr.chrg.cpMax = -1;
5809 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM)&fr);
5810 todo_wine {
5811 if (! skip_non_english)
5812 ok(fr.rc.bottom == (stringsize.cy * tpp_y), "Expected bottom to be %ld, got %ld\n", (stringsize.cy * tpp_y), fr.rc.bottom);
5813 }
5814 if (fmtstrings[i].first)
5815 todo_wine {
5816 ok(r == fmtstrings[i].first, "Expected %d, got %d\n", fmtstrings[i].first, r);
5817 }
5818 else
5819 ok(r < len, "Expected < %d, got %d\n", len, r);
5820
5821 /* Do another page */
5822 fr.chrg.cpMin = r;
5823 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM)&fr);
5824 if (fmtstrings[i].second)
5825 todo_wine {
5826 ok(r == fmtstrings[i].second, "Expected %d, got %d\n", fmtstrings[i].second, r);
5827 }
5828 else if (! skip_non_english)
5829 ok (r < len, "Expected < %d, got %d\n", len, r);
5830
5831 /* There is at least one more page, but we don't care */
5832
5833 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, TRUE, 0);
5834 todo_wine {
5835 ok(r == len, "Expected %d, got %d\n", len, r);
5836 }
5837 winetest_pop_context();
5838 }
5839
5840 ReleaseDC(NULL, hdc);
5841 DestroyWindow(hwndRichEdit);
5842}
5843
5844static int nCallbackCount = 0;
5845
5846static DWORD CALLBACK EditStreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff,
5847 LONG cb, LONG* pcb)
5848{
5849 const char text[] = {'t','e','s','t'};
5850
5851 if (sizeof(text) <= cb)
5852 {
5853 if ((int)dwCookie != nCallbackCount)
5854 {
5855 *pcb = 0;
5856 return 0;
5857 }
5858
5859 memcpy (pbBuff, text, sizeof(text));
5860 *pcb = sizeof(text);
5861
5862 nCallbackCount++;
5863
5864 return 0;
5865 }
5866 else
5867 return 1; /* indicates callback failed */
5868}
5869
5870static DWORD CALLBACK test_EM_STREAMIN_esCallback(DWORD_PTR dwCookie,
5871 LPBYTE pbBuff,
5872 LONG cb,
5873 LONG *pcb)
5874{
5875 const char** str = (const char**)dwCookie;
5876 int size = strlen(*str);
5877 *pcb = cb;
5878 if (*pcb > size) {
5879 *pcb = size;
5880 }
5881 if (*pcb > 0) {
5882 memcpy(pbBuff, *str, *pcb);
5883 *str += *pcb;
5884 }
5885 return 0;
5886}
5887
5888static DWORD CALLBACK test_EM_STREAMIN_esCallback_UTF8Split(DWORD_PTR dwCookie,
5889 LPBYTE pbBuff,
5890 LONG cb,
5891 LONG *pcb)
5892{
5893 DWORD *phase = (DWORD *)dwCookie;
5894
5895 if(*phase == 0){
5896 static const char first[] = "\xef\xbb\xbf\xc3\x96\xc3";
5897 *pcb = sizeof(first) - 1;
5898 memcpy(pbBuff, first, *pcb);
5899 }else if(*phase == 1){
5900 static const char second[] = "\x8f\xc3\x8b";
5901 *pcb = sizeof(second) - 1;
5902 memcpy(pbBuff, second, *pcb);
5903 }else
5904 *pcb = 0;
5905
5906 ++*phase;
5907
5908 return 0;
5909}
5910
5911static DWORD CALLBACK test_EM_STREAMIN_null_bytes(DWORD_PTR cookie, BYTE *buf, LONG size, LONG *written)
5912{
5913 DWORD *phase = (DWORD *)cookie;
5914
5915 if (*phase == 0)
5916 {
5917 static const char first[] = "{\\rtf1\\ansi{Th\0is";
5918 *written = sizeof(first);
5919 memcpy(buf, first, *written);
5920 }
5921 else if (*phase == 1)
5922 {
5923 static const char second[] = " is a test}}";
5924 *written = sizeof(second);
5925 memcpy(buf, second, *written);
5926 }
5927 else
5928 *written = 0;
5929
5930 ++*phase;
5931
5932 return 0;
5933}
5934
5935struct StringWithLength {
5936 int length;
5937 char *buffer;
5938};
5939
5940/* This callback is used to handled the null characters in a string. */
5941static DWORD CALLBACK test_EM_STREAMIN_esCallback2(DWORD_PTR dwCookie,
5942 LPBYTE pbBuff,
5943 LONG cb,
5944 LONG *pcb)
5945{
5946 struct StringWithLength* str = (struct StringWithLength*)dwCookie;
5947 int size = str->length;
5948 *pcb = cb;
5949 if (*pcb > size) {
5950 *pcb = size;
5951 }
5952 if (*pcb > 0) {
5953 memcpy(pbBuff, str->buffer, *pcb);
5954 str->buffer += *pcb;
5955 str->length -= *pcb;
5956 }
5957 return 0;
5958}
5959
5960static void test_EM_STREAMIN(void)
5961{
5962 HWND hwndRichEdit = new_richedit(NULL);
5963 DWORD phase;
5964 LRESULT result;
5965 EDITSTREAM es;
5966 char buffer[1024] = {0}, tmp[16];
5967 CHARRANGE range;
5968 PARAFORMAT2 fmt;
5969 DWORD len;
5970
5971 const char * streamText0 = "{\\rtf1\\fi100\\li200\\rtlpar\\qr TestSomeText}";
5972 const char * streamText0a = "{\\rtf1\\fi100\\li200\\rtlpar\\qr TestSomeText\\par}";
5973 const char * streamText0b = "{\\rtf1 TestSomeText\\par\\par}";
5974 const char * ptr;
5975
5976 const char * streamText1 =
5977 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n"
5978 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n"
5979 "}\r\n";
5980
5981 /* In richedit 2.0 mode, this should NOT be accepted, unlike 1.0 */
5982 const char * streamText2 =
5983 "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;"
5984 "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255"
5985 "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 "
5986 "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 "
5987 "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 "
5988 "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 "
5989 "\\tx11448 \\tx11872 \\tx12296 \\tx12720 \\tx13144 \\cf2 RichEdit1\\line }";
5990
5991 const char * streamText3 = "RichEdit1";
5992
5993 const char * streamTextUTF8BOM = "\xef\xbb\xbfTestUTF8WithBOM";
5994
5995 const char * streamText4 =
5996 "This text just needs to be long enough to cause run to be split onto "
5997 "two separate lines and make sure the null terminating character is "
5998 "handled properly.\0";
5999
6000 const WCHAR UTF8Split_exp[4] = {0xd6, 0xcf, 0xcb, 0};
6001
6002 int length4 = strlen(streamText4) + 1;
6003 struct StringWithLength cookieForStream4 = {
6004 length4,
6005 (char *)streamText4,
6006 };
6007
6008 const WCHAR streamText5[] = { 'T', 'e', 's', 't', 'S', 'o', 'm', 'e', 'T', 'e', 'x', 't' };
6009 int length5 = ARRAY_SIZE(streamText5);
6010 struct StringWithLength cookieForStream5 = {
6011 sizeof(streamText5),
6012 (char *)streamText5,
6013 };
6014
6015 /* Minimal test without \par at the end */
6016 es.dwCookie = (DWORD_PTR)&streamText0;
6017 es.dwError = 0;
6018 es.pfnCallback = test_EM_STREAMIN_esCallback;
6019 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
6020 ok(result == 12, "got %Id, expected %d\n", result, 12);
6021
6022 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6023 ok (result == 12,
6024 "EM_STREAMIN: Test 0 returned %Id, expected 12\n", result);
6025 result = strcmp (buffer,"TestSomeText");
6026 ok (result == 0,
6027 "EM_STREAMIN: Test 0 set wrong text: Result: %s\n",buffer);
6028 ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %ld, expected %d\n", es.dwError, 0);
6029 /* Show that para fmts are ignored */
6030 range.cpMin = 2;
6031 range.cpMax = 2;
6032 result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&range);
6033 memset(&fmt, 0xcc, sizeof(fmt));
6034 fmt.cbSize = sizeof(fmt);
6035 result = SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt);
6036 ok(fmt.dxStartIndent == 0, "got %ld\n", fmt.dxStartIndent);
6037 ok(fmt.dxOffset == 0, "got %ld\n", fmt.dxOffset);
6038 ok(fmt.wAlignment == PFA_LEFT, "got %d\n", fmt.wAlignment);
6039 ok((fmt.wEffects & PFE_RTLPARA) == 0, "got %x\n", fmt.wEffects);
6040
6041 /* Native richedit 2.0 ignores last \par */
6042 ptr = streamText0a;
6043 es.dwCookie = (DWORD_PTR)&ptr;
6044 es.dwError = 0;
6045 es.pfnCallback = test_EM_STREAMIN_esCallback;
6046 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
6047 ok(result == 12, "got %Id, expected %d\n", result, 12);
6048
6049 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6050 ok (result == 12,
6051 "EM_STREAMIN: Test 0-a returned %Id, expected 12\n", result);
6052 result = strcmp (buffer,"TestSomeText");
6053 ok (result == 0,
6054 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer);
6055 ok(es.dwError == 0, "EM_STREAMIN: Test 0-a set error %ld, expected %d\n", es.dwError, 0);
6056 /* This time para fmts are processed */
6057 range.cpMin = 2;
6058 range.cpMax = 2;
6059 result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&range);
6060 memset(&fmt, 0xcc, sizeof(fmt));
6061 fmt.cbSize = sizeof(fmt);
6062 result = SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt);
6063 ok(fmt.dxStartIndent == 300, "got %ld\n", fmt.dxStartIndent);
6064 ok(fmt.dxOffset == -100, "got %ld\n", fmt.dxOffset);
6065 ok(fmt.wAlignment == PFA_RIGHT, "got %d\n", fmt.wAlignment);
6066 ok((fmt.wEffects & PFE_RTLPARA) == PFE_RTLPARA, "got %x\n", fmt.wEffects);
6067
6068 /* Native richedit 2.0 ignores last \par, next-to-last \par appears */
6069 es.dwCookie = (DWORD_PTR)&streamText0b;
6070 es.dwError = 0;
6071 es.pfnCallback = test_EM_STREAMIN_esCallback;
6072 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
6073 ok(result == 13, "got %Id, expected %d\n", result, 13);
6074
6075 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6076 ok (result == 14,
6077 "EM_STREAMIN: Test 0-b returned %Id, expected 14\n", result);
6078 result = strcmp (buffer,"TestSomeText\r\n");
6079 ok (result == 0,
6080 "EM_STREAMIN: Test 0-b set wrong text: Result: %s\n",buffer);
6081 ok(es.dwError == 0, "EM_STREAMIN: Test 0-b set error %ld, expected %d\n", es.dwError, 0);
6082
6083 /* Show that when using SFF_SELECTION the last \par is not ignored. */
6084 ptr = streamText0a;
6085 es.dwCookie = (DWORD_PTR)&ptr;
6086 es.dwError = 0;
6087 es.pfnCallback = test_EM_STREAMIN_esCallback;
6088 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
6089 ok(result == 12, "got %Id, expected %d\n", result, 12);
6090
6091 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6092 ok (result == 12,
6093 "EM_STREAMIN: Test 0-a returned %Id, expected 12\n", result);
6094 result = strcmp (buffer,"TestSomeText");
6095 ok (result == 0,
6096 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer);
6097 ok(es.dwError == 0, "EM_STREAMIN: Test 0-a set error %ld, expected %d\n", es.dwError, 0);
6098
6099 range.cpMin = 0;
6100 range.cpMax = -1;
6101 result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&range);
6102 ok (result == 13, "got %Id\n", result);
6103
6104 ptr = streamText0a;
6105 es.dwCookie = (DWORD_PTR)&ptr;
6106 es.dwError = 0;
6107 es.pfnCallback = test_EM_STREAMIN_esCallback;
6108
6109 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SFF_SELECTION | SF_RTF, (LPARAM)&es);
6110 ok(result == 13, "got %Id, expected 13\n", result);
6111
6112 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6113 ok (result == 14,
6114 "EM_STREAMIN: Test SFF_SELECTION 0-a returned %Id, expected 14\n", result);
6115 result = strcmp (buffer,"TestSomeText\r\n");
6116 ok (result == 0,
6117 "EM_STREAMIN: Test SFF_SELECTION 0-a set wrong text: Result: %s\n",buffer);
6118 ok(es.dwError == 0, "EM_STREAMIN: Test SFF_SELECTION 0-a set error %ld, expected %d\n", es.dwError, 0);
6119
6120 es.dwCookie = (DWORD_PTR)&streamText1;
6121 es.dwError = 0;
6122 es.pfnCallback = test_EM_STREAMIN_esCallback;
6123 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
6124 ok(result == 12, "got %Id, expected %d\n", result, 12);
6125
6126 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6127 ok (result == 12,
6128 "EM_STREAMIN: Test 1 returned %Id, expected 12\n", result);
6129 result = strcmp (buffer,"TestSomeText");
6130 ok (result == 0,
6131 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer);
6132 ok(es.dwError == 0, "EM_STREAMIN: Test 1 set error %ld, expected %d\n", es.dwError, 0);
6133
6134 es.dwCookie = (DWORD_PTR)&streamText2;
6135 es.dwError = 0;
6136 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
6137 ok(result == 0, "got %Id, expected %d\n", result, 0);
6138
6139 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6140 ok (result == 0,
6141 "EM_STREAMIN: Test 2 returned %Id, expected 0\n", result);
6142 ok(!buffer[0], "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
6143 ok(es.dwError == -16, "EM_STREAMIN: Test 2 set error %ld, expected %d\n", es.dwError, -16);
6144
6145 es.dwCookie = (DWORD_PTR)&streamText3;
6146 es.dwError = 0;
6147 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
6148 ok(result == 0, "got %Id, expected %d\n", result, 0);
6149
6150 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6151 ok (result == 0,
6152 "EM_STREAMIN: Test 3 returned %Id, expected 0\n", result);
6153 ok(!buffer[0], "EM_STREAMIN: Test 3 set wrong text: Result: %s\n",buffer);
6154 ok(es.dwError == -16, "EM_STREAMIN: Test 3 set error %ld, expected %d\n", es.dwError, -16);
6155
6156 es.dwCookie = (DWORD_PTR)&streamTextUTF8BOM;
6157 es.dwError = 0;
6158 es.pfnCallback = test_EM_STREAMIN_esCallback;
6159 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es);
6160 ok(result == 18, "got %Id, expected %d\n", result, 18);
6161
6162 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6163 ok(result == 15,
6164 "EM_STREAMIN: Test UTF8WithBOM returned %Id, expected 15\n", result);
6165 result = strcmp (buffer,"TestUTF8WithBOM");
6166 ok(result == 0,
6167 "EM_STREAMIN: Test UTF8WithBOM set wrong text: Result: %s\n",buffer);
6168 ok(es.dwError == 0, "EM_STREAMIN: Test UTF8WithBOM set error %ld, expected %d\n", es.dwError, 0);
6169
6170 phase = 0;
6171 es.dwCookie = (DWORD_PTR)&phase;
6172 es.dwError = 0;
6173 es.pfnCallback = test_EM_STREAMIN_esCallback_UTF8Split;
6174 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es);
6175 ok(result == 8, "got %Id\n", result);
6176
6177 len = WideCharToMultiByte(CP_ACP, 0, UTF8Split_exp, -1, tmp, sizeof(tmp), NULL, NULL);
6178
6179 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6180 ok(result + 1 == len,
6181 "EM_STREAMIN: Test UTF8Split returned %Id\n", result);
6182 result = memcmp (buffer, tmp, result);
6183 ok(result == 0,
6184 "EM_STREAMIN: Test UTF8Split set wrong text: Result: %s\n",buffer);
6185 ok(es.dwError == 0, "EM_STREAMIN: Test UTF8Split set error %ld, expected %d\n", es.dwError, 0);
6186
6187 es.dwCookie = (DWORD_PTR)&cookieForStream4;
6188 es.dwError = 0;
6189 es.pfnCallback = test_EM_STREAMIN_esCallback2;
6190 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es);
6191 ok(result == length4, "got %Id, expected %d\n", result, length4);
6192
6193 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6194 ok (result == length4,
6195 "EM_STREAMIN: Test 4 returned %Id, expected %d\n", result, length4);
6196 ok(es.dwError == 0, "EM_STREAMIN: Test 4 set error %ld, expected %d\n", es.dwError, 0);
6197
6198 es.dwCookie = (DWORD_PTR)&cookieForStream5;
6199 es.dwError = 0;
6200 es.pfnCallback = test_EM_STREAMIN_esCallback2;
6201 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT | SF_UNICODE, (LPARAM)&es);
6202 ok(result == sizeof(streamText5), "got %Id, expected %u\n", result, (UINT)sizeof(streamText5));
6203
6204 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6205 ok (result == length5,
6206 "EM_STREAMIN: Test 5 returned %Id, expected %d\n", result, length5);
6207 ok(es.dwError == 0, "EM_STREAMIN: Test 5 set error %ld, expected %d\n", es.dwError, 0);
6208
6209 DestroyWindow(hwndRichEdit);
6210
6211 /* Single-line richedit */
6212 hwndRichEdit = new_richedit_with_style(NULL, 0);
6213 ptr = "line1\r\nline2";
6214 es.dwCookie = (DWORD_PTR)&ptr;
6215 es.dwError = 0;
6216 es.pfnCallback = test_EM_STREAMIN_esCallback;
6217 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es);
6218 ok(result == 12, "got %Id, expected %d\n", result, 12);
6219 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6220 ok (!strcmp(buffer, "line1"),
6221 "EM_STREAMIN: Unexpected text '%s'\n", buffer);
6222
6223 /* Test 0-bytes inside text */
6224 hwndRichEdit = new_richedit_with_style(NULL, 0);
6225 phase = 0;
6226 es.dwCookie = (DWORD_PTR)&phase;
6227 es.dwError = 0;
6228 es.pfnCallback = test_EM_STREAMIN_null_bytes;
6229 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
6230 ok(result == 16, "got %Id, expected %d\n", result, 16);
6231 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6232 ok (!strcmp(buffer, "Th is is a test"), "EM_STREAMIN: Unexpected text '%s'\n", buffer);
6233}
6234
6235static void test_EM_StreamIn_Undo(void)
6236{
6237 /* The purpose of this test is to determine when a EM_StreamIn should be
6238 * undoable. This is important because WM_PASTE currently uses StreamIn and
6239 * pasting should always be undoable but streaming isn't always.
6240 *
6241 * cases to test:
6242 * StreamIn plain text without SFF_SELECTION.
6243 * StreamIn plain text with SFF_SELECTION set but a zero-length selection
6244 * StreamIn plain text with SFF_SELECTION and a valid, normal selection
6245 * StreamIn plain text with SFF_SELECTION and a backwards-selection (from>to)
6246 * Feel free to add tests for other text modes or StreamIn things.
6247 */
6248
6249
6250 HWND hwndRichEdit = new_richedit(NULL);
6251 LRESULT result;
6252 EDITSTREAM es;
6253 char buffer[1024] = {0};
6254 const char randomtext[] = "Some text";
6255
6256 es.pfnCallback = EditStreamCallback;
6257
6258 /* StreamIn, no SFF_SELECTION */
6259 es.dwCookie = nCallbackCount;
6260 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
6261 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)randomtext);
6262 SendMessageA(hwndRichEdit, EM_SETSEL,0,0);
6263 SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es);
6264 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6265 result = strcmp (buffer,"test");
6266 ok (result == 0,
6267 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer);
6268
6269 result = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
6270 ok (result == FALSE,
6271 "EM_STREAMIN without SFF_SELECTION wrongly allows undo\n");
6272
6273 /* StreamIn, SFF_SELECTION, but nothing selected */
6274 es.dwCookie = nCallbackCount;
6275 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
6276 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)randomtext);
6277 SendMessageA(hwndRichEdit, EM_SETSEL,0,0);
6278 SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT|SFF_SELECTION, (LPARAM)&es);
6279 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6280 result = strcmp (buffer,"testSome text");
6281 ok (result == 0,
6282 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
6283
6284 result = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
6285 ok (result == TRUE,
6287 "should create an undo\n");
6288
6289 /* StreamIn, SFF_SELECTION, with a selection */
6290 es.dwCookie = nCallbackCount;
6291 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
6292 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)randomtext);
6293 SendMessageA(hwndRichEdit, EM_SETSEL,4,5);
6294 SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT|SFF_SELECTION, (LPARAM)&es);
6295 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6296 result = strcmp (buffer,"Sometesttext");
6297 ok (result == 0,
6298 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
6299
6300 result = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
6301 ok (result == TRUE,
6303 "should create an undo\n");
6304
6305 DestroyWindow(hwndRichEdit);
6306}
6307
6308static BOOL is_em_settextex_supported(HWND hwnd)
6309{
6310 SETTEXTEX stex = { ST_DEFAULT, CP_ACP };
6311 return SendMessageA(hwnd, EM_SETTEXTEX, (WPARAM)&stex, 0) != 0;
6312}
6313
6314static void test_unicode_conversions(void)
6315{
6316 static const WCHAR tW[] = {'t',0};
6317 static const WCHAR teW[] = {'t','e',0};
6318 static const WCHAR textW[] = {'t','e','s','t',0};
6319 static const char textA[] = "test";
6320 char bufA[64];
6321 WCHAR bufW[64];
6322 HWND hwnd;
6323 int em_settextex_supported, ret;
6324
6325#define set_textA(hwnd, wm_set_text, txt) \
6326 do { \
6327 SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; \
6328 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
6329 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
6330 ret = SendMessageA(hwnd, wm_set_text, wparam, (LPARAM)txt); \
6331 ok(ret, "SendMessageA(%02x) error %lu\n", wm_set_text, GetLastError()); \
6332 } while(0)
6333#define expect_textA(hwnd, wm_get_text, txt) \
6334 do { \
6335 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
6336 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)&gtex; \
6337 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
6338 memset(bufA, 0xAA, sizeof(bufA)); \
6339 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
6340 ok(ret, "SendMessageA(%02x) error %lu\n", wm_get_text, GetLastError()); \
6341 ret = lstrcmpA(bufA, txt); \
6342 ok(!ret, "%02x: strings do not match: expected %s got %s\n", wm_get_text, txt, bufA); \
6343 } while(0)
6344
6345#define set_textW(hwnd, wm_set_text, txt) \
6346 do { \
6347 SETTEXTEX stex = { ST_DEFAULT, 1200 }; \
6348 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
6349 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
6350 ret = SendMessageW(hwnd, wm_set_text, wparam, (LPARAM)txt); \
6351 ok(ret, "SendMessageW(%02x) error %lu\n", wm_set_text, GetLastError()); \
6352 } while(0)
6353#define expect_textW(hwnd, wm_get_text, txt) \
6354 do { \
6355 GETTEXTEX gtex = { 64, GT_DEFAULT, 1200, NULL, NULL }; \
6356 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)&gtex; \
6357 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
6358 memset(bufW, 0xAA, sizeof(bufW)); \
6359 ret = SendMessageW(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
6360 ok(ret, "SendMessageW(%02x) error %lu\n", wm_get_text, GetLastError()); \
6361 ret = lstrcmpW(bufW, txt); \
6362 ok(!ret, "%02x: strings do not match: expected[0] %x got[0] %x\n", wm_get_text, txt[0], bufW[0]); \
6363 } while(0)
6364#define expect_empty(hwnd, wm_get_text) \
6365 do { \
6366 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
6367 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)&gtex; \
6368 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
6369 memset(bufA, 0xAA, sizeof(bufA)); \
6370 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
6371 ok(!ret, "empty richedit should return 0, got %d\n", ret); \
6372 ok(!*bufA, "empty richedit should return empty string, got %s\n", bufA); \
6373 } while(0)
6374
6375 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
6376 0, 0, 200, 60, 0, 0, 0, 0);
6377 ok(hwnd != 0, "CreateWindowExA error %lu\n", GetLastError());
6378
6379 ret = IsWindowUnicode(hwnd);
6380 ok(ret, "RichEdit20W should be unicode under NT\n");
6381
6382 /* EM_SETTEXTEX is supported starting from version 3.0 */
6383 em_settextex_supported = is_em_settextex_supported(hwnd);
6384 trace("EM_SETTEXTEX is %ssupported on this platform\n",
6385 em_settextex_supported ? "" : "NOT ");
6386
6387 expect_empty(hwnd, WM_GETTEXT);
6388 expect_empty(hwnd, EM_GETTEXTEX);
6389
6390 ret = SendMessageA(hwnd, WM_CHAR, textW[0], 0);
6391 ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret);
6392 expect_textA(hwnd, WM_GETTEXT, "t");
6393 expect_textA(hwnd, EM_GETTEXTEX, "t");
6394 expect_textW(hwnd, EM_GETTEXTEX, tW);
6395
6396 ret = SendMessageA(hwnd, WM_CHAR, textA[1], 0);
6397 ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret);
6398 expect_textA(hwnd, WM_GETTEXT, "te");
6399 expect_textA(hwnd, EM_GETTEXTEX, "te");
6400 expect_textW(hwnd, EM_GETTEXTEX, teW);
6401
6402 set_textA(hwnd, WM_SETTEXT, NULL);
6403 expect_empty(hwnd, WM_GETTEXT);
6404 expect_empty(hwnd, EM_GETTEXTEX);
6405
6406 set_textA(hwnd, WM_SETTEXT, textA);
6407 expect_textA(hwnd, WM_GETTEXT, textA);
6408 expect_textA(hwnd, EM_GETTEXTEX, textA);
6409 expect_textW(hwnd, EM_GETTEXTEX, textW);
6410
6411 if (em_settextex_supported)
6412 {
6413 set_textA(hwnd, EM_SETTEXTEX, textA);
6414 expect_textA(hwnd, WM_GETTEXT, textA);
6415 expect_textA(hwnd, EM_GETTEXTEX, textA);
6416 expect_textW(hwnd, EM_GETTEXTEX, textW);
6417 }
6418
6419 set_textW(hwnd, WM_SETTEXT, textW);
6420 expect_textW(hwnd, WM_GETTEXT, textW);
6421 expect_textA(hwnd, WM_GETTEXT, textA);
6422 expect_textW(hwnd, EM_GETTEXTEX, textW);
6423 expect_textA(hwnd, EM_GETTEXTEX, textA);
6424
6425 if (em_settextex_supported)
6426 {
6427 set_textW(hwnd, EM_SETTEXTEX, textW);
6428 expect_textW(hwnd, WM_GETTEXT, textW);
6429 expect_textA(hwnd, WM_GETTEXT, textA);
6430 expect_textW(hwnd, EM_GETTEXTEX, textW);
6431 expect_textA(hwnd, EM_GETTEXTEX, textA);
6432 }
6433 DestroyWindow(hwnd);
6434
6435 hwnd = CreateWindowExA(0, "RichEdit20A", NULL, WS_POPUP,
6436 0, 0, 200, 60, 0, 0, 0, 0);
6437 ok(hwnd != 0, "CreateWindowExA error %lu\n", GetLastError());
6438
6439 ret = IsWindowUnicode(hwnd);
6440 ok(!ret, "RichEdit20A should NOT be unicode\n");
6441
6442 set_textA(hwnd, WM_SETTEXT, textA);
6443 expect_textA(hwnd, WM_GETTEXT, textA);
6444 expect_textA(hwnd, EM_GETTEXTEX, textA);
6445 expect_textW(hwnd, EM_GETTEXTEX, textW);
6446
6447 if (em_settextex_supported)
6448 {
6449 set_textA(hwnd, EM_SETTEXTEX, textA);
6450 expect_textA(hwnd, WM_GETTEXT, textA);
6451 expect_textA(hwnd, EM_GETTEXTEX, textA);
6452 expect_textW(hwnd, EM_GETTEXTEX, textW);
6453 }
6454
6455 set_textW(hwnd, WM_SETTEXT, textW);
6456 expect_textW(hwnd, WM_GETTEXT, textW);
6457 expect_textA(hwnd, WM_GETTEXT, textA);
6458 expect_textW(hwnd, EM_GETTEXTEX, textW);
6459 expect_textA(hwnd, EM_GETTEXTEX, textA);
6460
6461 if (em_settextex_supported)
6462 {
6463 set_textW(hwnd, EM_SETTEXTEX, textW);
6464 expect_textW(hwnd, WM_GETTEXT, textW);
6465 expect_textA(hwnd, WM_GETTEXT, textA);
6466 expect_textW(hwnd, EM_GETTEXTEX, textW);
6467 expect_textA(hwnd, EM_GETTEXTEX, textA);
6468 }
6469 DestroyWindow(hwnd);
6470}
6471
6472static void test_WM_CHAR(void)
6473{
6474 HWND hwnd;
6475 int ret;
6476 const char * char_list = "abc\rabc\r";
6477 const char * expected_content_single = "abcabc";
6478 const char * expected_content_multi = "abc\r\nabc\r\n";
6479 char buffer[64] = {0};
6480 const char * p;
6481
6482 /* single-line control must IGNORE carriage returns */
6483 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
6484 0, 0, 200, 60, 0, 0, 0, 0);
6485 ok(hwnd != 0, "CreateWindowExA error %lu\n", GetLastError());
6486 disable_beep( hwnd );
6487
6488 p = char_list;
6489 while (*p != '\0') {
6490 SendMessageA(hwnd, WM_KEYDOWN, *p, 1);
6491 ret = SendMessageA(hwnd, WM_CHAR, *p, 1);
6492 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *p, ret);
6493 SendMessageA(hwnd, WM_KEYUP, *p, 1);
6494 p++;
6495 }
6496
6498 ret = strcmp(buffer, expected_content_single);
6499 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n");
6500
6502
6503 /* multi-line control inserts CR normally */
6504 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP|ES_MULTILINE,
6505 0, 0, 200, 60, 0, 0, 0, 0);
6506 ok(hwnd != 0, "CreateWindowExA error %lu\n", GetLastError());
6507
6508 p = char_list;
6509 while (*p != '\0') {
6511 ret = SendMessageA(hwnd, WM_CHAR, *p, 1);
6512 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *p, ret);
6513 SendMessageA(hwnd, WM_KEYUP, *p, 1);
6514 p++;
6515 }
6516
6518 ret = strcmp(buffer, expected_content_multi);
6519 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n");
6520
6522}
6523
6525{
6526 HWND hwnd;
6527 GETTEXTLENGTHEX gtl;
6528 int ret;
6529 const char * base_string = "base string";
6530 const char * test_string = "a\nb\n\n\r\n";
6531 const char * test_string_after = "a";
6532 const char * test_string_2 = "a\rtest\rstring";
6533 char buffer[64] = {0};
6534
6535 /* single line */
6536 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
6537 0, 0, 200, 60, 0, 0, 0, 0);
6538 ok(hwnd != 0, "CreateWindowExA error %lu\n", GetLastError());
6539
6541 gtl.codepage = CP_ACP;
6543 ok(ret == 0, "ret %d\n",ret);
6544
6546 gtl.codepage = CP_ACP;
6548 ok(ret == 0, "ret %d\n",ret);
6549
6550 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)base_string);
6551
6553 gtl.codepage = CP_ACP;
6555 ok(ret == strlen(base_string), "ret %d\n",ret);
6556
6558 gtl.codepage = CP_ACP;
6560 ok(ret == strlen(base_string), "ret %d\n",ret);
6561
6563
6565 gtl.codepage = CP_ACP;
6567 ok(ret == 1, "ret %d\n",ret);
6568
6570 gtl.codepage = CP_ACP;
6572 ok(ret == 1, "ret %d\n",ret);
6573
6575 ret = strcmp(buffer, test_string_after);
6576 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n");
6577
6579
6580 /* multi line */
6581 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP | ES_MULTILINE,
6582 0, 0, 200, 60, 0, 0, 0, 0);
6583 ok(hwnd != 0, "CreateWindowExA error %lu\n", GetLastError());
6584
6586 gtl.codepage = CP_ACP;
6588 ok(ret == 0, "ret %d\n",ret);
6589
6591 gtl.codepage = CP_ACP;
6593 ok(ret == 0, "ret %d\n",ret);
6594
6595 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)base_string);
6596
6598 gtl.codepage = CP_ACP;
6600 ok(ret == strlen(base_string), "ret %d\n",ret);
6601
6603 gtl.codepage = CP_ACP;
6605 ok(ret == strlen(base_string), "ret %d\n",ret);
6606
6607 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)test_string_2);
6608
6610 gtl.codepage = CP_ACP;
6612 ok(ret == strlen(test_string_2) + 2, "ret %d\n",ret);
6613
6615 gtl.codepage = CP_ACP;
6617 ok(ret == strlen(test_string_2), "ret %d\n",ret);
6618
6620
6622 gtl.codepage = CP_ACP;
6624 ok(ret == 10, "ret %d\n",ret);
6625
6627 gtl.codepage = CP_ACP;
6629 ok(ret == 6, "ret %d\n",ret);
6630
6631 /* Unicode/NUMCHARS/NUMBYTES */
6632 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)test_string_2);
6633
6634 gtl.flags = GTL_DEFAULT;
6635 gtl.codepage = 1200;
6637 ok(ret == lstrlenA(test_string_2),
6638 "GTL_DEFAULT gave %i, expected %i\n", ret, lstrlenA(test_string_2));
6639
6640 gtl.flags = GTL_NUMCHARS;
6641 gtl.codepage = 1200;
6643 ok(ret == lstrlenA(test_string_2),
6644 "GTL_NUMCHARS gave %i, expected %i\n", ret, lstrlenA(test_string_2));
6645
6646 gtl.flags = GTL_NUMBYTES;
6647 gtl.codepage = 1200;
6649 ok(ret == lstrlenA(test_string_2)*2,
6650 "GTL_NUMBYTES gave %i, expected %i\n", ret, lstrlenA(test_string_2)*2);
6651
6652 gtl.flags = GTL_PRECISE;
6653 gtl.codepage = 1200;
6655 ok(ret == lstrlenA(test_string_2)*2,
6656 "GTL_PRECISE gave %i, expected %i\n", ret, lstrlenA(test_string_2)*2);
6657
6659 gtl.codepage = 1200;
6661 ok(ret == lstrlenA(test_string_2),
6662 "GTL_NUMCHAR | GTL_PRECISE gave %i, expected %i\n", ret, lstrlenA(test_string_2));
6663
6665 gtl.codepage = 1200;
6667 ok(ret == E_INVALIDARG,
6668 "GTL_NUMCHARS | GTL_NUMBYTES gave %i, expected %li\n", ret, E_INVALIDARG);
6669
6671}
6672
6673
6674/* globals that parent and child access when checking event masks & notifications */
6677static int watchForEventMask = 0;
6678
6679/* parent proc that queries the edit's event mask when it gets a WM_COMMAND */
6681{
6682 if(message == WM_COMMAND && (watchForEventMask & (wParam >> 16)))
6683 {
6685 }
6687}
6688
6689/* test event masks in combination with WM_COMMAND */
6690static void test_eventMask(void)
6691{
6692 HWND parent;
6693 int ret, style;
6694 WNDCLASSA cls;
6695 const char text[] = "foo bar\n";
6696 int eventMask;
6697
6698 /* register class to capture WM_COMMAND */
6699 cls = make_simple_class(ParentMsgCheckProcA, "EventMaskParentClass");
6700 if(!RegisterClassA(&cls)) assert(0);
6701
6703 0, 0, 200, 60, NULL, NULL, NULL, NULL);
6704 ok (parent != 0, "Failed to create parent window\n");
6705
6707 ok(eventMaskEditHwnd != 0, "Failed to create edit window\n");
6708
6709 eventMask = ENM_CHANGE | ENM_UPDATE;
6711 ok(ret == ENM_NONE, "wrong event mask\n");
6713 ok(ret == eventMask, "failed to set event mask\n");
6714
6715 /* check what happens when we ask for EN_CHANGE and send WM_SETTEXT */
6716 queriedEventMask = 0; /* initialize to something other than we expect */
6719 ok(ret == TRUE, "failed to set text\n");
6720 /* richedit should mask off ENM_CHANGE when it sends an EN_CHANGE
6721 notification in response to WM_SETTEXT */
6722 ok(queriedEventMask == (eventMask & ~ENM_CHANGE),
6723 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask);
6724
6725 /* check to see if EN_CHANGE is sent when redraw is turned off */
6727 ok(IsWindowVisible(eventMaskEditHwnd), "Window should be visible.\n");
6729 /* redraw is disabled by making the window invisible. */
6730 ok(!IsWindowVisible(eventMaskEditHwnd), "Window shouldn't be visible.\n");
6731 queriedEventMask = 0; /* initialize to something other than we expect */
6733 ok(queriedEventMask == (eventMask & ~ENM_CHANGE),
6734 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask);
6736 ok(IsWindowVisible(eventMaskEditHwnd), "Window should be visible.\n");
6737
6738 /* check to see if EN_UPDATE is sent when the editor isn't visible */
6742 ok(!IsWindowVisible(eventMaskEditHwnd), "Window shouldn't be visible.\n");
6744 queriedEventMask = 0; /* initialize to something other than we expect */
6746 ok(queriedEventMask == 0,
6747 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask);
6749 ok(IsWindowVisible(eventMaskEditHwnd), "Window should be visible.\n");
6750 queriedEventMask = 0; /* initialize to something other than we expect */
6752 ok(queriedEventMask == eventMask,
6753 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask);
6754
6755
6757}
6758
6759static int received_WM_NOTIFY = 0;
6760static int modify_at_WM_NOTIFY = 0;
6763
6765{
6766 if(message == WM_NOTIFY)
6767 {
6770 if (filter_on_WM_NOTIFY) return TRUE;
6771 }
6773}
6774
6775static void test_WM_NOTIFY(void)
6776{
6777 HWND parent;
6778 WNDCLASSA cls;
6779 CHARFORMAT2A cf2;
6780 int sel_start, sel_end;
6781
6782 /* register class to capture WM_NOTIFY */
6783 cls = make_simple_class(WM_NOTIFY_ParentMsgCheckProcA, "WM_NOTIFY_ParentClass");
6784 if(!RegisterClassA(&cls)) assert(0);
6785
6787 0, 0, 200, 60, NULL, NULL, NULL, NULL);
6788 ok (parent != 0, "Failed to create parent window\n");
6789
6791 ok(hwndRichedit_WM_NOTIFY != 0, "Failed to create edit window\n");
6792
6794
6795 /* Notifications for selection change should only be sent when selection
6796 actually changes. EM_SETCHARFORMAT is one message that calls
6797 ME_CommitUndo, which should check whether message should be sent */
6799 cf2.cbSize = sizeof(CHARFORMAT2A);
6801 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
6802 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
6804 ok(received_WM_NOTIFY == 0, "Unexpected WM_NOTIFY was sent!\n");
6805
6806 /* WM_SETTEXT should NOT cause a WM_NOTIFY to be sent when selection is
6807 already at 0. */
6811 ok(received_WM_NOTIFY == 0, "Unexpected WM_NOTIFY was sent!\n");
6812 ok(modify_at_WM_NOTIFY == 0, "WM_NOTIFY callback saw text flagged as modified!\n");
6813
6817 ok(received_WM_NOTIFY == 1, "Expected WM_NOTIFY was NOT sent!\n");
6818
6822 ok(received_WM_NOTIFY == 1, "Expected WM_NOTIFY was NOT sent!\n");
6823 ok(modify_at_WM_NOTIFY == 0, "WM_NOTIFY callback saw text flagged as modified!\n");
6824
6825 /* Test for WM_NOTIFY messages with redraw disabled. */
6830 ok(received_WM_NOTIFY == 1, "Expected WM_NOTIFY was NOT sent!\n");
6832
6833 /* Test filtering key events. */
6836 SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
6839 SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
6840 ok(sel_start == 1 && sel_end == 1,
6841 "selections is incorrectly at (%d,%d)\n", sel_start, sel_end);
6845 SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
6846 ok(sel_start == 1 && sel_end == 1,
6847 "selections is incorrectly at (%d,%d)\n", sel_start, sel_end);
6848
6849 /* test with owner set to NULL */
6852 SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
6853 ok(sel_start == 1 && sel_end == 1,
6854 "selections is incorrectly at (%d,%d)\n", sel_start, sel_end);
6855
6858}
6859
6861#define CURSOR_CLIENT_X 5
6862#define CURSOR_CLIENT_Y 5
6863#define WP_PARENT 1
6864#define WP_CHILD 2
6865
6867{
6868 if(message == WM_NOTIFY && ((NMHDR*)lParam)->code == EN_LINK)
6869 {
6870 enlink = *(ENLINK*)lParam;
6871 }
6873}
6874
6875static void link_notify_test(const char *desc, int i, HWND hwnd, HWND parent,
6876 UINT msg, WPARAM wParam, LPARAM lParam, BOOL notifies)
6877{
6878 ENLINK junk_enlink;
6879
6880 switch (msg)
6881 {
6882 case WM_LBUTTONDBLCLK:
6883 case WM_LBUTTONDOWN:
6884 case WM_LBUTTONUP:
6885 case WM_MOUSEHOVER:
6886 case WM_MOUSEMOVE:
6887 case WM_MOUSEWHEEL:
6888 case WM_RBUTTONDBLCLK:
6889 case WM_RBUTTONDOWN:
6890 case WM_RBUTTONUP:
6892 break;
6893 case WM_SETCURSOR:
6894 if (wParam == WP_PARENT)
6895 wParam = (WPARAM)parent;
6896 else if (wParam == WP_CHILD)
6897 wParam = (WPARAM)hwnd;
6898 break;
6899 }
6900
6901 memset(&junk_enlink, 0x23, sizeof(junk_enlink));
6902 enlink = junk_enlink;
6903
6905
6906 if (notifies)
6907 {
6909 "%s test %i: Expected hwnd %p got %p\n", desc, i, hwnd, enlink.nmhdr.hwndFrom);
6910 ok(enlink.nmhdr.idFrom == 0,
6911 "%s test %i: Expected idFrom 0 got 0x%Ix\n", desc, i, enlink.nmhdr.idFrom);
6912 ok(enlink.msg == msg,
6913 "%s test %i: Expected msg 0x%x got 0x%x\n", desc, i, msg, enlink.msg);
6914 if (msg == WM_SETCURSOR)
6915 {
6916 ok(enlink.wParam == 0,
6917 "%s test %i: Expected wParam 0 got 0x%Ix\n", desc, i, enlink.wParam);
6918 }
6919 else
6920 {
6922 "%s test %i: Expected wParam 0x%Ix got 0x%Ix\n", desc, i, wParam, enlink.wParam);
6923 }
6925 "%s test %i: Expected lParam 0x%Ix got 0x%Ix\n",
6927 ok(enlink.chrg.cpMin == 0 && enlink.chrg.cpMax == 31,
6928 "%s test %i: Expected link range [0,31) got [%li,%li)\n", desc, i, enlink.chrg.cpMin, enlink.chrg.cpMax);
6929 }
6930 else
6931 {
6932 ok(memcmp(&enlink, &junk_enlink, sizeof(enlink)) == 0,
6933 "%s test %i: Expected enlink to remain unmodified\n", desc, i);
6934 }
6935}
6936
6937static void test_EN_LINK(void)
6938{
6939 HWND hwnd, parent;
6940 WNDCLASSA cls;
6941 CHARFORMAT2A cf2;
6942 POINT orig_cursor_pos;
6943 POINT cursor_screen_pos = {CURSOR_CLIENT_X, CURSOR_CLIENT_Y};
6944 int i;
6945
6946 static const struct
6947 {
6948 UINT msg;
6949 WPARAM wParam;
6950 LPARAM lParam;
6951 BOOL notifies;
6952 }
6953 link_notify_tests[] =
6954 {
6955 /* hold down the left button and try some messages */
6956 { WM_LBUTTONDOWN, 0, 0, TRUE }, /* 0 */
6957 { EM_LINESCROLL, 0, 1, FALSE },
6958 { EM_SCROLL, SB_BOTTOM, 0, FALSE },
6959 { WM_LBUTTONDBLCLK, 0, 0, TRUE },
6960 { WM_MOUSEHOVER, 0, 0, FALSE },
6961 { WM_MOUSEMOVE, 0, 0, FALSE },
6962 { WM_MOUSEWHEEL, 0, 0, FALSE },
6963 { WM_RBUTTONDBLCLK, 0, 0, TRUE },
6964 { WM_RBUTTONDOWN, 0, 0, TRUE },
6965 { WM_RBUTTONUP, 0, 0, TRUE },
6966 { WM_SETCURSOR, 0, 0, FALSE },
6967 { WM_SETCURSOR, WP_PARENT, 0, FALSE },
6968 { WM_SETCURSOR, WP_CHILD, 0, TRUE },
6969 { WM_SETCURSOR, WP_CHILD, 1, TRUE },
6970 { WM_VSCROLL, SB_BOTTOM, 0, FALSE },
6971 { WM_LBUTTONUP, 0, 0, TRUE },
6972 /* hold down the right button and try some messages */
6973 { WM_RBUTTONDOWN, 0, 0, TRUE }, /* 16 */
6974 { EM_LINESCROLL, 0, 1, FALSE },
6975 { EM_SCROLL, SB_BOTTOM, 0, FALSE },
6976 { WM_LBUTTONDBLCLK, 0, 0, TRUE },
6977 { WM_LBUTTONDOWN, 0, 0, TRUE },
6978 { WM_LBUTTONUP, 0, 0, TRUE },
6979 { WM_MOUSEHOVER, 0, 0, FALSE },
6980 { WM_MOUSEMOVE, 0, 0, TRUE },
6981 { WM_MOUSEWHEEL, 0, 0, FALSE },
6982 { WM_RBUTTONDBLCLK, 0, 0, TRUE },
6983 { WM_SETCURSOR, 0, 0, FALSE },
6984 { WM_SETCURSOR, WP_PARENT, 0, FALSE },
6985 { WM_SETCURSOR, WP_CHILD, 0, TRUE },
6986 { WM_SETCURSOR, WP_CHILD, 1, TRUE },
6987 { WM_VSCROLL, SB_BOTTOM, 0, FALSE },
6988 { WM_RBUTTONUP, 0, 0, TRUE },
6989 /* try the messages with both buttons released */
6990 { EM_LINESCROLL, 0, 1, FALSE }, /* 32 */
6991 { EM_SCROLL, SB_BOTTOM, 0, FALSE },
6992 { WM_LBUTTONDBLCLK, 0, 0, TRUE },
6993 { WM_LBUTTONDOWN, 0, 0, TRUE },
6994 { WM_LBUTTONUP, 0, 0, TRUE },
6995 { WM_MOUSEHOVER, 0, 0, FALSE },
6996 { WM_MOUSEMOVE, 0, 0, TRUE },
6997 { WM_MOUSEWHEEL, 0, 0, FALSE },
6998 { WM_RBUTTONDBLCLK, 0, 0, TRUE },
6999 { WM_RBUTTONDOWN, 0, 0, TRUE },
7000 { WM_RBUTTONUP, 0, 0, TRUE },
7001 { WM_SETCURSOR, 0, 0, FALSE },
7002 { WM_SETCURSOR, WP_CHILD, 0, TRUE },
7003 { WM_SETCURSOR, WP_CHILD, 1, TRUE },
7004 { WM_SETCURSOR, WP_PARENT, 0, FALSE },
7005 { WM_VSCROLL, SB_BOTTOM, 0, FALSE }
7006 };
7007
7008 /* register class to capture WM_NOTIFY */
7009 cls = make_simple_class(EN_LINK_ParentMsgCheckProcA, "EN_LINK_ParentClass");
7010 if(!RegisterClassA(&cls)) assert(0);
7011
7013 0, 0, 200, 60, NULL, NULL, NULL, NULL);
7014 ok(parent != 0, "Failed to create parent window\n");
7015
7017 ok(hwnd != 0, "Failed to create edit window\n");
7018
7020
7021 cf2.cbSize = sizeof(CHARFORMAT2A);
7022 cf2.dwMask = CFM_LINK;
7023 cf2.dwEffects = CFE_LINK;
7025 /* mixing letters and numbers causes runs to be split */
7026 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"link text with at least 2 runs");
7027
7028 GetCursorPos(&orig_cursor_pos);
7029 SetCursorPos(0, 0);
7030
7031 for (i = 0; i < ARRAY_SIZE(link_notify_tests); i++)
7032 {
7033 link_notify_test("cursor position simulated", i, hwnd, parent,
7034 link_notify_tests[i].msg, link_notify_tests[i].wParam, link_notify_tests[i].lParam,
7035 link_notify_tests[i].msg == WM_SETCURSOR ? FALSE : link_notify_tests[i].notifies);
7036 }
7037
7038 ClientToScreen(hwnd, &cursor_screen_pos);
7039 SetCursorPos(cursor_screen_pos.x, cursor_screen_pos.y);
7040
7041 for (i = 0; i < ARRAY_SIZE(link_notify_tests); i++)
7042 {
7043 link_notify_test("cursor position set", i, hwnd, parent,
7044 link_notify_tests[i].msg, link_notify_tests[i].wParam, link_notify_tests[i].lParam,
7045 link_notify_tests[i].notifies);
7046 }
7047
7048 SetCursorPos(orig_cursor_pos.x, orig_cursor_pos.y);
7051}
7052
7053static void test_undo_coalescing(void)
7054{
7055 HWND hwnd;
7056 int result;
7057 char buffer[64] = {0};
7058
7059 /* multi-line control inserts CR normally */
7060 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP|ES_MULTILINE,
7061 0, 0, 200, 60, 0, 0, 0, 0);
7062 ok(hwnd != 0, "CreateWindowExA error %lu\n", GetLastError());
7063 disable_beep( hwnd );
7064
7066 ok (result == FALSE, "Can undo after window creation.\n");
7067 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
7068 ok (result == FALSE, "Undo operation successful with nothing to undo.\n");
7070 ok (result == FALSE, "Can redo after window creation.\n");
7071 result = SendMessageA(hwnd, EM_REDO, 0, 0);
7072 ok (result == FALSE, "Redo operation successful with nothing undone.\n");
7073
7074 /* Test the effect of arrows keys during typing on undo transactions*/
7075 simulate_typing_characters(hwnd, "one two three");
7078 simulate_typing_characters(hwnd, " four five six");
7079
7081 ok (result == FALSE, "Can redo before anything is undone.\n");
7083 ok (result == TRUE, "Cannot undo typed characters.\n");
7084 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
7085 ok (result == TRUE, "EM_UNDO Failed to undo typed characters.\n");
7087 ok (result == TRUE, "Cannot redo after undo.\n");
7089 result = strcmp(buffer, "one two three");
7090 ok (result == 0, "expected '%s' but got '%s'\n", "one two three", buffer);
7091
7093 ok (result == TRUE, "Cannot undo typed characters.\n");
7094 result = SendMessageA(hwnd, WM_UNDO, 0, 0);
7095 ok (result == TRUE, "Failed to undo typed characters.\n");
7097 result = strcmp(buffer, "");
7098 ok (result == 0, "expected '%s' but got '%s'\n", "", buffer);
7099
7100 /* Test the effect of focus changes during typing on undo transactions*/
7101 simulate_typing_characters(hwnd, "one two three");
7103 ok (result == FALSE, "Redo buffer should have been cleared by typing.\n");
7106 simulate_typing_characters(hwnd, " four five six");
7107 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
7108 ok (result == TRUE, "Failed to undo typed characters.\n");
7110 result = strcmp(buffer, "one two three");
7111 ok (result == 0, "expected '%s' but got '%s'\n", "one two three", buffer);
7112
7113 /* Test the effect of the back key during typing on undo transactions */
7116 ok (result == TRUE, "Failed to clear the text.\n");
7117 simulate_typing_characters(hwnd, "one two threa");
7119 ok (result == FALSE, "Redo buffer should have been cleared by typing.\n");
7122 simulate_typing_characters(hwnd, "e four five six");
7123 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
7124 ok (result == TRUE, "Failed to undo typed characters.\n");
7126 result = strcmp(buffer, "");
7127 ok (result == 0, "expected '%s' but got '%s'\n", "", buffer);
7128
7129 /* Test the effect of the delete key during typing on undo transactions */
7131 result = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"abcd");
7132 ok(result == TRUE, "Failed to set the text.\n");
7133 SendMessageA(hwnd, EM_SETSEL, 1, 1);
7138 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
7139 ok (result == TRUE, "Failed to undo typed characters.\n");
7141 result = strcmp(buffer, "acd");
7142 ok (result == 0, "expected '%s' but got '%s'\n", "acd", buffer);
7143 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
7144 ok (result == TRUE, "Failed to undo typed characters.\n");
7146 result = strcmp(buffer, "abcd");
7147 ok (result == 0, "expected '%s' but got '%s'\n", "abcd", buffer);
7148
7149 /* Test the effect of EM_STOPGROUPTYPING on undo transactions*/
7152 ok (result == TRUE, "Failed to clear the text.\n");
7153 simulate_typing_characters(hwnd, "one two three");
7155 ok (result == 0, "expected %d but got %d\n", 0, result);
7156 simulate_typing_characters(hwnd, " four five six");
7157 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
7158 ok (result == TRUE, "Failed to undo typed characters.\n");
7160 result = strcmp(buffer, "one two three");
7161 ok (result == 0, "expected '%s' but got '%s'\n", "one two three", buffer);
7162 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
7163 ok (result == TRUE, "Failed to undo typed characters.\n");
7165 result = strcmp(buffer, "");
7166 ok (result == 0, "expected '%s' but got '%s'\n", "", buffer);
7167
7169}
7170
7172{
7173 int length;
7174
7175 /* MSDN lied, length is actually the number of bytes. */
7176 length = bytes / sizeof(WCHAR);
7177 switch(code)
7178 {
7179 case WB_ISDELIMITER:
7180 return text[pos] == 'X';
7181 case WB_LEFT:
7182 case WB_MOVEWORDLEFT:
7184 return pos-1;
7186 case WB_LEFTBREAK:
7187 pos--;
7189 pos--;
7190 return pos;
7191 case WB_RIGHT:
7192 case WB_MOVEWORDRIGHT:
7194 return pos+1;
7196 case WB_RIGHTBREAK:
7197 pos++;
7199 pos++;
7200 return pos;
7201 default:
7202 ok(FALSE, "Unexpected code %d\n", code);
7203 break;
7204 }
7205 return 0;
7206}
7207
7208static void test_word_movement(void)
7209{
7210 HWND hwnd;
7211 int result;
7212 int sel_start, sel_end;
7213 const WCHAR textW[] = {'o','n','e',' ','t','w','o','X','t','h','r','e','e',0};
7214
7215 /* multi-line control inserts CR normally */
7217
7218 result = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"one two three");
7219 ok (result == TRUE, "Failed to clear the text.\n");
7220 SendMessageA(hwnd, EM_SETSEL, 0, 0);
7221 /* |one two three */
7222
7224 /* one |two three */
7225 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7226 ok(sel_start == sel_end, "Selection should be empty\n");
7227 ok(sel_start == 4, "Cursor is at %d instead of %d\n", sel_start, 4);
7228
7230 /* one two |three */
7231 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7232 ok(sel_start == sel_end, "Selection should be empty\n");
7233 ok(sel_start == 9, "Cursor is at %d instead of %d\n", sel_start, 9);
7234
7236 /* one |two three */
7237 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7238 ok(sel_start == sel_end, "Selection should be empty\n");
7239 ok(sel_start == 4, "Cursor is at %d instead of %d\n", sel_start, 4);
7240
7242 /* |one two three */
7243 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7244 ok(sel_start == sel_end, "Selection should be empty\n");
7245 ok(sel_start == 0, "Cursor is at %d instead of %d\n", sel_start, 0);
7246
7247 SendMessageA(hwnd, EM_SETSEL, 8, 8);
7248 /* one two | three */
7250 /* one two |three */
7251 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7252 ok(sel_start == sel_end, "Selection should be empty\n");
7253 ok(sel_start == 9, "Cursor is at %d instead of %d\n", sel_start, 9);
7254
7255 SendMessageA(hwnd, EM_SETSEL, 11, 11);
7256 /* one two th|ree */
7258 /* one two |three */
7259 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7260 ok(sel_start == sel_end, "Selection should be empty\n");
7261 ok(sel_start == 9, "Cursor is at %d instead of %d\n", sel_start, 9);
7262
7263 /* Test with a custom word break procedure that uses X as the delimiter. */
7264 result = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"one twoXthree");
7265 ok (result == TRUE, "Failed to clear the text.\n");
7267 /* |one twoXthree */
7269 /* one twoX|three */
7270 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7271 ok(sel_start == sel_end, "Selection should be empty\n");
7272 ok(sel_start == 8, "Cursor is at %d instead of %d\n", sel_start, 8);
7273
7275
7276 /* Make sure the behaviour is the same with a unicode richedit window,
7277 * and using unicode functions. */
7278
7281 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7282
7283 /* Test with a custom word break procedure that uses X as the delimiter. */
7285 ok (result == TRUE, "Failed to clear the text.\n");
7287 /* |one twoXthree */
7289 /* one twoX|three */
7290 SendMessageW(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7291 ok(sel_start == sel_end, "Selection should be empty\n");
7292 ok(sel_start == 8, "Cursor is at %d instead of %d\n", sel_start, 8);
7293
7295}
7296
7298{
7299 DWORD sel_start, sel_end;
7301 HWND hwnd;
7302
7303 /* multi-line control inserts CR normally */
7305
7306 result = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Lorem ipsum\rdolor sit\rnamet");
7307 ok(result == TRUE, "WM_SETTEXT returned %Iu.\n", result);
7308 SendMessageA(hwnd, EM_SETSEL, 0, 0);
7309 /* [|Lorem ipsum] [dolor sit] [amet] */
7310
7312 /* [Lorem |ipsum] [dolor sit] [amet] */
7313 sel_start = sel_end = 0xdeadbeefUL;
7314 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7315 ok(sel_start == sel_end, "expected sel length to be 0, got %lu.\n", sel_end - sel_start);
7316 ok(sel_start == 6, "expected sel_start to be %u, got %lu.\n", 6, sel_start);
7317
7319 /* [Lorem ipsum|] [dolor sit] [amet] */
7320 sel_start = sel_end = 0xdeadbeefUL;
7321 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7322 ok(sel_start == sel_end, "expected sel length to be 0, got %lu.\n", sel_end - sel_start);
7323 ok(sel_start == 11, "expected sel_start to be %u, got %lu.\n", 11, sel_start);
7324
7326 /* [Lorem ipsum] [|dolor sit] [amet] */
7327 sel_start = sel_end = 0xdeadbeefUL;
7328 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7329 ok(sel_start == sel_end, "expected sel length to be 0, got %lu.\n", sel_end - sel_start);
7330 ok(sel_start == 12, "expected sel_start to be %u, got %lu.\n", 12, sel_start);
7331
7333 /* [Lorem ipsum|] [dolor sit] [amet] */
7334 sel_start = sel_end = 0xdeadbeefUL;
7335 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7336 ok(sel_start == sel_end, "expected sel length to be 0, got %lu.\n", sel_end - sel_start);
7337 ok(sel_start == 11, "expected sel_start to be %u, got %lu.\n", 11, sel_start);
7338
7340}
7341
7342static void test_EM_CHARFROMPOS(void)
7343{
7344 HWND hwnd;
7345 int result;
7346 RECT rcClient;
7347 POINTL point;
7348 point.x = 0;
7349 point.y = 40;
7350
7351 /* multi-line control inserts CR normally */
7354 (LPARAM)"one two three four five six seven\reight");
7355 ok(result == 1, "Expected 1, got %d\n", result);
7356 GetClientRect(hwnd, &rcClient);
7357
7359 ok(result == 34, "expected character index of 34 but got %d\n", result);
7360
7361 /* Test with points outside the bounds of the richedit control. */
7362 point.x = -1;
7363 point.y = 40;
7365 ok(result == 34, "expected character index of 34 but got %d\n", result);
7366
7367 point.x = 1000;
7368 point.y = 0;
7370 ok(result == 33, "expected character index of 33 but got %d\n", result);
7371
7372 point.x = 1000;
7373 point.y = 36;
7375 ok(result == 39, "expected character index of 39 but got %d\n", result);
7376
7377 point.x = 1000;
7378 point.y = -1;
7380 /* This differs from the msftedit result */
7381 todo_wine ok(result == 0, "expected character index of 0 but got %d\n", result);
7382
7383 point.x = 1000;
7384 point.y = rcClient.bottom + 1;
7386 /* This differs from the msftedit result */
7387 todo_wine ok(result == 34, "expected character index of 34 but got %d\n", result);
7388
7389 point.x = 1000;
7390 point.y = rcClient.bottom;
7392 ok(result == 39, "expected character index of 39 but got %d\n", result);
7393
7395}
7396
7397static void test_word_wrap(void)
7398{
7399 HWND hwnd;
7400 POINTL point = {0, 60}; /* This point must be below the first line */
7401 const char *text = "Must be long enough to test line wrapping";
7403 int res, pos, lines;
7404
7405 /* Test the effect of WS_HSCROLL and ES_AUTOHSCROLL styles on wrapping
7406 * when specified on window creation and set later. */
7407 hwnd = CreateWindowA(RICHEDIT_CLASS20A, NULL, dwCommonStyle,
7408 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
7409 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
7411 ok(res, "WM_SETTEXT failed.\n");
7413 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
7415 ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines);
7416
7419 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
7421
7423 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
7424 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
7425
7427 ok(res, "WM_SETTEXT failed.\n");
7429 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
7431 ok(lines == 1, "Line wasn't expected to wrap (lines=%d).\n", lines);
7432
7433 SetWindowLongW(hwnd, GWL_STYLE, dwCommonStyle);
7435 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
7437
7439 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
7440 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
7442 ok(res, "WM_SETTEXT failed.\n");
7444 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
7445
7446 SetWindowLongW(hwnd, GWL_STYLE, dwCommonStyle);
7448 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
7450
7452 dwCommonStyle|WS_HSCROLL|ES_AUTOHSCROLL,
7453 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
7454 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
7456 ok(res, "WM_SETTEXT failed.\n");
7458 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
7459
7460 SetWindowLongW(hwnd, GWL_STYLE, dwCommonStyle);
7462 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
7463
7464 /* Test the effect of EM_SETTARGETDEVICE on word wrap. */
7466 ok(res, "EM_SETTARGETDEVICE failed (returned %d).\n", res);
7468 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
7469
7471 ok(res, "EM_SETTARGETDEVICE failed (returned %d).\n", res);
7473 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
7475
7476 /* Test to see if wrapping happens with redraw disabled. */
7477 hwnd = CreateWindowA(RICHEDIT_CLASS20A, NULL, dwCommonStyle,
7478 0, 0, 400, 80, NULL, NULL, hmoduleRichEdit, NULL);
7479 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
7482 ok(res, "EM_REPLACESEL failed.\n");
7484 ok(lines == 1, "Line wasn't expected to wrap (lines=%d).\n", lines);
7485 MoveWindow(hwnd, 0, 0, 200, 80, FALSE);
7487 ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines);
7488
7491}
7492
7493static void test_autoscroll(void)
7494{
7496 int lines, ret, redraw;
7497 POINT pt;
7498
7499 for (redraw = 0; redraw <= 1; redraw++) {
7500 trace("testing with WM_SETREDRAW=%d\n", redraw);
7502 SendMessageA(hwnd, EM_REPLACESEL, 0, (LPARAM)"1\n2\n3\n4\n5\n6\n7\n8");
7504 ok(lines == 8, "%d lines instead of 8\n", lines);
7506 ok(ret == 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret);
7507 ok(pt.y != 0, "Didn't scroll down after replacing text.\n");
7509 ok(ret & WS_VSCROLL, "Scrollbar was not shown yet (style=%x).\n", (UINT)ret);
7510
7513 ok(lines == 1, "%d lines instead of 1\n", lines);
7515 ok(ret == 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret);
7516 ok(pt.y == 0, "y scroll position is %ld after clearing text.\n", pt.y);
7518 ok(!(ret & WS_VSCROLL), "Scrollbar is still shown (style=%x).\n", (UINT)ret);
7519 }
7520
7523
7524 /* The WS_VSCROLL and WS_HSCROLL styles implicitly set
7525 * auto vertical/horizontal scrolling options. */
7528 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7529 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7531 ok(ret & ECO_AUTOVSCROLL, "ECO_AUTOVSCROLL isn't set.\n");
7532 ok(ret & ECO_AUTOHSCROLL, "ECO_AUTOHSCROLL isn't set.\n");
7534 ok(!(ret & ES_AUTOVSCROLL), "ES_AUTOVSCROLL is set.\n");
7535 ok(!(ret & ES_AUTOHSCROLL), "ES_AUTOHSCROLL is set.\n");
7537
7540 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7541 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7543 ok(!(ret & ECO_AUTOVSCROLL), "ECO_AUTOVSCROLL is set.\n");
7544 ok(!(ret & ECO_AUTOHSCROLL), "ECO_AUTOHSCROLL is set.\n");
7546 ok(!(ret & ES_AUTOVSCROLL), "ES_AUTOVSCROLL is set.\n");
7547 ok(!(ret & ES_AUTOHSCROLL), "ES_AUTOHSCROLL is set.\n");
7549}
7550
7551
7552static void test_format_rect(void)
7553{
7554 HWND hwnd;
7555 RECT rc, expected, clientRect;
7556 int n;
7557 DWORD options;
7558
7561 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7562 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7563
7564 GetClientRect(hwnd, &clientRect);
7565
7566 expected = clientRect;
7567 InflateRect(&expected, -1, 0);
7569 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7571
7572 for (n = -3; n <= 3; n++)
7573 {
7574 rc = clientRect;
7575 InflateRect(&rc, -n, -n);
7577
7578 expected = rc;
7579 expected.top = max(0, rc.top);
7580 expected.left = max(0, rc.left);
7581 expected.bottom = min(clientRect.bottom, rc.bottom);
7582 expected.right = min(clientRect.right, rc.right);
7584 ok(EqualRect(&rc, &expected), "[n=%d] rect %s != %s\n", n, wine_dbgstr_rect(&rc),
7586 }
7587
7588 rc = clientRect;
7590 expected = clientRect;
7592 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7594
7595 /* Adding the selectionbar adds the selectionbar width to the left side. */
7598 ok(options & ECO_SELECTIONBAR, "EM_SETOPTIONS failed to add selectionbar.\n");
7599 expected.left += 8; /* selection bar width */
7601 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7603
7604 rc = clientRect;
7606 expected = clientRect;
7608 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7610
7611 /* Removing the selectionbar subtracts the selectionbar width from the left side,
7612 * even if the left side is already 0. */
7615 ok(!(options & ECO_SELECTIONBAR), "EM_SETOPTIONS failed to remove selectionbar.\n");
7616 expected.left -= 8; /* selection bar width */
7618 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7620
7621 /* reset back to client rect and now try adding selection bar */
7623 expected = clientRect;
7624 InflateRect(&expected, -1, 0);
7626 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7630 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7633
7634 /* Set the absolute value of the formatting rectangle. */
7635 rc = clientRect;
7637 expected = clientRect;
7639 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7641
7642 /* MSDN documents the EM_SETRECT message as using the rectangle provided in
7643 * LPARAM as being a relative offset when the WPARAM value is 1, but these
7644 * tests show that this isn't true. */
7645 rc.top = 15;
7646 rc.left = 15;
7647 rc.bottom = clientRect.bottom - 15;
7648 rc.right = clientRect.right - 15;
7649 expected = rc;
7652 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7654
7655 /* For some reason it does not limit the values to the client rect with
7656 * a WPARAM value of 1. */
7657 rc.top = -15;
7658 rc.left = -15;
7659 rc.bottom = clientRect.bottom + 15;
7660 rc.right = clientRect.right + 15;
7661 expected = rc;
7664 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7666
7667 /* Reset to default rect and check how the format rect adjusts to window
7668 * resize and how it copes with very small windows */
7670
7671 MoveWindow(hwnd, 0, 0, 100, 30, FALSE);
7672 GetClientRect(hwnd, &clientRect);
7673
7674 expected = clientRect;
7675 InflateRect(&expected, -1, 0);
7677 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7679
7680 MoveWindow(hwnd, 0, 0, 0, 30, FALSE);
7681 GetClientRect(hwnd, &clientRect);
7682
7683 expected = clientRect;
7684 InflateRect(&expected, -1, 0);
7686 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7688
7689 MoveWindow(hwnd, 0, 0, 100, 0, FALSE);
7690 GetClientRect(hwnd, &clientRect);
7691
7692 expected = clientRect;
7693 InflateRect(&expected, -1, 0);
7695 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7697
7699
7700 /* The extended window style affects the formatting rectangle. */
7703 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7704 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7705
7706 GetClientRect(hwnd, &clientRect);
7707
7708 expected = clientRect;
7709 expected.top += 1;
7710 InflateRect(&expected, -1, 0);
7712 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7714
7715 rc = clientRect;
7716 InflateRect(&rc, -5, -5);
7717 expected = rc;
7718 expected.top -= 1;
7719 InflateRect(&expected, 1, 0);
7722 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7724
7726}
7727
7728static void test_WM_GETDLGCODE(void)
7729{
7730 HWND hwnd;
7731 UINT res, expected;
7732 MSG msg;
7733
7735
7738 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7739 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7740 msg.hwnd = hwnd;
7743 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7744 res, expected);
7746
7747 msg.message = WM_KEYDOWN;
7748 msg.wParam = VK_RETURN;
7749 msg.lParam = (MapVirtualKeyA(VK_RETURN, MAPVK_VK_TO_VSC) << 16) | 0x0001;
7750 msg.pt.x = 0;
7751 msg.pt.y = 0;
7752 msg.time = GetTickCount();
7753
7756 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7757 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7758 msg.hwnd = hwnd;
7761 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7762 res, expected);
7764
7767 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7768 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7769 msg.hwnd = hwnd;
7772 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7773 res, expected);
7775
7778 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7779 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7780 msg.hwnd = hwnd;
7783 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7784 res, expected);
7786
7788 WS_POPUP,
7789 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7790 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7791 msg.hwnd = hwnd;
7794 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7795 res, expected);
7797
7798 msg.wParam = VK_TAB;
7799 msg.lParam = (MapVirtualKeyA(VK_TAB, MAPVK_VK_TO_VSC) << 16) | 0x0001;
7800
7803 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7804 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7805 msg.hwnd = hwnd;
7808 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7809 res, expected);
7811
7813 WS_POPUP,
7814 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7815 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7816 msg.hwnd = hwnd;
7819 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7820 res, expected);
7822
7824
7827 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7828 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7829 msg.hwnd = hwnd;
7832 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7833 res, expected);
7835
7837 WS_POPUP,
7838 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7839 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7840 msg.hwnd = hwnd;
7843 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7844 res, expected);
7846
7848
7849 msg.wParam = 'a';
7850 msg.lParam = (MapVirtualKeyA('a', MAPVK_VK_TO_VSC) << 16) | 0x0001;
7851
7854 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7855 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7856 msg.hwnd = hwnd;
7859 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7860 res, expected);
7862
7864 WS_POPUP,
7865 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7866 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7867 msg.hwnd = hwnd;
7870 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7871 res, expected);
7873
7874 msg.message = WM_CHAR;
7875
7878 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7879 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7880 msg.hwnd = hwnd;
7883 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7884 res, expected);
7886
7888 WS_POPUP,
7889 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7890 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7891 msg.hwnd = hwnd;
7894 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7895 res, expected);
7897
7900 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7901 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7904 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7905 res, expected);
7907}
7908
7909static void test_zoom(void)
7910{
7911 HWND hwnd;
7912 UINT ret;
7913 RECT rc;
7914 POINT pt;
7915 int numerator, denominator;
7916
7918 GetClientRect(hwnd, &rc);
7919 pt.x = (rc.right - rc.left) / 2;
7920 pt.y = (rc.bottom - rc.top) / 2;
7922
7923 /* Test initial zoom value */
7924 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7925 ok(numerator == 0, "Numerator should be initialized to 0 (got %d).\n", numerator);
7926 ok(denominator == 0, "Denominator should be initialized to 0 (got %d).\n", denominator);
7927 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7928
7929 /* test scroll wheel */
7932 MAKELPARAM(pt.x, pt.y));
7933 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret);
7935
7936 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7937 ok(numerator == 110, "incorrect numerator is %d\n", numerator);
7938 ok(denominator == 100, "incorrect denominator is %d\n", denominator);
7939 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7940
7941 /* Test how much the mouse wheel can zoom in and out. */
7942 ret = SendMessageA(hwnd, EM_SETZOOM, 490, 100);
7943 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret);
7944
7947 MAKELPARAM(pt.x, pt.y));
7948 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret);
7950
7951 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7952 ok(numerator == 500, "incorrect numerator is %d\n", numerator);
7953 ok(denominator == 100, "incorrect denominator is %d\n", denominator);
7954 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7955
7956 ret = SendMessageA(hwnd, EM_SETZOOM, 491, 100);
7957 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret);
7958
7961 MAKELPARAM(pt.x, pt.y));
7962 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret);
7964
7965 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7966 ok(numerator == 491, "incorrect numerator is %d\n", numerator);
7967 ok(denominator == 100, "incorrect denominator is %d\n", denominator);
7968 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7969
7970 ret = SendMessageA(hwnd, EM_SETZOOM, 20, 100);
7971 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret);
7972
7975 MAKELPARAM(pt.x, pt.y));
7976 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret);
7978
7979 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7980 ok(numerator == 10, "incorrect numerator is %d\n", numerator);
7981 ok(denominator == 100, "incorrect denominator is %d\n", denominator);
7982 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7983
7984 ret = SendMessageA(hwnd, EM_SETZOOM, 19, 100);
7985 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret);
7986
7989 MAKELPARAM(pt.x, pt.y));
7990 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret);
7992
7993 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7994 ok(numerator == 19, "incorrect numerator is %d\n", numerator);
7995 ok(denominator == 100, "incorrect denominator is %d\n", denominator);
7996 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7997
7998 /* Test how WM_SCROLLWHEEL treats our custom denominator. */
7999 ret = SendMessageA(hwnd, EM_SETZOOM, 50, 13);
8000 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret);
8001
8004 MAKELPARAM(pt.x, pt.y));
8005 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret);
8007
8008 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
8009 ok(numerator == 394, "incorrect numerator is %d\n", numerator);
8010 ok(denominator == 100, "incorrect denominator is %d\n", denominator);
8011 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
8012
8013 /* Test bounds checking on EM_SETZOOM */
8014 ret = SendMessageA(hwnd, EM_SETZOOM, 2, 127);
8015 ok(ret == TRUE, "EM_SETZOOM rejected valid values (%d).\n", ret);
8016
8017 ret = SendMessageA(hwnd, EM_SETZOOM, 127, 2);
8018 ok(ret == TRUE, "EM_SETZOOM rejected valid values (%d).\n", ret);
8019
8020 ret = SendMessageA(hwnd, EM_SETZOOM, 2, 128);
8021 ok(ret == FALSE, "EM_SETZOOM accepted invalid values (%d).\n", ret);
8022
8023 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
8024 ok(numerator == 127, "incorrect numerator is %d\n", numerator);
8025 ok(denominator == 2, "incorrect denominator is %d\n", denominator);
8026 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
8027
8028 ret = SendMessageA(hwnd, EM_SETZOOM, 128, 2);
8029 ok(ret == FALSE, "EM_SETZOOM accepted invalid values (%d).\n", ret);
8030
8031 /* See if negative numbers are accepted. */
8032 ret = SendMessageA(hwnd, EM_SETZOOM, -100, -100);
8033 ok(ret == FALSE, "EM_SETZOOM accepted invalid values (%d).\n", ret);
8034
8035 /* See if negative numbers are accepted. */
8036 ret = SendMessageA(hwnd, EM_SETZOOM, 0, 100);
8037 ok(ret == FALSE, "EM_SETZOOM failed (%d).\n", ret);
8038
8039 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
8040 ok(numerator == 127, "incorrect numerator is %d\n", numerator);
8041 ok(denominator == 2, "incorrect denominator is %d\n", denominator);
8042 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
8043
8044 /* Reset the zoom value */
8045 ret = SendMessageA(hwnd, EM_SETZOOM, 0, 0);
8046 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret);
8047
8049}
8050
8052{
8054};
8055
8057
8058#define test_dm_messages(wmclose, wmgetdefid, wmnextdlgctl) \
8059 ok(dm_messages.wm_close == wmclose, "expected %d WM_CLOSE message, " \
8060 "got %d\n", wmclose, dm_messages.wm_close); \
8061 ok(dm_messages.wm_getdefid == wmgetdefid, "expected %d WM_GETDIFID message, " \
8062 "got %d\n", wmgetdefid, dm_messages.wm_getdefid);\
8063 ok(dm_messages.wm_nextdlgctl == wmnextdlgctl, "expected %d WM_NEXTDLGCTL message, " \
8064 "got %d\n", wmnextdlgctl, dm_messages.wm_nextdlgctl)
8065
8067{
8068 switch (iMsg)
8069 {
8070 case DM_GETDEFID:
8071 dm_messages.wm_getdefid++;
8073 case WM_NEXTDLGCTL:
8074 dm_messages.wm_nextdlgctl++;
8075 break;
8076 case WM_CLOSE:
8077 dm_messages.wm_close++;
8078 break;
8079 }
8080
8081 return DefWindowProcA(hwnd, iMsg, wParam, lParam);
8082}
8083
8084static void test_dialogmode(void)
8085{
8086 HWND hwRichEdit, hwParent, hwButton;
8087 MSG msg= {0};
8088 int lcount, r;
8089 WNDCLASSA cls;
8090
8091 cls = make_simple_class(dialog_mode_wnd_proc, "DialogModeParentClass");
8092 if(!RegisterClassA(&cls)) assert(0);
8093
8094 hwParent = CreateWindowA("DialogModeParentClass", NULL, WS_OVERLAPPEDWINDOW,
8095 CW_USEDEFAULT, 0, 200, 120, NULL, NULL, GetModuleHandleA(0), NULL);
8096
8097 /* Test richedit(ES_MULTILINE) */
8098
8099 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE, hwParent);
8100
8101 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8102 ok(0 == r, "expected 0, got %d\n", r);
8103 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8104 ok(2 == lcount, "expected 2, got %d\n", lcount);
8105
8106 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, 0);
8107 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r);
8108
8109 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8110 ok(0 == r, "expected 0, got %d\n", r);
8111 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8112 ok(3 == lcount, "expected 3, got %d\n", lcount);
8113
8114 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
8115 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r);
8116 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8117 ok(0 == r, "expected 0, got %d\n", r);
8118 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8119 ok(3 == lcount, "expected 3, got %d\n", lcount);
8120
8121 DestroyWindow(hwRichEdit);
8122
8123 /* Test standalone richedit(ES_MULTILINE) */
8124
8126
8127 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8128 ok(0 == r, "expected 0, got %d\n", r);
8129 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8130 ok(2 == lcount, "expected 2, got %d\n", lcount);
8131
8132 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
8133 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r);
8134
8135 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8136 ok(0 == r, "expected 0, got %d\n", r);
8137 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8138 ok(2 == lcount, "expected 2, got %d\n", lcount);
8139
8140 DestroyWindow(hwRichEdit);
8141
8142 /* Check a destination for messages */
8143
8144 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE, hwParent);
8145
8146 SetWindowLongA(hwRichEdit, GWL_STYLE, GetWindowLongA(hwRichEdit, GWL_STYLE)& ~WS_POPUP);
8147 SetParent( hwRichEdit, NULL);
8148
8149 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
8150 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r);
8151
8152 memset(&dm_messages, 0, sizeof(dm_messages));
8153 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8154 ok(0 == r, "expected 0, got %d\n", r);
8155 test_dm_messages(0, 1, 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 DestroyWindow(hwRichEdit);
8163
8164 /* Check messages from richedit(ES_MULTILINE) */
8165
8166 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE, hwParent);
8167
8168 memset(&dm_messages, 0, sizeof(dm_messages));
8169 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8170 ok(0 == r, "expected 0, got %d\n", r);
8171 test_dm_messages(0, 0, 0);
8172
8173 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8174 ok(2 == lcount, "expected 2, got %d\n", lcount);
8175
8176 memset(&dm_messages, 0, sizeof(dm_messages));
8177 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
8178 ok(0 == r, "expected 0, got %d\n", r);
8179 test_dm_messages(0, 0, 0);
8180
8181 memset(&dm_messages, 0, sizeof(dm_messages));
8182 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
8183 ok(0 == r, "expected 0, got %d\n", r);
8184 test_dm_messages(0, 0, 0);
8185
8186 memset(&dm_messages, 0, sizeof(dm_messages));
8187 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
8188 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r);
8189 test_dm_messages(0, 0, 0);
8190
8191 memset(&dm_messages, 0, sizeof(dm_messages));
8192 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8193 ok(0 == r, "expected 0, got %d\n", r);
8194 test_dm_messages(0, 1, 0);
8195
8196 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8197 ok(2 == lcount, "expected 2, got %d\n", lcount);
8198
8199 memset(&dm_messages, 0, sizeof(dm_messages));
8200 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
8201 ok(0 == r, "expected 0, got %d\n", r);
8202 test_dm_messages(0, 0, 0);
8203
8204 memset(&dm_messages, 0, sizeof(dm_messages));
8205 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
8206 ok(0 == r, "expected 0, got %d\n", r);
8207 test_dm_messages(0, 0, 1);
8208
8209 hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON,
8210 100, 100, 50, 20, hwParent, (HMENU)ID_RICHEDITTESTDBUTTON, GetModuleHandleA(0), NULL);
8211 ok(hwButton!=NULL, "CreateWindow failed with error code %ld\n", GetLastError());
8212
8213 memset(&dm_messages, 0, sizeof(dm_messages));
8214 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8215 ok(0 == r, "expected 0, got %d\n", r);
8216 test_dm_messages(0, 1, 1);
8217
8218 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8219 ok(2 == lcount, "expected 2, got %d\n", lcount);
8220
8221 DestroyWindow(hwButton);
8222 DestroyWindow(hwRichEdit);
8223
8224 /* Check messages from richedit(ES_MULTILINE|ES_WANTRETURN) */
8225
8226 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE|ES_WANTRETURN, hwParent);
8227
8228 memset(&dm_messages, 0, sizeof(dm_messages));
8229 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8230 ok(0 == r, "expected 0, got %d\n", r);
8231 test_dm_messages(0, 0, 0);
8232
8233 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8234 ok(2 == lcount, "expected 2, got %d\n", lcount);
8235
8236 memset(&dm_messages, 0, sizeof(dm_messages));
8237 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
8238 ok(0 == r, "expected 0, got %d\n", r);
8239 test_dm_messages(0, 0, 0);
8240
8241 memset(&dm_messages, 0, sizeof(dm_messages));
8242 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
8243 ok(0 == r, "expected 0, got %d\n", r);
8244 test_dm_messages(0, 0, 0);
8245
8246 memset(&dm_messages, 0, sizeof(dm_messages));
8247 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
8248 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r);
8249 test_dm_messages(0, 0, 0);
8250
8251 memset(&dm_messages, 0, sizeof(dm_messages));
8252 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8253 ok(0 == r, "expected 0, got %d\n", r);
8254 test_dm_messages(0, 0, 0);
8255
8256 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8257 ok(3 == lcount, "expected 3, got %d\n", lcount);
8258
8259 memset(&dm_messages, 0, sizeof(dm_messages));
8260 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
8261 ok(0 == r, "expected 0, got %d\n", r);
8262 test_dm_messages(0, 0, 0);
8263
8264 memset(&dm_messages, 0, sizeof(dm_messages));
8265 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
8266 ok(0 == r, "expected 0, got %d\n", r);
8267 test_dm_messages(0, 0, 1);
8268
8269 hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON,
8270 100, 100, 50, 20, hwParent, (HMENU)ID_RICHEDITTESTDBUTTON, GetModuleHandleA(0), NULL);
8271 ok(hwButton!=NULL, "CreateWindow failed with error code %ld\n", GetLastError());
8272
8273 memset(&dm_messages, 0, sizeof(dm_messages));
8274 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8275 ok(0 == r, "expected 0, got %d\n", r);
8276 test_dm_messages(0, 0, 0);
8277
8278 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8279 ok(4 == lcount, "expected 4, got %d\n", lcount);
8280
8281 DestroyWindow(hwButton);
8282 DestroyWindow(hwRichEdit);
8283
8284 /* Check messages from richedit(0) */
8285
8286 hwRichEdit = new_window(RICHEDIT_CLASS20A, 0, hwParent);
8287
8288 memset(&dm_messages, 0, sizeof(dm_messages));
8289 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8290 ok(0 == r, "expected 0, got %d\n", r);
8291 test_dm_messages(0, 0, 0);
8292
8293 memset(&dm_messages, 0, sizeof(dm_messages));
8294 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
8295 ok(0 == r, "expected 0, got %d\n", r);
8296 test_dm_messages(0, 0, 0);
8297
8298 memset(&dm_messages, 0, sizeof(dm_messages));
8299 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
8300 ok(0 == r, "expected 0, got %d\n", r);
8301 test_dm_messages(0, 0, 0);
8302
8303 memset(&dm_messages, 0, sizeof(dm_messages));
8304 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
8305 ok(0x8b == r, "expected 0x8b, got 0x%x\n", r);
8306 test_dm_messages(0, 0, 0);
8307
8308 memset(&dm_messages, 0, sizeof(dm_messages));
8309 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8310 ok(0 == r, "expected 0, got %d\n", r);
8311 test_dm_messages(0, 1, 0);
8312
8313 memset(&dm_messages, 0, sizeof(dm_messages));
8314 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
8315 ok(0 == r, "expected 0, got %d\n", r);
8316 test_dm_messages(0, 0, 0);
8317
8318 memset(&dm_messages, 0, sizeof(dm_messages));
8319 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
8320 ok(0 == r, "expected 0, got %d\n", r);
8321 test_dm_messages(0, 0, 1);
8322
8323 hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON,
8324 100, 100, 50, 20, hwParent, (HMENU)ID_RICHEDITTESTDBUTTON, GetModuleHandleA(0), NULL);
8325 ok(hwButton!=NULL, "CreateWindow failed with error code %ld\n", GetLastError());
8326
8327 memset(&dm_messages, 0, sizeof(dm_messages));
8328 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8329 ok(0 == r, "expected 0, got %d\n", r);
8330 test_dm_messages(0, 1, 1);
8331
8332 DestroyWindow(hwRichEdit);
8333
8334 /* Check messages from richedit(ES_WANTRETURN) */
8335
8336 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_WANTRETURN, hwParent);
8337
8338 memset(&dm_messages, 0, sizeof(dm_messages));
8339 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8340 ok(0 == r, "expected 0, got %d\n", r);
8341 test_dm_messages(0, 0, 0);
8342
8343 memset(&dm_messages, 0, sizeof(dm_messages));
8344 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
8345 ok(0x8b == r, "expected 0x8b, got 0x%x\n", r);
8346 test_dm_messages(0, 0, 0);
8347
8348 memset(&dm_messages, 0, sizeof(dm_messages));
8349 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8350 ok(0 == r, "expected 0, got %d\n", r);
8351 test_dm_messages(0, 0, 0);
8352
8353 hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON,
8354 100, 100, 50, 20, hwParent, (HMENU)ID_RICHEDITTESTDBUTTON, GetModuleHandleA(0), NULL);
8355 ok(hwButton!=NULL, "CreateWindow failed with error code %ld\n", GetLastError());
8356
8357 memset(&dm_messages, 0, sizeof(dm_messages));
8358 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8359 ok(0 == r, "expected 0, got %d\n", r);
8360 test_dm_messages(0, 0, 0);
8361
8362 DestroyWindow(hwRichEdit);
8363 DestroyWindow(hwParent);
8364}
8365
8367{
8368 static const struct {
8369 WCHAR c;
8370 BOOL isdelimiter; /* expected result of WB_ISDELIMITER */
8371 } delimiter_tests[] = {
8372 {0x0a, FALSE}, /* newline */
8373 {0x0b, FALSE}, /* vertical tab */
8374 {0x0c, FALSE}, /* form feed */
8375 {0x0d, FALSE}, /* carriage return */
8376 {0x20, TRUE}, /* space */
8377 {0x61, FALSE}, /* capital letter a */
8378 {0xa0, FALSE}, /* no-break space */
8379 {0x2000, FALSE}, /* en quad */
8380 {0x3000, FALSE}, /* Ideographic space */
8381 {0x1100, FALSE}, /* Hangul Choseong Kiyeok (G sound) Ordinary Letter*/
8382 {0x11ff, FALSE}, /* Hangul Jongseoung Kiyeok-Hieuh (Hard N sound) Ordinary Letter*/
8383 {0x115f, FALSE}, /* Hangul Choseong Filler (no sound, used with two letter Hangul words) Ordinary Letter */
8384 {0xac00, FALSE}, /* Hangul character GA*/
8385 {0xd7af, FALSE}, /* End of Hangul character chart */
8386 {0xf020, TRUE}, /* MS private for CP_SYMBOL round trip?, see kb897872 */
8387 {0xff20, FALSE}, /* fullwidth commercial @ */
8388 {WCH_EMBEDDING, FALSE}, /* object replacement character*/
8389 };
8390 int i;
8391 HWND hwndRichEdit = new_richeditW(NULL);
8392 ok(IsWindowUnicode(hwndRichEdit), "window should be unicode\n");
8393 for (i = 0; i < ARRAY_SIZE(delimiter_tests); i++)
8394 {
8395 WCHAR wbuf[2];
8396 int result;
8397
8398 wbuf[0] = delimiter_tests[i].c;
8399 wbuf[1] = 0;
8400 SendMessageW(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)wbuf);
8402 todo_wine_if (wbuf[0] == 0x20 || wbuf[0] == 0xf020)
8403 ok(result == delimiter_tests[i].isdelimiter,
8404 "wanted ISDELIMITER_W(0x%x) %d, got %d\n",
8405 delimiter_tests[i].c, delimiter_tests[i].isdelimiter, result);
8406 }
8407 DestroyWindow(hwndRichEdit);
8408}
8409
8411{
8412 static const struct {
8413 WCHAR c;
8414 BOOL isdelimiter; /* expected result of WB_ISDELIMITER */
8415 } delimiter_tests[] = {
8416 {0x0a, FALSE}, /* newline */
8417 {0x0b, FALSE}, /* vertical tab */
8418 {0x0c, FALSE}, /* form feed */
8419 {0x0d, FALSE}, /* carriage return */
8420 {0x20, TRUE}, /* space */
8421 {0x61, FALSE}, /* capital letter a */
8422 };
8423 int i;
8424 HWND hwndRichEdit = new_richedit(NULL);
8425
8426 ok(!IsWindowUnicode(hwndRichEdit), "window should not be unicode\n");
8427 for (i = 0; i < ARRAY_SIZE(delimiter_tests); i++)
8428 {
8429 int result;
8430 char buf[2];
8431 buf[0] = delimiter_tests[i].c;
8432 buf[1] = 0;
8433 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buf);
8435 todo_wine_if (buf[0] == 0x20)
8436 ok(result == delimiter_tests[i].isdelimiter,
8437 "wanted ISDELIMITER_A(0x%x) %d, got %d\n",
8438 delimiter_tests[i].c, delimiter_tests[i].isdelimiter, result);
8439 }
8440 DestroyWindow(hwndRichEdit);
8441}
8442
8443static void format_test_result(char *target, const char *src)
8444{
8445 int i;
8446 for (i = 0; i < strlen(src); i++)
8447 sprintf(target + 2*i, "%02x", src[i] & 0xFF);
8448 target[2*i] = 0;
8449}
8450
8451/*
8452 * This test attempts to show the effect of enter on a richedit
8453 * control v1.0 inserts CRLF whereas for higher versions it only
8454 * inserts CR. If shows that EM_GETTEXTEX with GT_USECRLF == WM_GETTEXT
8455 * and also shows that GT_USECRLF has no effect in richedit 1.0, but
8456 * does for higher. The same test is cloned in riched32 and riched20.
8457 * Also shows the difference between WM_CHAR/WM_KEYDOWN in v1.0 and higher versions
8458 */
8459static void test_enter(void)
8460{
8461 static const struct {
8462 const char *initialtext;
8463 const int cursor;
8464 const char *expectedwmtext;
8465 const char *expectedemtext;
8466 const char *expectedemtextcrlf;
8467 } testenteritems[] = {
8468 { "aaabbb\r\n", 3, "aaa\r\nbbb\r\n", "aaa\rbbb\r", "aaa\r\nbbb\r\n"},
8469 { "aaabbb\r\n", 6, "aaabbb\r\n\r\n", "aaabbb\r\r", "aaabbb\r\n\r\n"},
8470 { "aa\rabbb\r\n", 7, "aa\r\nabbb\r\n\r\n", "aa\rabbb\r\r", "aa\r\nabbb\r\n\r\n"},
8471 { "aa\rabbb\r\n", 3, "aa\r\n\r\nabbb\r\n", "aa\r\rabbb\r", "aa\r\n\r\nabbb\r\n"},
8472 { "aa\rabbb\r\n", 2, "aa\r\n\r\nabbb\r\n", "aa\r\rabbb\r", "aa\r\n\r\nabbb\r\n"}
8473 };
8474
8475 char expectedbuf[1024];
8476 char resultbuf[1024];
8477 HWND hwndRichEdit = new_richedit(NULL);
8478 UINT i;
8479 char buf[1024] = {0};
8480 GETTEXTEX getText = {sizeof(buf)};
8482 const char *expected;
8483
8484 for (i = 0; i < ARRAY_SIZE(testenteritems); i++)
8485 {
8486 /* Set the text to the initial text */
8487 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)testenteritems[i].initialtext);
8488 ok (result == 1, "[%d] WM_SETTEXT returned %Id instead of 1\n", i, result);
8489
8490 /* Send Enter */
8491 SendMessageA(hwndRichEdit, EM_SETSEL, testenteritems[i].cursor, testenteritems[i].cursor);
8492 simulate_typing_characters(hwndRichEdit, "\r");
8493
8494 /* 1. Retrieve with WM_GETTEXT */
8495 buf[0] = 0x00;
8496 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf);
8497 expected = testenteritems[i].expectedwmtext;
8498
8499 format_test_result(resultbuf, buf);
8500 format_test_result(expectedbuf, expected);
8501
8503 ok (result == 0,
8504 "[%d] WM_GETTEXT unexpected '%s' expected '%s'\n",
8505 i, resultbuf, expectedbuf);
8506
8507 /* 2. Retrieve with EM_GETTEXTEX, GT_DEFAULT */
8508 getText.flags = GT_DEFAULT;
8509 getText.codepage = CP_ACP;
8510 buf[0] = 0x00;
8511 result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
8512 expected = testenteritems[i].expectedemtext;
8513
8514 format_test_result(resultbuf, buf);
8515 format_test_result(expectedbuf, expected);
8516
8518 ok (result == 0,
8519 "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n",
8520 i, resultbuf, expectedbuf);
8521
8522 /* 3. Retrieve with EM_GETTEXTEX, GT_USECRLF */
8523 getText.flags = GT_USECRLF;
8524 getText.codepage = CP_ACP;
8525 buf[0] = 0x00;
8526 result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
8527 expected = testenteritems[i].expectedemtextcrlf;
8528
8529 format_test_result(resultbuf, buf);
8530 format_test_result(expectedbuf, expected);
8531
8533 ok (result == 0,
8534 "[%d] EM_GETTEXTEX, GT_USECRLF unexpected '%s', expected '%s'\n",
8535 i, resultbuf, expectedbuf);
8536 }
8537
8538 /* Show that WM_CHAR is handled differently from WM_KEYDOWN */
8539 getText.flags = GT_DEFAULT;
8540 getText.codepage = CP_ACP;
8541
8542 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
8543 ok (result == 1, "[%d] WM_SETTEXT returned %Id instead of 1\n", i, result);
8544 SendMessageW(hwndRichEdit, WM_CHAR, 'T', 0);
8545 SendMessageW(hwndRichEdit, WM_KEYDOWN, VK_RETURN, 0);
8546
8547 result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
8548 ok(result == 2, "Got %d\n", (int)result);
8549 format_test_result(resultbuf, buf);
8550 format_test_result(expectedbuf, "T\r");
8551 result = strcmp(resultbuf, expectedbuf);
8552 ok (result == 0, "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n", i, resultbuf, expectedbuf);
8553
8554 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
8555 ok (result == 1, "[%d] WM_SETTEXT returned %Id instead of 1\n", i, result);
8556 SendMessageW(hwndRichEdit, WM_CHAR, 'T', 0);
8557 SendMessageW(hwndRichEdit, WM_CHAR, '\r', 0);
8558
8559 result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
8560 ok(result == 1, "Got %d\n", (int)result);
8561 format_test_result(resultbuf, buf);
8562 format_test_result(expectedbuf, "T");
8563 result = strcmp(resultbuf, expectedbuf);
8564 ok (result == 0, "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n", i, resultbuf, expectedbuf);
8565
8566 DestroyWindow(hwndRichEdit);
8567}
8568
8569static void test_WM_CREATE(void)
8570{
8571 static const WCHAR titleW[] = {'l','i','n','e','1','\n','l','i','n','e','2',0};
8572 static const char title[] = "line1\nline2";
8573
8574 HWND rich_edit;
8575 LRESULT res;
8576 char buf[64];
8577 int len;
8578
8580 0, 0, 200, 80, NULL, NULL, NULL, NULL);
8581 ok(rich_edit != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
8582
8583 len = GetWindowTextA(rich_edit, buf, sizeof(buf));
8584 ok(len == 5, "GetWindowText returned %d\n", len);
8585 ok(!strcmp(buf, "line1"), "buf = %s\n", buf);
8586
8587 res = SendMessageA(rich_edit, EM_GETSEL, 0, 0);
8588 ok(res == 0, "SendMessage(EM_GETSEL) returned %Ix\n", res);
8589
8590 DestroyWindow(rich_edit);
8591
8593 0, 0, 200, 80, NULL, NULL, NULL, NULL);
8594 ok(rich_edit != NULL, "class: %s, error: %d\n", wine_dbgstr_w(RICHEDIT_CLASS20W), (int) GetLastError());
8595
8596 len = GetWindowTextA(rich_edit, buf, sizeof(buf));
8597 ok(len == 12, "GetWindowText returned %d\n", len);
8598 ok(!strcmp(buf, "line1\r\nline2"), "buf = %s\n", buf);
8599
8600 res = SendMessageA(rich_edit, EM_GETSEL, 0, 0);
8601 ok(res == 0, "SendMessage(EM_GETSEL) returned %Ix\n", res);
8602
8603 DestroyWindow(rich_edit);
8604}
8605
8606/*******************************************************************
8607 * Test that after deleting all of the text, the first paragraph
8608 * format reverts to the default.
8609 */
8611{
8612 HWND richedit = new_richeditW( NULL );
8614 WORD def_align, new_align;
8615
8616 memset( &fmt, 0, sizeof(fmt) );
8617 fmt.cbSize = sizeof(PARAFORMAT2);
8618 fmt.dwMask = -1;
8619 SendMessageA( richedit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt );
8620 def_align = fmt.wAlignment;
8621 new_align = (def_align == PFA_LEFT) ? PFA_RIGHT : PFA_LEFT;
8622
8623 simulate_typing_characters( richedit, "123" );
8624
8625 SendMessageA( richedit, EM_SETSEL, 0, -1 );
8626 fmt.dwMask = PFM_ALIGNMENT;
8627 fmt.wAlignment = new_align;
8628 SendMessageA( richedit, EM_SETPARAFORMAT, 0, (LPARAM)&fmt );
8629
8630 SendMessageA( richedit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt );
8631 ok( fmt.wAlignment == new_align, "got %d expect %d\n", fmt.wAlignment, new_align );
8632
8633 SendMessageA( richedit, EM_SETSEL, 0, -1 );
8634 SendMessageA( richedit, WM_CUT, 0, 0 );
8635
8636 SendMessageA( richedit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt );
8637 ok( fmt.wAlignment == def_align, "got %d expect %d\n", fmt.wAlignment, def_align );
8638
8639 DestroyWindow( richedit );
8640}
8641
8642static void test_EM_SETREADONLY(void)
8643{
8644 HWND richedit = new_richeditW(NULL);
8645 DWORD dwStyle;
8646 LRESULT res;
8647
8648 res = SendMessageA(richedit, EM_SETREADONLY, TRUE, 0);
8649 ok(res == 1, "EM_SETREADONLY\n");
8650 dwStyle = GetWindowLongA(richedit, GWL_STYLE);
8651 ok(dwStyle & ES_READONLY, "got wrong value: 0x%lx\n", dwStyle);
8652
8653 res = SendMessageA(richedit, EM_SETREADONLY, FALSE, 0);
8654 ok(res == 1, "EM_SETREADONLY\n");
8655 dwStyle = GetWindowLongA(richedit, GWL_STYLE);
8656 ok(!(dwStyle & ES_READONLY), "got wrong value: 0x%lx\n", dwStyle);
8657
8658 DestroyWindow(richedit);
8659}
8660
8662{
8663 return value / 20;
8664}
8665
8666#define TEST_EM_SETFONTSIZE(hwnd,size,expected_size,expected_res,expected_undo) \
8667 _test_font_size(__LINE__,hwnd,size,expected_size,expected_res,expected_undo)
8668static void _test_font_size(unsigned line, HWND hwnd, LONG size, LONG expected_size,
8669 LRESULT expected_res, BOOL expected_undo)
8670{
8672 LRESULT res;
8673 BOOL isundo;
8674
8675 cf.cbSize = sizeof(cf);
8676 cf.dwMask = CFM_SIZE;
8677
8680 isundo = SendMessageA(hwnd, EM_CANUNDO, 0, 0);
8681 ok_(__FILE__,line)(res == expected_res, "EM_SETFONTSIZE unexpected return value: %Ix.\n", res);
8682 ok_(__FILE__,line)(twips2points(cf.yHeight) == expected_size, "got wrong font size: %ld, expected: %ld\n",
8683 twips2points(cf.yHeight), expected_size);
8684 ok_(__FILE__,line)(isundo == expected_undo, "get wrong undo mark: %d, expected: %d.\n",
8685 isundo, expected_undo);
8686}
8687
8688static void test_EM_SETFONTSIZE(void)
8689{
8690 HWND richedit = new_richedit(NULL);
8691 CHAR text[] = "wine";
8692 CHARFORMAT2A tmp_cf;
8693 LONG default_size;
8694
8695 tmp_cf.cbSize = sizeof(tmp_cf);
8696 tmp_cf.dwMask = CFM_SIZE;
8697 tmp_cf.yHeight = 9 * 20.0;
8698 SendMessageA(richedit, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM)&tmp_cf);
8699
8700 SendMessageA(richedit, WM_SETTEXT, 0, (LPARAM)text);
8701
8702 SendMessageA(richedit, EM_SETMODIFY, FALSE, 0);
8703 /* without selection */
8704 TEST_EM_SETFONTSIZE(richedit, 1, 10, TRUE, FALSE); /* 9 + 1 -> 10 */
8705 SendMessageA(richedit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&tmp_cf);
8706 default_size = twips2points(tmp_cf.yHeight);
8707 ok(default_size == 9, "Default font size should not be changed.\n");
8708 ok(SendMessageA(richedit, EM_SETMODIFY, 0, 0) == FALSE, "Modify flag should not be changed.\n");
8709
8710 SendMessageA(richedit, EM_SETSEL, 0, 2);
8711
8712 TEST_EM_SETFONTSIZE(richedit, 0, 9, TRUE, TRUE); /* 9 + 0 -> 9 */
8713
8714 SendMessageA(richedit, EM_SETMODIFY, FALSE, 0);
8715 TEST_EM_SETFONTSIZE(richedit, 3, 12, TRUE, TRUE); /* 9 + 3 -> 12 */
8716 ok(SendMessageA(richedit, EM_SETMODIFY, 0, 0) == FALSE, "Modify flag should not be changed.\n");
8717
8718 TEST_EM_SETFONTSIZE(richedit, 1, 14, TRUE, TRUE); /* 12 + 1 + 1 -> 14 */
8719 TEST_EM_SETFONTSIZE(richedit, -1, 12, TRUE, TRUE); /* 14 - 1 - 1 -> 12 */
8720 TEST_EM_SETFONTSIZE(richedit, 4, 16, TRUE, TRUE); /* 12 + 4 -> 16 */
8721 TEST_EM_SETFONTSIZE(richedit, 3, 20, TRUE, TRUE); /* 16 + 3 + 1 -> 20 */
8722 TEST_EM_SETFONTSIZE(richedit, 0, 20, TRUE, TRUE); /* 20 + 0 -> 20 */
8723 TEST_EM_SETFONTSIZE(richedit, 8, 28, TRUE, TRUE); /* 20 + 8 -> 28 */
8724 TEST_EM_SETFONTSIZE(richedit, 0, 28, TRUE, TRUE); /* 28 + 0 -> 28 */
8725 TEST_EM_SETFONTSIZE(richedit, 1, 36, TRUE, TRUE); /* 28 + 1 -> 36 */
8726 TEST_EM_SETFONTSIZE(richedit, 0, 36, TRUE, TRUE); /* 36 + 0 -> 36 */
8727 TEST_EM_SETFONTSIZE(richedit, 1, 48, TRUE, TRUE); /* 36 + 1 -> 48 */
8728 TEST_EM_SETFONTSIZE(richedit, 0, 48, TRUE, TRUE); /* 48 + 0 -> 48 */
8729 TEST_EM_SETFONTSIZE(richedit, 1, 72, TRUE, TRUE); /* 48 + 1 -> 72 */
8730 TEST_EM_SETFONTSIZE(richedit, 0, 72, TRUE, TRUE); /* 72 + 0 -> 72 */
8731 TEST_EM_SETFONTSIZE(richedit, 1, 80, TRUE, TRUE); /* 72 + 1 -> 80 */
8732 TEST_EM_SETFONTSIZE(richedit, 0, 80, TRUE, TRUE); /* 80 + 0 -> 80 */
8733 TEST_EM_SETFONTSIZE(richedit, 1, 90, TRUE, TRUE); /* 80 + 1 -> 90 */
8734 TEST_EM_SETFONTSIZE(richedit, 0, 90, TRUE, TRUE); /* 90 + 0 -> 90 */
8735 TEST_EM_SETFONTSIZE(richedit, 1, 100, TRUE, TRUE); /* 90 + 1 -> 100 */
8736 TEST_EM_SETFONTSIZE(richedit, 25, 130, TRUE, TRUE); /* 100 + 25 -> 130 */
8737 TEST_EM_SETFONTSIZE(richedit, -1, 120, TRUE, TRUE); /* 130 - 1 -> 120 */
8738 TEST_EM_SETFONTSIZE(richedit, -35, 80, TRUE, TRUE); /* 120 - 35 -> 80 */
8739 TEST_EM_SETFONTSIZE(richedit, -7, 72, TRUE, TRUE); /* 80 - 7 -> 72 */
8740 TEST_EM_SETFONTSIZE(richedit, -42, 28, TRUE, TRUE); /* 72 - 42 -> 28 */
8741 TEST_EM_SETFONTSIZE(richedit, -16, 12, TRUE, TRUE); /* 28 - 16 -> 12 */
8742 TEST_EM_SETFONTSIZE(richedit, -3, 9, TRUE, TRUE); /* 12 - 3 -> 9 */
8743 TEST_EM_SETFONTSIZE(richedit, -8, 1, TRUE, TRUE); /* 9 - 8 -> 1 */
8744 TEST_EM_SETFONTSIZE(richedit, -111, 1, TRUE, TRUE); /* 1 - 111 -> 1 */
8745 TEST_EM_SETFONTSIZE(richedit, 10086, 1638, TRUE, TRUE); /* 1 + 10086 -> 1638 */
8746
8747 /* return FALSE when richedit is TM_PLAINTEXT mode */
8748 SendMessageA(richedit, WM_SETTEXT, 0, (LPARAM)"");
8750 TEST_EM_SETFONTSIZE(richedit, 0, 9, FALSE, FALSE);
8751
8752 DestroyWindow(richedit);
8753}
8754
8755static void test_alignment_style(void)
8756{
8757 HWND richedit = NULL;
8758 PARAFORMAT2 pf;
8759 DWORD align_style[] = {ES_LEFT, ES_CENTER, ES_RIGHT, ES_RIGHT | ES_CENTER,
8764 const char * streamtext =
8765 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n"
8766 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n"
8767 "}\r\n";
8768 EDITSTREAM es;
8769 int i;
8770
8771 for (i = 0; i < ARRAY_SIZE(align_style); i++)
8772 {
8773 DWORD dwStyle, new_align;
8774
8775 richedit = new_windowW(RICHEDIT_CLASS20W, align_style[i], NULL);
8776 memset(&pf, 0, sizeof(pf));
8777 pf.cbSize = sizeof(PARAFORMAT2);
8778 pf.dwMask = -1;
8779
8780 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
8781 ok(pf.wAlignment == align_mask[i], "(i = %d) got %d expected %ld\n",
8782 i, pf.wAlignment, align_mask[i]);
8783 dwStyle = GetWindowLongW(richedit, GWL_STYLE);
8784 ok((i ? (dwStyle & align_style[i]) : (!(dwStyle & 0x0000000f))) ,
8785 "(i = %d) didn't set right align style: 0x%lx\n", i, dwStyle);
8786
8787
8788 /* Based on test_reset_default_para_fmt() */
8789 new_align = (align_mask[i] == PFA_LEFT) ? PFA_RIGHT : PFA_LEFT;
8790 simulate_typing_characters(richedit, "123");
8791
8792 SendMessageW(richedit, EM_SETSEL, 0, -1);
8793 pf.dwMask = PFM_ALIGNMENT;
8794 pf.wAlignment = new_align;
8795 SendMessageW(richedit, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
8796
8797 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
8798 ok(pf.wAlignment == new_align, "got %d expect %ld\n", pf.wAlignment, new_align);
8799
8800 SendMessageW(richedit, EM_SETSEL, 0, -1);
8801 SendMessageW(richedit, WM_CUT, 0, 0);
8802
8803 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
8804 ok(pf.wAlignment == align_mask[i], "got %d expect %ld\n", pf.wAlignment, align_mask[i]);
8805
8806 /* Test out of bounds tab count */
8807 pf.dwMask = PFM_TABSTOPS;
8808 pf.cTabCount = -25000;
8809 SendMessageW(richedit, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
8810 ok(pf.cTabCount == -25000, "Got %d\n", pf.cTabCount);
8811 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
8812 ok(pf.cTabCount == 0, "Got %d\n", pf.cTabCount);
8813 pf.dwMask = PFM_TABSTOPS;
8814 pf.cTabCount = 25000;
8815 SendMessageW(richedit, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
8816 ok(pf.cTabCount == 25000, "Got %d\n", pf.cTabCount);
8817 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
8818 ok(pf.cTabCount == 32, "Got %d\n", pf.cTabCount);
8819 pf.dwMask = PFM_TABSTOPS;
8820 pf.cTabCount = 32;
8821 SendMessageW(richedit, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
8822 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
8823 ok(pf.cTabCount == 32, "Got %d\n", pf.cTabCount);
8824 pf.dwMask = PFM_TABSTOPS;
8825 pf.cTabCount = 33;
8826 SendMessageW(richedit, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
8827 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
8828 ok(pf.cTabCount == 32, "Got %d\n", pf.cTabCount);
8829 pf.dwMask = PFM_TABSTOPS;
8830 pf.cTabCount = 1;
8831 SendMessageW(richedit, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
8832 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
8833 ok(pf.cTabCount == 1, "Got %d\n", pf.cTabCount);
8834
8835 DestroyWindow(richedit);
8836 }
8837
8838 /* test with EM_STREAMIN */
8840 simulate_typing_characters(richedit, "abc");
8841 es.dwCookie = (DWORD_PTR)&streamtext;
8842 es.dwError = 0;
8843 es.pfnCallback = test_EM_STREAMIN_esCallback;
8844 SendMessageW(richedit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
8845 SendMessageW(richedit, EM_SETSEL, 0, -1);
8846 memset(&pf, 0, sizeof(pf));
8847 pf.cbSize = sizeof(PARAFORMAT2);
8848 pf.dwMask = -1;
8850 ok(pf.wAlignment == PFA_LEFT, "got %d expected PFA_LEFT\n", pf.wAlignment);
8851 DestroyWindow(richedit);
8852}
8853
8854static void test_WM_GETTEXTLENGTH(void)
8855{
8856 HWND hwndRichEdit = new_richedit(NULL);
8857 static const char text1[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee";
8858 static const char text2[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee\r\n";
8859 static const char text3[] = "abcdef\x8e\xf0";
8860 int result;
8861
8862 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
8863 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
8864 ok(result == lstrlenA(text1), "WM_GETTEXTLENGTH returned %d, expected %d\n",
8865 result, lstrlenA(text1));
8866
8867 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
8868 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
8869 ok(result == lstrlenA(text2), "WM_GETTEXTLENGTH returned %d, expected %d\n",
8870 result, lstrlenA(text2));
8871
8872 /* Test with multibyte character */
8873 if (!is_lang_japanese)
8874 skip("Skip multibyte character tests on non-Japanese platform\n");
8875 else
8876 {
8877 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text3);
8878 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
8879 todo_wine ok(result == 8, "WM_GETTEXTLENGTH returned %d, expected 8\n", result);
8880 }
8881
8882 DestroyWindow(hwndRichEdit);
8883}
8884
8885static void test_rtf(void)
8886{
8887 const char *specials = "{\\rtf1\\emspace\\enspace\\bullet\\lquote"
8888 "\\rquote\\ldblquote\\rdblquote\\ltrmark\\rtlmark\\zwj\\zwnj}";
8889 const WCHAR expect_specials[] = {' ',' ',0x2022,0x2018,0x2019,0x201c,
8890 0x201d,0x200e,0x200f,0x200d,0x200c};
8891 const char *pard = "{\\rtf1 ABC\\rtlpar\\par DEF\\par HIJ\\pard\\par}";
8892 const char *highlight = "{\\rtf1{\\colortbl;\\red0\\green0\\blue0;\\red128\\green128\\blue128;\\red192\\green192\\blue192;}\\cf2\\highlight3 foo\\par}";
8893 const char *crash = "{\\rtf2 {\\par \\pard \\trowd \\cellx6000 \\intbl \\cell \\row \\par \\pard \\li300 \\bullet packages... \\par }";
8894 const char *crash2 = "{\\rtf1 \\trowd row1 \\intbl \\cell \\row \\par \\trowd row2 \\intbl \\cell \\row}";
8895
8896 HWND edit = new_richeditW( NULL );
8897 EDITSTREAM es;
8898 WCHAR buf[80];
8902
8903 /* Test rtf specials */
8904 es.dwCookie = (DWORD_PTR)&specials;
8905 es.dwError = 0;
8906 es.pfnCallback = test_EM_STREAMIN_esCallback;
8908 ok( result == 11, "got %Id\n", result );
8909
8911 ok( result == ARRAY_SIZE(expect_specials), "got %Id\n", result );
8912 ok( !memcmp( buf, expect_specials, sizeof(expect_specials) ), "got %s\n", wine_dbgstr_w(buf) );
8913
8914 /* Show that \rtlpar propagates to the second paragraph and is
8915 reset by \pard in the third. */
8916 es.dwCookie = (DWORD_PTR)&pard;
8918 ok( result == 11, "got %Id\n", result );
8919
8920 fmt.cbSize = sizeof(fmt);
8921 SendMessageW( edit, EM_SETSEL, 1, 1 );
8922 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt );
8923 ok( fmt.dwMask & PFM_RTLPARA, "rtl para mask not set\n" );
8924 ok( fmt.wEffects & PFE_RTLPARA, "rtl para not set\n" );
8925 SendMessageW( edit, EM_SETSEL, 5, 5 );
8926 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt );
8927 ok( fmt.dwMask & PFM_RTLPARA, "rtl para mask not set\n" );
8928 ok( fmt.wEffects & PFE_RTLPARA, "rtl para not set\n" );
8929 SendMessageW( edit, EM_SETSEL, 9, 9 );
8930 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt );
8931 ok( fmt.dwMask & PFM_RTLPARA, "rtl para mask not set\n" );
8932 ok( !(fmt.wEffects & PFE_RTLPARA), "rtl para set\n" );
8933
8934 /* Test \highlight */
8935 es.dwCookie = (DWORD_PTR)&highlight;
8937 ok( result == 3, "got %Id\n", result );
8938 SendMessageW( edit, EM_SETSEL, 1, 1 );
8939 memset( &cf, 0, sizeof(cf) );
8940 cf.cbSize = sizeof(cf);
8942 ok( (cf.dwEffects & (CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR)) == 0, "got %08lx\n", cf.dwEffects );
8943 ok( cf.crTextColor == RGB(128,128,128), "got %08lx\n", cf.crTextColor );
8944 ok( cf.crBackColor == RGB(192,192,192), "got %08lx\n", cf.crBackColor );
8945
8946 /* Test cases that crash */
8947 es.dwCookie = (DWORD_PTR)&crash;
8948 es.dwError = 0;
8950
8951 es.dwCookie = (DWORD_PTR)&crash2;
8952 es.dwError = 0;
8954
8955 DestroyWindow( edit );
8956}
8957
8958static void test_background(void)
8959{
8960 HWND hwndRichEdit = new_richedit(NULL);
8961
8962 /* set the background color to black */
8963 ValidateRect(hwndRichEdit, NULL);
8964 SendMessageA(hwndRichEdit, EM_SETBKGNDCOLOR, FALSE, RGB(0, 0, 0));
8965 ok(GetUpdateRect(hwndRichEdit, NULL, FALSE), "Update rectangle is empty!\n");
8966
8967 DestroyWindow(hwndRichEdit);
8968}
8969
8970static void test_eop_char_fmt(void)
8971{
8972 HWND edit = new_richedit( NULL );
8973 const char *rtf = "{\\rtf1{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 Arial;}{\\f1\\fnil\\fcharset2 Symbol;}}"
8974 "{\\fs10{\\pard\\fs16\\fi200\\li360\\f0 First\\par"
8975 "\\f0\\fs25 Second\\par"
8976 "{\\f0\\fs26 Third}\\par"
8977 "{\\f0\\fs22 Fourth}\\par}}}";
8978 EDITSTREAM es;
8980 int i, num, expect_height;
8981
8982 es.dwCookie = (DWORD_PTR)&rtf;
8983 es.dwError = 0;
8984 es.pfnCallback = test_EM_STREAMIN_esCallback;
8985 num = SendMessageA( edit, EM_STREAMIN, SF_RTF, (LPARAM)&es );
8986 ok( num == 25, "got %d\n", num );
8987
8988 for (i = 0; i <= num; i++)
8989 {
8990 SendMessageW( edit, EM_SETSEL, i, i + 1 );
8991 cf.cbSize = sizeof(cf);
8992 cf.dwMask = CFM_SIZE;
8994 ok( cf.dwMask & CFM_SIZE, "%d: got %08lx\n", i, cf.dwMask );
8995 if (i < 6) expect_height = 160;
8996 else if (i < 13) expect_height = 250;
8997 else if (i < 18) expect_height = 260;
8998 else if (i == 18 || i == 25) expect_height = 250;
8999 else expect_height = 220;
9000 ok( cf.yHeight == expect_height, "%d: got %ld\n", i, cf.yHeight );
9001 }
9002
9003 DestroyWindow( edit );
9004}
9005
9006static void test_para_numbering(void)
9007{
9008 HWND edit = new_richeditW( NULL );
9009 const char *numbers = "{\\rtf1{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 Arial;}{\\f1\\fnil\\fcharset2 Symbol;}}"
9010 "\\pard{\\pntext\\f0 3.\\tab}{\\*\\pn\\pnlvlbody\\pnfs32\\pnf0\\pnindent1000\\pnstart2\\pndec{\\pntxta.}}"
9011 "\\fs20\\fi200\\li360\\f0 First\\par"
9012 "{\\pntext\\f0 4.\\tab}\\f0 Second\\par"
9013 "{\\pntext\\f0 6.\\tab}\\f0 Third\\par}";
9014 const WCHAR expect_numbers_txt[] = {'F','i','r','s','t','\r','S','e','c','o','n','d','\r','T','h','i','r','d',0};
9015 EDITSTREAM es;
9016 WCHAR buf[80];
9018 PARAFORMAT2 fmt, fmt2;
9021
9022 get_text.cb = sizeof(buf);
9023 get_text.flags = GT_RAWTEXT;
9024 get_text.codepage = 1200;
9025 get_text.lpDefaultChar = NULL;
9026 get_text.lpUsedDefChar = NULL;
9027
9028 es.dwCookie = (DWORD_PTR)&numbers;
9029 es.dwError = 0;
9030 es.pfnCallback = test_EM_STREAMIN_esCallback;
9032 ok( result == lstrlenW( expect_numbers_txt ), "got %Id\n", result );
9033
9035 ok( result == lstrlenW( expect_numbers_txt ), "got %Id\n", result );
9036 ok( !lstrcmpW( buf, expect_numbers_txt ), "got %s\n", wine_dbgstr_w(buf) );
9037
9038 SendMessageW( edit, EM_SETSEL, 1, 1 );
9039 memset( &fmt, 0, sizeof(fmt) );
9040 fmt.cbSize = sizeof(fmt);
9041 fmt.dwMask = PFM_ALL2;
9042 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt );
9043 ok( fmt.wNumbering == PFN_ARABIC, "got %d\n", fmt.wNumbering );
9044 ok( fmt.wNumberingStart == 2, "got %d\n", fmt.wNumberingStart );
9045 ok( fmt.wNumberingStyle == PFNS_PERIOD, "got %04x\n", fmt.wNumberingStyle );
9046 ok( fmt.wNumberingTab == 1000, "got %d\n", fmt.wNumberingTab );
9047 ok( fmt.dxStartIndent == 560, "got %ld\n", fmt.dxStartIndent );
9048 ok( fmt.dxOffset == -200, "got %ld\n", fmt.dxOffset );
9049
9050 /* Second para should have identical fmt */
9051 SendMessageW( edit, EM_SETSEL, 10, 10 );
9052 memset( &fmt2, 0, sizeof(fmt2) );
9053 fmt2.cbSize = sizeof(fmt2);
9054 fmt2.dwMask = PFM_ALL2;
9055 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt2 );
9056 ok( !memcmp( &fmt, &fmt2, sizeof(fmt) ), "format mismatch\n" );
9057
9058 /* Check the eop heights - this determines the label height */
9059 SendMessageW( edit, EM_SETSEL, 12, 13 );
9060 cf.cbSize = sizeof(cf);
9061 cf.dwMask = CFM_SIZE;
9063 ok( cf.yHeight == 200, "got %ld\n", cf.yHeight );
9064
9065 SendMessageW( edit, EM_SETSEL, 18, 19 );
9066 cf.cbSize = sizeof(cf);
9067 cf.dwMask = CFM_SIZE;
9069 ok( cf.yHeight == 200, "got %ld\n", cf.yHeight );
9070
9071 DestroyWindow( edit );
9072}
9073
9074static void fill_reobject_struct(REOBJECT *reobj, LONG cp, LPOLEOBJECT poleobj,
9075 LPSTORAGE pstg, LPOLECLIENTSITE polesite, LONG sizel_cx,
9076 LONG sizel_cy, DWORD aspect, DWORD flags, DWORD user)
9077{
9078 reobj->cbStruct = sizeof(*reobj);
9079 reobj->clsid = CLSID_NULL;
9080 reobj->cp = cp;
9081 reobj->poleobj = poleobj;
9082 reobj->pstg = pstg;
9083 reobj->polesite = polesite;
9084 reobj->sizel.cx = sizel_cx;
9085 reobj->sizel.cy = sizel_cy;
9086 reobj->dvaspect = aspect;
9087 reobj->dwFlags = flags;
9088 reobj->dwUser = user;
9089}
9090
9092
9094{
9095 if (message == WM_COMMAND && (wParam >> 16) == EN_CHANGE) change_received = TRUE;
9097}
9098
9100{
9101 if (message == WM_CREATE)
9103 return CallWindowProcA(richeditProc, hwnd, message, wParam, lParam);
9104}
9105
9106static void test_init_messages(void)
9107{
9108 WNDCLASSA cls;
9109 HWND parent, edit;
9110
9111 /* register class to capture EN_CHANGE */
9112 cls = make_simple_class(ChangeWatcherWndProc, "ChangeWatcherClass");
9113 if (!RegisterClassA(&cls)) assert(0);
9114
9115 /* and a class that sets ENM_CHANGE during WM_CREATE */
9116 if (!GetClassInfoA(hmoduleRichEdit, RICHEDIT_CLASS20A, &cls)) return;
9117 richeditProc = cls.lpfnWndProc;
9119 cls.lpszClassName = "RichEditWithEvents";
9120 if (!RegisterClassA(&cls)) assert(0);
9121
9122 parent = CreateWindowA("ChangeWatcherClass", NULL, WS_POPUP|WS_VISIBLE,
9123 0, 0, 200, 60, NULL, NULL, NULL, NULL);
9124 ok(parent != 0, "Failed to create parent window\n");
9126 edit = new_window("RichEditWithEvents", 0, parent);
9127 ok(change_received == FALSE, "Creating a RichEdit should not make any EN_CHANGE events\n");
9128 DestroyWindow(edit);
9130}
9131
9132static void test_EM_SELECTIONTYPE(void)
9133{
9135 IRichEditOle *reole = NULL;
9136 static const char text1[] = "abcdefg\n";
9137 int result;
9138 REOBJECT reo1, reo2;
9139 IOleClientSite *clientsite;
9140 HRESULT hr;
9141
9142 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)text1);
9144
9145 SendMessageA(hwnd, EM_SETSEL, 1, 1);
9147 ok(result == SEL_EMPTY, "got wrong selection type: %x.\n", result);
9148
9149 SendMessageA(hwnd, EM_SETSEL, 1, 2);
9151 ok(result == SEL_TEXT, "got wrong selection type: %x.\n", result);
9152
9153 SendMessageA(hwnd, EM_SETSEL, 2, 5);
9155 ok(result == (SEL_TEXT | SEL_MULTICHAR), "got wrong selection type: %x.\n", result);
9156
9157 SendMessageA(hwnd, EM_SETSEL, 0, 1);
9158 hr = IRichEditOle_GetClientSite(reole, &clientsite);
9159 ok(hr == S_OK, "IRichEditOle_GetClientSite failed: 0x%08lx\n", hr);
9160 fill_reobject_struct(&reo1, REO_CP_SELECTION, NULL, NULL, clientsite, 10, 10,
9161 DVASPECT_CONTENT, 0, 1);
9162 hr = IRichEditOle_InsertObject(reole, &reo1);
9163 ok(hr == S_OK, "IRichEditOle_InsertObject failed: 0x%08lx\n", hr);
9164 IOleClientSite_Release(clientsite);
9165
9166 SendMessageA(hwnd, EM_SETSEL, 0, 1);
9168 ok(result == SEL_OBJECT, "got wrong selection type: %x.\n", result);
9169
9170 SendMessageA(hwnd, EM_SETSEL, 0, 2);
9172 ok(result == (SEL_TEXT | SEL_OBJECT), "got wrong selection type: %x.\n", result);
9173
9174 SendMessageA(hwnd, EM_SETSEL, 0, 3);
9176 ok(result == (SEL_TEXT | SEL_MULTICHAR | SEL_OBJECT), "got wrong selection type: %x.\n", result);
9177
9178 SendMessageA(hwnd, EM_SETSEL, 2, 3);
9179 hr = IRichEditOle_GetClientSite(reole, &clientsite);
9180 ok(hr == S_OK, "IRichEditOle_GetClientSite failed: 0x%08lx\n", hr);
9181 fill_reobject_struct(&reo2, REO_CP_SELECTION, NULL, NULL, clientsite, 10, 10,
9182 DVASPECT_CONTENT, 0, 2);
9183 hr = IRichEditOle_InsertObject(reole, &reo2);
9184 ok(hr == S_OK, "IRichEditOle_InsertObject failed: 0x%08lx\n", hr);
9185 IOleClientSite_Release(clientsite);
9186
9187 SendMessageA(hwnd, EM_SETSEL, 0, 2);
9189 ok(result == (SEL_OBJECT | SEL_TEXT), "got wrong selection type: %x.\n", result);
9190
9191 SendMessageA(hwnd, EM_SETSEL, 0, 3);
9193 ok(result == (SEL_OBJECT | SEL_MULTIOBJECT | SEL_TEXT), "got wrong selection type: %x.\n", result);
9194
9195 SendMessageA(hwnd, EM_SETSEL, 0, 4);
9197 ok(result == (SEL_TEXT| SEL_MULTICHAR | SEL_OBJECT | SEL_MULTIOBJECT), "got wrong selection type: %x.\n", result);
9198
9199 IRichEditOle_Release(reole);
9201}
9202
9203static void test_window_classes(void)
9204{
9205 static const struct
9206 {
9207 const char *class;
9208 BOOL success;
9209 } test[] =
9210 {
9211 { "RichEdit", FALSE },
9212 { "RichEdit20A", TRUE },
9213 { "RichEdit20W", TRUE },
9214 { "RichEdit50A", FALSE },
9215 { "RichEdit50W", FALSE }
9216 };
9217 int i;
9218 HWND hwnd;
9219
9220 for (i = 0; i < ARRAY_SIZE(test); i++)
9221 {
9222 SetLastError(0xdeadbeef);
9223 hwnd = CreateWindowExA(0, test[i].class, NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL);
9224todo_wine_if(!strcmp(test[i].class, "RichEdit50A") || !strcmp(test[i].class, "RichEdit50W"))
9225 ok(!hwnd == !test[i].success, "CreateWindow(%s) should %s\n",
9226 test[i].class, test[i].success ? "succeed" : "fail");
9227 if (!hwnd)
9230 else
9232 }
9233}
9234
9235START_TEST( editor )
9236{
9237 BOOL ret;
9238 /* Must explicitly LoadLibrary(). The test has no reference to functions in
9239 * RICHED20.DLL, so the linker does not actually link to it. */
9240 hmoduleRichEdit = LoadLibraryA("riched20.dll");
9241 ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError());
9243
9245 test_WM_CHAR();
9272 test_WM_PASTE();
9285 test_EN_LINK();
9297 test_zoom();
9301 test_enter();
9307 test_rtf();
9313
9314 /* Set the environment variable WINETEST_RICHED20 to keep windows
9315 * responsive and open for 30 seconds. This is useful for debugging.
9316 */
9317 if (getenv( "WINETEST_RICHED20" )) {
9318 keep_responsive(30);
9319 }
9320
9323 ok(ret, "error: %d\n", (int) GetLastError());
9324}
DWORD Id
BOOLEAN Expected
static struct _test_info results[8]
Definition: SetCursorPos.c:31
#define expect(EXPECTED, GOT)
Definition: SystemMenu.c:483
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 * 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 broken(x)
Definition: atltest.h:178
#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
#define CF_TEXT
Definition: constants.h:396
void user(int argc, const char *argv[])
Definition: cmds.c:1350
void get(int argc, const char *argv[])
Definition: cmds.c:480
int null(void)
Definition: ftp.c:1794
#define ARRAY_SIZE(A)
Definition: main.h:20
while(CdLookupNextInitialFileDirent(IrpContext, Fcb, FileContext))
Definition: terminate.cpp:24
Definition: _set.h:50
static LPSTR * split(LPSTR s, LPINT args)
Definition: cmdcons.c:163
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
int selection
Definition: ctm.c:92
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 Z(I)
#define Y(I)
#define A(row, col)
static WCHAR no[MAX_STRING_RESOURCE_LEN]
Definition: object.c:2340
static const WCHAR empty[]
Definition: main.c:47
#define GetProcessHeap()
Definition: compat.h:736
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define CP_ACP
Definition: compat.h:109
#define SetLastError(x)
Definition: compat.h:752
#define GetProcAddress(x, y)
Definition: compat.h:753
#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 MultiByteToWideChar
Definition: compat.h:110
#define ERROR_ACCESS_DENIED
Definition: compat.h:97
#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
LANGID WINAPI GetSystemDefaultLangID(void)
Definition: locale.c:1194
int WINAPI lstrcmpW(LPCWSTR str1, LPCWSTR str2)
Definition: locale.c:4243
INT WINAPI GetLocaleInfoA(LCID lcid, LCTYPE lctype, LPSTR buffer, INT len)
Definition: locale.c:1600
int WINAPI lstrcmpA(LPCSTR str1, LPCSTR str2)
Definition: locale.c:4195
LCID WINAPI GetSystemDefaultLCID(void)
Definition: locale.c:1230
ULONG WINAPI DECLSPEC_HOTPATCH GetTickCount(void)
Definition: sync.c:182
const WCHAR * text
Definition: package.c:1794
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:71
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
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
const GLdouble * v
Definition: gl.h:2040
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLdouble s
Definition: gl.h:2039
GLuint GLuint end
Definition: gl.h:1545
GLint GLint GLsizei GLsizei height
Definition: gl.h:1546
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLdouble GLdouble t
Definition: gl.h:2047
GLdouble n
Definition: glext.h:7729
GLuint res
Definition: glext.h:9613
GLenum src
Definition: glext.h:6340
GLsizei const GLchar *const * strings
Definition: glext.h:7622
GLuint buffer
Definition: glext.h:5915
GLsizeiptr size
Definition: glext.h:5919
const GLubyte * c
Definition: glext.h:8905
GLfloat f
Definition: glext.h:7540
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
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
GLint GLint bottom
Definition: glext.h:7726
GLuint64EXT * result
Definition: glext.h:11304
GLfloat GLfloat p
Definition: glext.h:8902
GLuint GLuint num
Definition: glext.h:9618
GLenum GLsizei len
Definition: glext.h:6722
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
GLbyte by
Definition: glext.h:8766
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
LPVOID NTAPI GlobalLock(HGLOBAL hMem)
Definition: heapmem.c:755
BOOL NTAPI GlobalUnlock(HGLOBAL hMem)
Definition: heapmem.c:1190
static const WCHAR titleW[]
Definition: htmlelem.c:1067
#define es
Definition: i386-dis.c:440
const char cursor[]
Definition: icontest.c:13
static double two
Definition: jn_yn.c:52
_Check_return_ char *__cdecl getenv(_In_z_ const char *_VarName)
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define d
Definition: ke_i.h:81
#define c
Definition: ke_i.h:80
#define wine_dbgstr_w
Definition: kernel32.h:34
#define trace_(file, line,...)
Definition: kmt_test.h:224
int WINAPI lstrlenA(LPCSTR lpString)
Definition: lstring.c:145
POINT cp
Definition: magnifier.c:59
__u16 time
Definition: mkdosfs.c:8
#define error(str)
Definition: mkdosfs.c:1605
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
char string[160]
Definition: util.h:11
static struct test_info tests[]
#define sprintf(buf, format,...)
Definition: sprintf.c:55
UCHAR ab[sizeof("Hello World!") -1]
Definition: fdi.c:106
static BOOL rtl
Definition: propsheet.c:36
static const WCHAR textW[]
Definition: itemdlg.c:1559
static const BYTE wine[]
Definition: encode.c:696
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:86
#define todo_wine
Definition: custom.c:89
static const struct access_res create[16]
Definition: package.c:7505
static char * dest
Definition: rtl.c:135
static unsigned int recursionLevel
Definition: editor.c:2972
static struct dialog_mode_messages dm_messages
Definition: editor.c:8056
static void test_EM_SELECTIONTYPE(void)
Definition: editor.c:9132
static void test_EM_FORMATRANGE(void)
Definition: editor.c:5726
static CHAR string2[MAX_PATH]
Definition: editor.c:44
static LRESULT WINAPI WM_NOTIFY_ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
Definition: editor.c:6764
static void test_SETPARAFORMAT(void)
Definition: editor.c:1592
static void simulate_typing_characters(HWND hwnd, const char *szChars)
Definition: editor.c:149
static LRESULT WINAPI EN_LINK_ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
Definition: editor.c:6866
static LRESULT CALLBACK dialog_mode_wnd_proc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
Definition: editor.c:8066
static void test_WM_PASTE(void)
Definition: editor.c:5590
static void test_EM_EXSETSEL(void)
Definition: editor.c:5090
static void test_EM_GETSELTEXT(void)
Definition: editor.c:1887
static void check_CFE_LINK_rcvd(HWND hwnd, BOOL is_url, const char *url)
Definition: editor.c:2029
static void test_word_movement_multiline(void)
Definition: editor.c:7297
static void test_WM_GETTEXT(void)
Definition: editor.c:1736
#define CURSOR_CLIENT_Y
Definition: editor.c:6862
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:9074
static void test_EM_StreamIn_Undo(void)
Definition: editor.c:6235
#define test_dm_messages(wmclose, wmgetdefid, wmnextdlgctl)
Definition: editor.c:8058
static void test_EM_SETOPTIONS(void)
Definition: editor.c:1947
static UINT message
Definition: editor.c:2975
static HWND new_richeditW(HWND parent)
Definition: editor.c:109
static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
Definition: editor.c:6680
static void test_EM_FINDWORDBREAK_W(void)
Definition: editor.c:8366
static void test_WM_SETFONT(void)
Definition: editor.c:4734
static void check_EM_SETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id)
Definition: editor.c:5129
#define WP_PARENT
Definition: editor.c:6863
LONG streamout_written
Definition: editor.c:3774
static HMODULE hmoduleRichEdit
Definition: editor.c:53
#define ID_RICHEDITTESTDBUTTON
Definition: editor.c:42
static void test_undo_coalescing(void)
Definition: editor.c:7053
#define TEST_SETTEXTW(a, b)
static void test_EM_GETTEXTLENGTHEX(void)
Definition: editor.c:6524
static void format_test_result(char *target, const char *src)
Definition: editor.c:8443
static HWND new_richedit(HWND parent)
Definition: editor.c:101
#define send_paste(a)
Definition: editor.c:1417
static LRESULT WINAPI ChangeWatcherWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
Definition: editor.c:9093
static BOOL change_received
Definition: editor.c:9091
static void test_EM_STREAMOUT_FONTTBL(void)
Definition: editor.c:4021
static void test_EM_GETLINE(void)
Definition: editor.c:435
#define DISABLE_WS_VSCROLL(hwnd)
static void test_WM_GETTEXTLENGTH(void)
Definition: editor.c:8854
static void test_EM_SCROLL(void)
Definition: editor.c:2838
static HWND new_windowW(LPCWSTR lpClassName, DWORD dwStyle, HWND parent)
Definition: editor.c:91
static unsigned int WM_SIZE_recursionLevel
Definition: editor.c:2973
static DWORD CALLBACK test_EM_STREAMIN_esCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
Definition: editor.c:5870
static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *find, int num_tests, BOOL unicode)
Definition: editor.c:366
static void move_cursor(HWND hwnd, LONG charindex)
Definition: editor.c:571
static WCHAR * atowstr(const char *str)
Definition: editor.c:274
static void test_EM_GETLIMITTEXT(void)
Definition: editor.c:4719
static const struct exsetsel_s exsetsel_tests[]
Definition: editor.c:5043
static void test_EN_LINK(void)
Definition: editor.c:6937
static void test_unicode_conversions(void)
Definition: editor.c:6314
static void test_EM_STREAMIN(void)
Definition: editor.c:5960
static void check_EM_EXSETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id)
Definition: editor.c:5072
static BOOL check_CFE_LINK_selection(HWND hwnd, int sel_start, int sel_end)
Definition: editor.c:2020
static void test_EM_STREAMOUT(void)
Definition: editor.c:3919
static BOOL hold_key(int vk)
Definition: editor.c:162
static void test_EM_AUTOURLDETECT(void)
Definition: editor.c:2048
static void test_EM_REPLACESEL(int redraw)
Definition: editor.c:5206
static LRESULT send_ctrl_key(HWND hwnd, UINT key)
Definition: editor.c:5581
static int received_WM_NOTIFY
Definition: editor.c:6759
#define ok_w3(format, szString1, szString2, szString3)
Definition: editor.c:46
static WNDCLASSA make_simple_class(WNDPROC wndproc, LPCSTR lpClassName)
Definition: editor.c:113
static HWND new_richedit_with_style(HWND parent, DWORD style)
Definition: editor.c:105
static DWORD CALLBACK test_esCallback_written_1(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
Definition: editor.c:3890
static void test_WM_CREATE(void)
Definition: editor.c:8569
static void test_WM_SETTEXT(void)
Definition: editor.c:3791
static void test_EM_SETCHARFORMAT(void)
Definition: editor.c:795
static int queriedEventMask
Definition: editor.c:6676
static void test_background(void)
Definition: editor.c:8958
static BOOL is_lang_japanese
Definition: editor.c:54
static void _send_paste(unsigned int line, HWND wnd)
Definition: editor.c:1418
static void test_dialogmode(void)
Definition: editor.c:8084
static BOOL filter_on_WM_NOTIFY
Definition: editor.c:6761
static struct find_s find_tests2[]
Definition: editor.c:211
static void test_EM_SETTEXTMODE(void)
Definition: editor.c:1446
static void test_format_rect(void)
Definition: editor.c:7552
static HWND hwndRichedit_WM_NOTIFY
Definition: editor.c:6762
static LRESULT WINAPI RicheditStupidOverrideProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
Definition: editor.c:2977
static void test_init_messages(void)
Definition: editor.c:9106
static void test_eventMask(void)
Definition: editor.c:6690
static BOOL open_clipboard_(int line, HWND hwnd)
Definition: editor.c:4817
static void test_EM_LINELENGTH(void)
Definition: editor.c:507
static struct find_s find_tests[]
Definition: editor.c:202
static void test_scrollbar_visibility(void)
Definition: editor.c:3004
static CHAR string1[MAX_PATH]
Definition: editor.c:44
static void keep_responsive(time_t delay_time)
Definition: editor.c:131
static void test_EM_CHARFROMPOS(void)
Definition: editor.c:7342
#define CURSOR_CLIENT_X
Definition: editor.c:6861
static HWND eventMaskEditHwnd
Definition: editor.c:6675
static BOOL release_key(int vk)
Definition: editor.c:176
static void test_EM_SETFONTSIZE(void)
Definition: editor.c:8688
static DWORD CALLBACK test_EM_GETMODIFY_esCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
Definition: editor.c:4796
static void test_EM_SETSEL(void)
Definition: editor.c:5161
static void line_scroll(HWND hwnd, int amount)
Definition: editor.c:579
static int modify_at_WM_NOTIFY
Definition: editor.c:6760
static void test_rtf(void)
Definition: editor.c:8885
#define MAX_BUF_LEN
static void check_EM_SETSEL_multiline(HWND hwnd)
Definition: editor.c:5145
static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id, BOOL unicode)
Definition: editor.c:284
static void test_WM_GETDLGCODE(void)
Definition: editor.c:7728
static void test_EM_SCROLLCARET(void)
Definition: editor.c:584
static ENLINK enlink
Definition: editor.c:6860
static int get_scroll_pos_y(HWND hwnd)
Definition: editor.c:563
static void test_EM_SETUNDOLIMIT(void)
Definition: editor.c:3684
static CHAR string3[MAX_PATH]
Definition: editor.c:44
static void test_EM_STREAMOUT_empty_para(void)
Definition: editor.c:4074
#define WP_CHILD
Definition: editor.c:6864
static void test_EM_LIMITTEXT(void)
Definition: editor.c:4548
static void test_autoscroll(void)
Definition: editor.c:7493
static void check_EM_FINDTEXTEX(HWND hwnd, const char *name, struct find_s *f, int id, BOOL unicode)
Definition: editor.c:320
#define open_clipboard(hwnd)
Definition: editor.c:4816
static void test_word_wrap(void)
Definition: editor.c:7397
static void test_enter(void)
Definition: editor.c:8459
#define TEST_SETTEXT(a, b)
static void test_EM_FINDWORDBREAK_A(void)
Definition: editor.c:8410
static LONG CALLBACK customWordBreakProc(WCHAR *text, int pos, int bytes, int code)
Definition: editor.c:7171
static void test_reset_default_para_fmt(void)
Definition: editor.c:8610
static void test_window_classes(void)
Definition: editor.c:9203
static LRESULT WINAPI RichEditWithEventsWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
Definition: editor.c:9099
static DWORD CALLBACK test_WM_SETTEXT_esCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
Definition: editor.c:3776
static LONG twips2points(LONG value)
Definition: editor.c:8661
#define ENABLE_WS_VSCROLL(hwnd)
#define ITextServices_OnTxPropertyBitsChange(This, a, b)
Definition: editor.c:62
static int count_pars(const char *buf)
Definition: editor.c:3906
static void test_EM_POSFROMCHAR(void)
Definition: editor.c:642
static void test_zoom(void)
Definition: editor.c:7909
static int watchForEventMask
Definition: editor.c:6677
static HWND new_static_wnd(HWND parent)
Definition: editor.c:2044
static HWND new_window(LPCSTR lpClassName, DWORD dwStyle, HWND parent)
Definition: editor.c:81
static void test_ES_PASSWORD(void)
Definition: editor.c:3748
static const struct getline_s gl[]
static void test_EM_EXLIMITTEXT(void)
Definition: editor.c:4588
static void _test_font_size(unsigned line, HWND hwnd, LONG size, LONG expected_size, LRESULT expected_res, BOOL expected_undo)
Definition: editor.c:8668
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:6875
static BOOL bailedOutOfRecursion
Definition: editor.c:2974
static void test_WM_CHAR(void)
Definition: editor.c:6472
static void test_eop_char_fmt(void)
Definition: editor.c:8970
static void test_word_movement(void)
Definition: editor.c:7208
#define TEST_EM_SETFONTSIZE(hwnd, size, expected_size, expected_res, expected_undo)
Definition: editor.c:8666
static const char haystack[]
Definition: editor.c:190
static void test_para_numbering(void)
Definition: editor.c:9006
static void test_EM_GETTEXTRANGE(void)
Definition: editor.c:1803
static void test_alignment_style(void)
Definition: editor.c:8755
static void test_EM_SETTEXTEX(void)
Definition: editor.c:4094
static void disable_beep(HWND hwnd)
Definition: editor.c:63
static void test_WM_NOTIFY(void)
Definition: editor.c:6775
static void test_EM_SETREADONLY(void)
Definition: editor.c:8642
static void test_TM_PLAINTEXT(void)
Definition: editor.c:1626
static void test_EM_GETMODIFY(void)
Definition: editor.c:4846
static IID * pIID_ITextServices
Definition: txtsrv.c:63
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
platform
Definition: msipriv.h:364
@ System
Definition: scrrun.idl:72
unsigned int UINT
Definition: ndis.h:50
#define LOCALE_SYSTEM_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:4979
#define CLSID_NULL
Definition: guiddef.h:99
#define NOT(x)
Definition: qtewin.cpp:1003
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 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 PFM_TABSTOPS
Definition: richedit.h:842
#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 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
WCHAR classname[128]
Definition: startup.c:15
#define test
Definition: rosglue.h:37
const WCHAR * str
#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:182
strcat
Definition: string.h:92
strcpy
Definition: string.h:131
#define memset(x, y, z)
Definition: compat.h:39
HRESULT hr
Definition: shlfolder.c:183
STDMETHOD() Skip(THIS_ ULONG celt) PURE
CHAR lfFaceName[LF_FACESIZE]
Definition: dimm.idl:55
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:3246
HICON hIcon
Definition: winuser.h:3244
HINSTANCE hInstance
Definition: winuser.h:3243
HCURSOR hCursor
Definition: winuser.h:3245
int cbWndExtra
Definition: winuser.h:3242
UINT style
Definition: winuser.h:3239
LPCSTR lpszMenuName
Definition: winuser.h:3247
LPCSTR lpszClassName
Definition: winuser.h:3248
WNDPROC lpfnWndProc
Definition: winuser.h:3240
int cbClsExtra
Definition: winuser.h:3241
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
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: query.h:86
LRESULT expected_retval
Definition: editor.c:5037
LONG max
Definition: editor.c:5036
BOOL todo
Definition: editor.c:5040
int expected_getsel_end
Definition: editor.c:5039
LONG min
Definition: editor.c:5035
int expected_getsel_start
Definition: editor.c:5038
Definition: editor.c:193
int flags
Definition: editor.c:197
int start
Definition: editor.c:194
int end
Definition: editor.c:195
int expected_loc
Definition: editor.c:198
const char * needle
Definition: editor.c:196
Definition: dsound.c:943
size_t buffer_len
Definition: editor.c:421
int line
Definition: editor.c:420
const char * text
Definition: editor.c:422
Definition: parser.c:49
Definition: match.c:28
Definition: tftpd.h:60
Definition: name.c:39
DWORD lsUsb[4]
Definition: wingdi.h:2611
UINT_PTR idFrom
Definition: winuser.h:3234
HWND hwndFrom
Definition: winuser.h:3233
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 TXTBIT_ALLOWBEEP
Definition: textserv.h:196
#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:96
int ret
int WINAPI GetWindowTextA(HWND hWnd, LPSTR lpString, int nMaxCount)
Definition: window.c:1300
static UINT WPARAM LPARAM BOOL ansi
Definition: misc.c:135
#define success(from, fromstr, to, tostr)
#define ZeroMemory
Definition: winbase.h:1753
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 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 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
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)
#define LOCALE_FONTSIGNATURE
Definition: winnls.h:132
#define EM_SETREADONLY
Definition: winuser.h:2034
LRESULT WINAPI DispatchMessageA(_In_ const MSG *)
#define MAKEWPARAM(l, h)
Definition: winuser.h:4085
#define SetWindowLongPtrA
Definition: winuser.h:5430
#define WM_GETTEXTLENGTH
Definition: winuser.h:1638
#define EM_GETRECT
Definition: winuser.h:2015
#define WM_CLOSE
Definition: winuser.h:1640
#define EM_LIMITTEXT
Definition: winuser.h:2019
#define VK_TAB
Definition: winuser.h:2218
UINT WINAPI MapVirtualKeyA(_In_ UINT, _In_ UINT)
#define SB_LINEUP
Definition: winuser.h:564
#define WM_HSCROLL
Definition: winuser.h:1762
BOOL WINAPI SetKeyboardState(_In_reads_(256) LPBYTE)
#define WM_PASTE
Definition: winuser.h:1882
BOOL WINAPI TranslateMessage(_In_ const MSG *)
#define MAKELPARAM(l, h)
Definition: winuser.h:4084
#define WM_KEYUP
Definition: winuser.h:1735
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:2014
LONG WINAPI GetWindowLongA(_In_ HWND, _In_ int)
LRESULT WINAPI DefWindowProcA(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define WM_VSCROLL
Definition: winuser.h:1763
#define CreateWindowA(a, b, c, d, e, f, g, h, i, j, k)
Definition: winuser.h:4391
LONG WINAPI SetWindowLongA(_In_ HWND, _In_ int, _In_ LONG)
#define SIF_RANGE
Definition: winuser.h:1246
#define WM_CREATE
Definition: winuser.h:1627
#define DLGC_WANTCHARS
Definition: winuser.h:2637
#define DLGC_WANTTAB
Definition: winuser.h:2630
#define EM_GETSEL
Definition: winuser.h:2016
#define EM_SETPASSWORDCHAR
Definition: winuser.h:2033
#define EN_UPDATE
Definition: winuser.h:2047
#define EM_GETMODIFY
Definition: winuser.h:2013
#define WB_ISDELIMITER
Definition: winuser.h:549
HWND WINAPI SetParent(_In_ HWND, _In_opt_ HWND)
#define WM_SIZE
Definition: winuser.h:1630
#define SB_VERT
Definition: winuser.h:553
int WINAPI GetClassNameA(_In_ HWND hWnd, _Out_writes_to_(nMaxCount, return) LPSTR lpClassName, _In_ int nMaxCount)
#define EM_EMPTYUNDOBUFFER
Definition: winuser.h:2004
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:1797
BOOL WINAPI ValidateRect(_In_opt_ HWND, _In_opt_ LPCRECT)
HWND WINAPI GetOpenClipboardWindow(void)
Definition: ntwrapper.h:214
#define WM_COMMAND
Definition: winuser.h:1759
#define EM_REPLACESEL
Definition: winuser.h:2025
#define IDC_ARROW
Definition: winuser.h:695
BOOL WINAPI CloseClipboard(void)
Definition: ntwrapper.h:178
#define VK_CONTROL
Definition: winuser.h:2222
BOOL WINAPI GetCursorPos(_Out_ LPPOINT)
Definition: cursoricon.c:3032
#define EM_SETRECT
Definition: winuser.h:2035
#define WM_RBUTTONUP
Definition: winuser.h:1799
#define DC_HASDEFID
Definition: winuser.h:2628
#define WM_RBUTTONDBLCLK
Definition: winuser.h:1800
LRESULT WINAPI SendMessageA(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define WM_SETFOCUS
Definition: winuser.h:1632
#define SIF_PAGE
Definition: winuser.h:1244
#define WM_MOUSEMOVE
Definition: winuser.h:1794
#define WM_GETTEXT
Definition: winuser.h:1637
_Check_return_ BOOL WINAPI GetKeyboardState(_Out_writes_(256) PBYTE lpKeyState)
BOOL WINAPI OpenClipboard(_In_opt_ HWND)
#define WM_CUT
Definition: winuser.h:1880
#define SB_LINERIGHT
Definition: winuser.h:567
#define WM_LBUTTONDOWN
Definition: winuser.h:1795
BOOL WINAPI SetCursorPos(_In_ int, _In_ int)
Definition: cursoricon.c:3024
HANDLE WINAPI GetClipboardData(_In_ UINT)
#define EM_LINESCROLL
Definition: winuser.h:2023
#define EM_GETFIRSTVISIBLELINE
Definition: winuser.h:2007
BOOL WINAPI ClientToScreen(_In_ HWND, _Inout_ LPPOINT)
#define WM_NEXTDLGCTL
Definition: winuser.h:1662
#define WM_UNDO
Definition: winuser.h:1884
#define WM_RBUTTONDOWN
Definition: winuser.h:1798
#define WM_SETTEXT
Definition: winuser.h:1636
#define EM_CANUNDO
Definition: winuser.h:2002
#define EM_LINELENGTH
Definition: winuser.h:2022
BOOL WINAPI IsWindowUnicode(_In_ HWND)
BOOL WINAPI GetClientRect(_In_ HWND, _Out_ LPRECT)
ATOM WINAPI RegisterClassA(_In_ CONST WNDCLASSA *)
#define VK_RETURN
Definition: winuser.h:2220
#define EM_GETLINE
Definition: winuser.h:2010
#define SB_LINELEFT
Definition: winuser.h:566
#define MK_CONTROL
Definition: winuser.h:2389
#define WB_LEFT
Definition: winuser.h:550
#define GWLP_HWNDPARENT
Definition: winuser.h:869
#define WM_SETFONT
Definition: winuser.h:1669
#define EM_UNDO
Definition: winuser.h:2040
#define DLGC_WANTARROWS
Definition: winuser.h:2629
#define EM_SCROLL
Definition: winuser.h:2026
#define PM_REMOVE
Definition: winuser.h:1207
#define SB_PAGEDOWN
Definition: winuser.h:569
#define EM_SETWORDBREAKPROC
Definition: winuser.h:2039
#define SIF_ALL
Definition: winuser.h:1243
#define VK_BACK
Definition: winuser.h:2217
#define SB_LINEDOWN
Definition: winuser.h:565
#define EM_SETSEL
Definition: winuser.h:2037
#define CreateWindowW(a, b, c, d, e, f, g, h, i, j, k)
Definition: winuser.h:4392
BOOL WINAPI GetClassInfoA(_In_opt_ HINSTANCE, _In_ LPCSTR, _Out_ LPWNDCLASSA)
#define WM_LBUTTONUP
Definition: winuser.h:1796
#define WB_RIGHT
Definition: winuser.h:551
#define WM_CHAR
Definition: winuser.h:1736
#define CW_USEDEFAULT
Definition: winuser.h:225
#define VK_LEFT
Definition: winuser.h:2243
#define VK_RIGHT
Definition: winuser.h:2245
#define WM_COPY
Definition: winuser.h:1881
#define WM_SETCURSOR
Definition: winuser.h:1655
BOOL WINAPI PeekMessageA(_Out_ LPMSG, _In_opt_ HWND, _In_ UINT, _In_ UINT, _In_ UINT)
#define DLGC_WANTMESSAGE
Definition: winuser.h:2632
#define VK_DELETE
Definition: winuser.h:2252
#define MAPVK_VK_TO_VSC
Definition: winuser.h:2374
#define WS_EX_CLIENTEDGE
Definition: winuser.h:384
#define WM_CLEAR
Definition: winuser.h:1883
BOOL WINAPI ShowScrollBar(_In_ HWND, _In_ int, _In_ BOOL)
#define WM_KEYDOWN
Definition: winuser.h:1734
#define EM_GETLINECOUNT
Definition: winuser.h:2011
LRESULT(CALLBACK * WNDPROC)(HWND, UINT, WPARAM, LPARAM)
Definition: winuser.h:2982
#define DM_GETDEFID
Definition: winuser.h:2117
BOOL WINAPI InflateRect(_Inout_ LPRECT, _In_ int, _In_ int)
#define GWL_STYLE
Definition: winuser.h:863
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:2233
#define DLGC_HASSETSEL
Definition: winuser.h:2633
BOOL WINAPI IsWindowVisible(_In_ HWND)
BOOL WINAPI DestroyWindow(_In_ HWND)
#define WM_KILLFOCUS
Definition: winuser.h:1633
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)
LRESULT WINAPI CallWindowProcA(_In_ WNDPROC, _In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define WM_GETDLGCODE
Definition: winuser.h:1708
#define EM_SETMODIFY
Definition: winuser.h:2032
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
HCURSOR WINAPI LoadCursorA(_In_opt_ HINSTANCE, _In_ LPCSTR)
Definition: cursoricon.c:2427
#define EN_CHANGE
Definition: winuser.h:2041
#define WM_SETREDRAW
Definition: winuser.h:1635
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409
ActualNumberDriverObjects * sizeof(PDRIVER_OBJECT)) PDRIVER_OBJECT *DriverObjectList
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