ReactOS 0.4.16-dev-889-g9563c07
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
113/* Keeps the window reponsive for the deley_time in seconds.
114 * This is useful for debugging a test to see what is happening. */
115static void keep_responsive(time_t delay_time)
116{
117 MSG msg;
118 time_t end;
119
120 /* The message pump uses PeekMessage() to empty the queue and then
121 * sleeps for 50ms before retrying the queue. */
122 end = time(NULL) + delay_time;
123 while (time(NULL) < end) {
124 if (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
127 } else {
128 Sleep(50);
129 }
130 }
131}
132
133static void simulate_typing_characters(HWND hwnd, const char* szChars)
134{
135 int ret;
136
137 while (*szChars != '\0') {
138 SendMessageA(hwnd, WM_KEYDOWN, *szChars, 1);
139 ret = SendMessageA(hwnd, WM_CHAR, *szChars, 1);
140 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *szChars, ret);
141 SendMessageA(hwnd, WM_KEYUP, *szChars, 1);
142 szChars++;
143 }
144}
145
146static BOOL hold_key(int vk)
147{
148 BYTE key_state[256];
149 BOOL result;
150
151 result = GetKeyboardState(key_state);
152 ok(result, "GetKeyboardState failed.\n");
153 if (!result) return FALSE;
154 key_state[vk] |= 0x80;
155 result = SetKeyboardState(key_state);
156 ok(result, "SetKeyboardState failed.\n");
157 return result != 0;
158}
159
160static BOOL release_key(int vk)
161{
162 BYTE key_state[256];
163 BOOL result;
164
165 result = GetKeyboardState(key_state);
166 ok(result, "GetKeyboardState failed.\n");
167 if (!result) return FALSE;
168 key_state[vk] &= ~0x80;
169 result = SetKeyboardState(key_state);
170 ok(result, "SetKeyboardState failed.\n");
171 return result != 0;
172}
173
174static const char haystack[] = "WINEWine wineWine wine WineWine";
175 /* ^0 ^10 ^20 ^30 */
176
177struct find_s {
178 int start;
179 int end;
180 const char *needle;
181 int flags;
183};
184
185
186static struct find_s find_tests[] = {
187 /* Find in empty text */
188 {0, -1, "foo", FR_DOWN, -1},
189 {0, -1, "foo", 0, -1},
190 {0, -1, "", FR_DOWN, -1},
191 {20, 5, "foo", FR_DOWN, -1},
192 {5, 20, "foo", FR_DOWN, -1}
193};
194
195static struct find_s find_tests2[] = {
196 /* No-result find */
197 {0, -1, "foo", FR_DOWN | FR_MATCHCASE, -1},
198 {5, 20, "WINE", FR_DOWN | FR_MATCHCASE, -1},
199
200 /* Subsequent finds */
201 {0, -1, "Wine", FR_DOWN | FR_MATCHCASE, 4},
202 {5, 31, "Wine", FR_DOWN | FR_MATCHCASE, 13},
203 {14, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23},
204 {24, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27},
205
206 /* Find backwards */
207 {19, 20, "Wine", FR_MATCHCASE, 13},
208 {10, 20, "Wine", FR_MATCHCASE, 4},
209 {20, 10, "Wine", FR_MATCHCASE, 13},
210
211 /* Case-insensitive */
212 {1, 31, "wInE", FR_DOWN, 4},
213 {1, 31, "Wine", FR_DOWN, 4},
214
215 /* High-to-low ranges */
216 {20, 5, "Wine", FR_DOWN, -1},
217 {2, 1, "Wine", FR_DOWN, -1},
218 {30, 29, "Wine", FR_DOWN, -1},
219 {20, 5, "Wine", 0, 13},
220
221 /* Find nothing */
222 {5, 10, "", FR_DOWN, -1},
223 {10, 5, "", FR_DOWN, -1},
224 {0, -1, "", FR_DOWN, -1},
225 {10, 5, "", 0, -1},
226
227 /* Whole-word search */
228 {0, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18},
229 {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1},
230 {13, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18},
231 {0, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 0},
232 {10, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 23},
233 {11, -1, "winewine", FR_WHOLEWORD, 0},
234 {31, -1, "winewine", FR_WHOLEWORD, 23},
235
236 /* Bad ranges */
237 {5, 200, "XXX", FR_DOWN, -1},
238 {-20, 20, "Wine", FR_DOWN, -1},
239 {-20, 20, "Wine", FR_DOWN, -1},
240 {-15, -20, "Wine", FR_DOWN, -1},
241 {1<<12, 1<<13, "Wine", FR_DOWN, -1},
242
243 /* Check the case noted in bug 4479 where matches at end aren't recognized */
244 {23, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23},
245 {27, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27},
246 {27, 32, "Wine", FR_DOWN | FR_MATCHCASE, 27},
247 {13, 31, "WineWine", FR_DOWN | FR_MATCHCASE, 23},
248 {13, 32, "WineWine", FR_DOWN | FR_MATCHCASE, 23},
249
250 /* The backwards case of bug 4479; bounds look right
251 * Fails because backward find is wrong */
252 {19, 20, "WINE", FR_MATCHCASE, 0},
253 {0, 20, "WINE", FR_MATCHCASE, -1},
254
255 {0, -1, "wineWine wine", 0, -1},
256};
257
258static WCHAR *atowstr(const char *str)
259{
260 WCHAR *ret;
261 DWORD len;
262 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
263 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
265 return ret;
266}
267
268static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id, BOOL unicode)
269{
270 int findloc;
271
272 if(unicode){
273 FINDTEXTW ftw;
274 memset(&ftw, 0, sizeof(ftw));
275 ftw.chrg.cpMin = f->start;
276 ftw.chrg.cpMax = f->end;
277 ftw.lpstrText = atowstr(f->needle);
278
279 findloc = SendMessageA(hwnd, EM_FINDTEXT, f->flags, (LPARAM)&ftw);
280 ok(findloc == f->expected_loc,
281 "EM_FINDTEXT(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
282 name, id, unicode, f->needle, f->start, f->end, f->flags, findloc, f->expected_loc);
283
284 findloc = SendMessageA(hwnd, EM_FINDTEXTW, f->flags, (LPARAM)&ftw);
285 ok(findloc == f->expected_loc,
286 "EM_FINDTEXTW(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
287 name, id, unicode, f->needle, f->start, f->end, f->flags, findloc, f->expected_loc);
288
289 HeapFree(GetProcessHeap(), 0, (void*)ftw.lpstrText);
290 }else{
291 FINDTEXTA fta;
292 memset(&fta, 0, sizeof(fta));
293 fta.chrg.cpMin = f->start;
294 fta.chrg.cpMax = f->end;
295 fta.lpstrText = f->needle;
296
297 findloc = SendMessageA(hwnd, EM_FINDTEXT, f->flags, (LPARAM)&fta);
298 ok(findloc == f->expected_loc,
299 "EM_FINDTEXT(%s,%d,%u) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
300 name, id, unicode, f->needle, f->start, f->end, f->flags, findloc, f->expected_loc);
301 }
302}
303
304static void check_EM_FINDTEXTEX(HWND hwnd, const char *name, struct find_s *f,
305 int id, BOOL unicode)
306{
307 int findloc;
308 int expected_end_loc;
309
310 if(unicode){
311 FINDTEXTEXW ftw;
312 memset(&ftw, 0, sizeof(ftw));
313 ftw.chrg.cpMin = f->start;
314 ftw.chrg.cpMax = f->end;
315 ftw.lpstrText = atowstr(f->needle);
316 findloc = SendMessageA(hwnd, EM_FINDTEXTEX, f->flags, (LPARAM)&ftw);
317 ok(findloc == f->expected_loc,
318 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
319 name, id, f->needle, f->start, f->end, f->flags, findloc);
320 ok(ftw.chrgText.cpMin == f->expected_loc,
321 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
322 name, id, f->needle, f->start, f->end, f->flags, ftw.chrgText.cpMin);
323 expected_end_loc = ((f->expected_loc == -1) ? -1
324 : f->expected_loc + strlen(f->needle));
325 ok(ftw.chrgText.cpMax == expected_end_loc,
326 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n",
327 name, id, f->needle, f->start, f->end, f->flags, ftw.chrgText.cpMax, expected_end_loc);
328 HeapFree(GetProcessHeap(), 0, (void*)ftw.lpstrText);
329 }else{
330 FINDTEXTEXA fta;
331 memset(&fta, 0, sizeof(fta));
332 fta.chrg.cpMin = f->start;
333 fta.chrg.cpMax = f->end;
334 fta.lpstrText = f->needle;
335 findloc = SendMessageA(hwnd, EM_FINDTEXTEX, f->flags, (LPARAM)&fta);
336 ok(findloc == f->expected_loc,
337 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
338 name, id, f->needle, f->start, f->end, f->flags, findloc);
339 ok(fta.chrgText.cpMin == f->expected_loc,
340 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
341 name, id, f->needle, f->start, f->end, f->flags, fta.chrgText.cpMin);
342 expected_end_loc = ((f->expected_loc == -1) ? -1
343 : f->expected_loc + strlen(f->needle));
344 ok(fta.chrgText.cpMax == expected_end_loc,
345 "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n",
346 name, id, f->needle, f->start, f->end, f->flags, fta.chrgText.cpMax, expected_end_loc);
347 }
348}
349
350static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *find,
351 int num_tests, BOOL unicode)
352{
353 int i;
354
355 for (i = 0; i < num_tests; i++) {
356 check_EM_FINDTEXT(hwnd, name, &find[i], i, unicode);
357 check_EM_FINDTEXTEX(hwnd, name, &find[i], i, unicode);
358 }
359}
360
361static void test_EM_FINDTEXT(BOOL unicode)
362{
363 HWND hwndRichEdit;
364 CHARFORMAT2A cf2;
365
366 if(unicode)
367 hwndRichEdit = new_richeditW(NULL);
368 else
369 hwndRichEdit = new_richedit(NULL);
370
371 /* Empty rich edit control */
372 run_tests_EM_FINDTEXT(hwndRichEdit, "1", find_tests, ARRAY_SIZE(find_tests), unicode);
373
374 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)haystack);
375
376 /* Haystack text */
377 run_tests_EM_FINDTEXT(hwndRichEdit, "2", find_tests2, ARRAY_SIZE(find_tests2), unicode);
378
379 /* Setting a format on an arbitrary range should have no effect in search
380 results. This tests correct offset reporting across runs. */
381 cf2.cbSize = sizeof(CHARFORMAT2A);
382 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2);
383 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
384 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
385 SendMessageA(hwndRichEdit, EM_SETSEL, 6, 20);
386 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
387
388 /* Haystack text, again */
389 run_tests_EM_FINDTEXT(hwndRichEdit, "2-bis", find_tests2, ARRAY_SIZE(find_tests2), unicode);
390
391 /* Yet another range */
392 cf2.dwMask = CFM_BOLD | cf2.dwMask;
393 cf2.dwEffects = CFE_BOLD ^ cf2.dwEffects;
394 SendMessageA(hwndRichEdit, EM_SETSEL, 11, 15);
395 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
396
397 /* Haystack text, again */
398 run_tests_EM_FINDTEXT(hwndRichEdit, "2-bisbis", find_tests2, ARRAY_SIZE(find_tests2), unicode);
399
400 DestroyWindow(hwndRichEdit);
401}
402
403static const struct getline_s {
404 int line;
406 const char *text;
407} gl[] = {
408 {0, 10, "foo bar\r"},
409 {1, 10, "\r"},
410 {2, 10, "bar\r"},
411 {3, 10, "\r"},
412
413 /* Buffer smaller than line length */
414 {0, 2, "foo bar\r"},
415 {0, 1, "foo bar\r"},
416 {0, 0, "foo bar\r"}
418
419static void test_EM_GETLINE(void)
420{
421 int i;
422 HWND hwndRichEdit = new_richedit(NULL);
423 static const int nBuf = 1024;
424 char dest[1024], origdest[1024];
425 const char text[] = "foo bar\n"
426 "\n"
427 "bar\n";
428
429 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
430
431 memset(origdest, 0xBB, nBuf);
432 for (i = 0; i < ARRAY_SIZE(gl); i++)
433 {
434 int nCopied;
435 int expected_nCopied = min(gl[i].buffer_len, strlen(gl[i].text));
436 int expected_bytes_written = min(gl[i].buffer_len, strlen(gl[i].text));
437 memset(dest, 0xBB, nBuf);
438 *(WORD *) dest = gl[i].buffer_len;
439
440 /* EM_GETLINE appends a "\r\0" to the end of the line
441 * nCopied counts up to and including the '\r' */
442 nCopied = SendMessageA(hwndRichEdit, EM_GETLINE, gl[i].line, (LPARAM)dest);
443 ok(nCopied == expected_nCopied, "%d: %d!=%d\n", i, nCopied,
444 expected_nCopied);
445 /* two special cases since a parameter is passed via dest */
446 if (gl[i].buffer_len == 0)
447 ok(!dest[0] && !dest[1] && !strncmp(dest+2, origdest+2, nBuf-2),
448 "buffer_len=0\n");
449 else if (gl[i].buffer_len == 1)
450 ok(dest[0] == gl[i].text[0] && !dest[1] &&
451 !strncmp(dest+2, origdest+2, nBuf-2), "buffer_len=1\n");
452 else
453 {
454 /* Prepare hex strings of buffers to dump on failure. */
455 char expectedbuf[1024];
456 char resultbuf[1024];
457 int j;
458 resultbuf[0] = '\0';
459 for (j = 0; j < 32; j++)
460 sprintf(resultbuf+strlen(resultbuf), "%02x", dest[j] & 0xFF);
461 expectedbuf[0] = '\0';
462 for (j = 0; j < expected_bytes_written; j++) /* Written bytes */
463 sprintf(expectedbuf+strlen(expectedbuf), "%02x", gl[i].text[j] & 0xFF);
464 for (; j < gl[i].buffer_len; j++) /* Ignored bytes */
465 sprintf(expectedbuf+strlen(expectedbuf), "??");
466 for (; j < 32; j++) /* Bytes after declared buffer size */
467 sprintf(expectedbuf+strlen(expectedbuf), "%02x", origdest[j] & 0xFF);
468
469 /* Test the part of the buffer that is expected to be written according
470 * to the MSDN documentation fo EM_GETLINE, which does not state that
471 * a NULL terminating character will be added unless no text is copied.
472 *
473 * Windows NT does not append a NULL terminating character, but
474 * Windows 2000 and up do append a NULL terminating character if there
475 * is space in the buffer. The test will ignore this difference. */
476 ok(!strncmp(dest, gl[i].text, expected_bytes_written),
477 "%d: expected_bytes_written=%d\n" "expected=0x%s\n" "but got= 0x%s\n",
478 i, expected_bytes_written, expectedbuf, resultbuf);
479 /* Test the part of the buffer after the declared length to make sure
480 * there are no buffer overruns. */
481 ok(!strncmp(dest + gl[i].buffer_len, origdest + gl[i].buffer_len,
482 nBuf - gl[i].buffer_len),
483 "%d: expected_bytes_written=%d\n" "expected=0x%s\n" "but got= 0x%s\n",
484 i, expected_bytes_written, expectedbuf, resultbuf);
485 }
486 }
487
488 DestroyWindow(hwndRichEdit);
489}
490
491static void test_EM_LINELENGTH(void)
492{
493 HWND hwndRichEdit = new_richedit(NULL);
494 const char * text =
495 "richedit1\r"
496 "richedit1\n"
497 "richedit1\r\n"
498 "richedit1";
499 int offset_test[10][2] = {
500 {0, 9},
501 {5, 9},
502 {10, 9},
503 {15, 9},
504 {20, 9},
505 {25, 9},
506 {30, 9},
507 {35, 9},
508 {40, 0},
509 {45, 0},
510 };
511 int i;
513
514 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
515
516 for (i = 0; i < 10; i++) {
517 result = SendMessageA(hwndRichEdit, EM_LINELENGTH, offset_test[i][0], 0);
518 ok(result == offset_test[i][1], "Length of line at offset %d is %ld, expected %d\n",
519 offset_test[i][0], result, offset_test[i][1]);
520 }
521
522 /* Test with multibyte character */
523 if (!is_lang_japanese)
524 skip("Skip multibyte character tests on non-Japanese platform\n");
525 else
526 {
527 const char *text1 =
528 "wine\n"
529 "richedit\x8e\xf0\n"
530 "wine";
531 int offset_test1[3][2] = {
532 {0, 4}, /* Line 1: |wine\n */
533 {5, 9}, /* Line 2: |richedit\x8e\xf0\n */
534 {15, 4}, /* Line 3: |wine */
535 };
536 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
537 for (i = 0; i < ARRAY_SIZE(offset_test1); i++) {
538 result = SendMessageA(hwndRichEdit, EM_LINELENGTH, offset_test1[i][0], 0);
539 ok(result == offset_test1[i][1], "Length of line at offset %d is %ld, expected %d\n",
540 offset_test1[i][0], result, offset_test1[i][1]);
541 }
542 }
543
544 DestroyWindow(hwndRichEdit);
545}
546
548{
549 POINT p = {-1, -1};
551 ok(p.x != -1 && p.y != -1, "p.x:%d p.y:%d\n", p.x, p.y);
552 return p.y;
553}
554
555static void move_cursor(HWND hwnd, LONG charindex)
556{
557 CHARRANGE cr;
558 cr.cpMax = charindex;
559 cr.cpMin = charindex;
561}
562
563static void line_scroll(HWND hwnd, int amount)
564{
565 SendMessageA(hwnd, EM_LINESCROLL, 0, amount);
566}
567
568static void test_EM_SCROLLCARET(void)
569{
570 int prevY, curY;
571 const char text[] = "aa\n"
572 "this is a long line of text that should be longer than the "
573 "control's width\n"
574 "cc\n"
575 "dd\n"
576 "ee\n"
577 "ff\n"
578 "gg\n"
579 "hh\n";
580 /* The richedit window height needs to be large enough vertically to fit in
581 * more than two lines of text, so the new_richedit function can't be used
582 * since a height of 60 was not large enough on some systems.
583 */
586 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
587 ok(hwndRichEdit != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
588
589 /* Can't verify this */
590 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0);
591
592 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
593
594 /* Caret above visible window */
595 line_scroll(hwndRichEdit, 3);
596 prevY = get_scroll_pos_y(hwndRichEdit);
597 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0);
598 curY = get_scroll_pos_y(hwndRichEdit);
599 ok(prevY != curY, "%d == %d\n", prevY, curY);
600
601 /* Caret below visible window */
602 move_cursor(hwndRichEdit, sizeof(text) - 1);
603 line_scroll(hwndRichEdit, -3);
604 prevY = get_scroll_pos_y(hwndRichEdit);
605 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0);
606 curY = get_scroll_pos_y(hwndRichEdit);
607 ok(prevY != curY, "%d == %d\n", prevY, curY);
608
609 /* Caret in visible window */
610 move_cursor(hwndRichEdit, sizeof(text) - 2);
611 prevY = get_scroll_pos_y(hwndRichEdit);
612 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0);
613 curY = get_scroll_pos_y(hwndRichEdit);
614 ok(prevY == curY, "%d != %d\n", prevY, curY);
615
616 /* Caret still in visible window */
617 line_scroll(hwndRichEdit, -1);
618 prevY = get_scroll_pos_y(hwndRichEdit);
619 SendMessageA(hwndRichEdit, EM_SCROLLCARET, 0, 0);
620 curY = get_scroll_pos_y(hwndRichEdit);
621 ok(prevY == curY, "%d != %d\n", prevY, curY);
622
623 DestroyWindow(hwndRichEdit);
624}
625
626static void test_EM_POSFROMCHAR(void)
627{
628 HWND hwndRichEdit = new_richedit(NULL);
629 int i, expected;
631 unsigned int height = 0;
632 int xpos = 0;
633 POINTL pt;
634 LOCALESIGNATURE sig;
635 BOOL rtl;
637 static const char text[] = "aa\n"
638 "this is a long line of text that should be longer than the "
639 "control's width\n"
640 "cc\n"
641 "dd\n"
642 "ee\n"
643 "ff\n"
644 "gg\n"
645 "hh\n";
646
648 (LPSTR) &sig, sizeof(LOCALESIGNATURE)) &&
649 (sig.lsUsb[3] & 0x08000000) != 0);
650
651 /* Fill the control to lines to ensure that most of them are offscreen */
652 for (i = 0; i < 50; i++)
653 {
654 /* Do not modify the string; it is exactly 16 characters long. */
655 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 0);
656 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"0123456789ABCDE\n");
657 }
658
659 /*
660 Richedit 1.0 receives a POINTL* on wParam and character offset on lParam, returns void.
661 Richedit 2.0 receives character offset on wParam, ignores lParam, returns MAKELONG(x,y)
662 Richedit 3.0 accepts either of the above API conventions.
663 */
664
665 /* Testing Richedit 2.0 API format */
666
667 /* Testing start of lines. X-offset should be constant on all cases (native is 1).
668 Since all lines are identical and drawn with the same font,
669 they should have the same height... right?
670 */
671 for (i = 0; i < 50; i++)
672 {
673 /* All the lines are 16 characters long */
674 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, i * 16, 0);
675 if (i == 0)
676 {
677 ok(HIWORD(result) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result));
678 ok(LOWORD(result) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
679 xpos = LOWORD(result);
680 }
681 else if (i == 1)
682 {
683 ok(HIWORD(result) > 0, "EM_POSFROMCHAR reports y=%d, expected > 0\n", HIWORD(result));
684 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
686 }
687 else
688 {
690 ok(HIWORD(result) == i * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), i * height);
691 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
692 }
693 }
694
695 /* Testing position at end of text */
696 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 50 * 16, 0);
697 ok(HIWORD(result) == 50 * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), 50 * height);
698 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
699
700 /* Testing position way past end of text */
701 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 55 * 16, 0);
702 ok(HIWORD(result) == 50 * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), 50 * height);
703 expected = (rtl ? 8 : 1);
704 ok(LOWORD(result) == expected, "EM_POSFROMCHAR reports x=%d, expected %d\n", LOWORD(result), expected);
705
706 /* Testing that vertical scrolling does, in fact, have an effect on EM_POSFROMCHAR */
707 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */
708 for (i = 0; i < 50; i++)
709 {
710 /* All the lines are 16 characters long */
711 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, i * 16, 0);
712 ok((signed short)(HIWORD(result)) == (i - 1) * height,
713 "EM_POSFROMCHAR reports y=%hd, expected %d\n",
714 (signed short)(HIWORD(result)), (i - 1) * height);
715 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
716 }
717
718 /* Testing position at end of text */
719 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 50 * 16, 0);
720 ok(HIWORD(result) == (50 - 1) * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), (50 - 1) * height);
721 ok(LOWORD(result) == xpos, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
722
723 /* Testing position way past end of text */
724 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 55 * 16, 0);
725 ok(HIWORD(result) == (50 - 1) * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", HIWORD(result), (50 - 1) * height);
726 expected = (rtl ? 8 : 1);
727 ok(LOWORD(result) == expected, "EM_POSFROMCHAR reports x=%d, expected %d\n", LOWORD(result), expected);
728
729 /* Testing that horizontal scrolling does, in fact, have an effect on EM_POSFROMCHAR */
730 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
731 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */
732
733 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 0, 0);
734 ok(HIWORD(result) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result));
735 ok(LOWORD(result) == 1, "EM_POSFROMCHAR reports x=%d, expected 1\n", LOWORD(result));
736 xpos = LOWORD(result);
737
738 SendMessageA(hwndRichEdit, WM_HSCROLL, SB_LINERIGHT, 0);
739 result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, 0, 0);
740 ok(HIWORD(result) == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", HIWORD(result));
741 ok((signed short)(LOWORD(result)) < xpos,
742 "EM_POSFROMCHAR reports x=%hd, expected value less than %d\n",
743 (signed short)(LOWORD(result)), xpos);
744 SendMessageA(hwndRichEdit, WM_HSCROLL, SB_LINELEFT, 0);
745
746 /* Test around end of text that doesn't end in a newline. */
747 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"12345678901234");
748 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt,
749 SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0)-1);
750 ok(pt.x > 1, "pt.x = %d\n", pt.x);
751 xpos = pt.x;
752 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt,
753 SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0));
754 ok(pt.x > xpos, "pt.x = %d\n", pt.x);
755 xpos = (rtl ? pt.x + 7 : pt.x);
756 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt,
757 SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0)+1);
758 ok(pt.x == xpos, "pt.x = %d\n", pt.x);
759
760 /* Try a negative position. */
761 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt, -1);
762 ok(pt.x == 1, "pt.x = %d\n", pt.x);
763
764 /* test negative indentation */
765 SendMessageA(hwndRichEdit, WM_SETTEXT, 0,
766 (LPARAM)"{\\rtf1\\pard\\fi-200\\li-200\\f1 TestSomeText\\par}");
767 SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pt, 0);
768 ok(pt.x == 1, "pt.x = %d\n", pt.x);
769
770 fmt.cbSize = sizeof(fmt);
771 SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt);
772 ok(fmt.dxStartIndent == -400, "got %d\n", fmt.dxStartIndent);
773 ok(fmt.dxOffset == 200, "got %d\n", fmt.dxOffset);
774 ok(fmt.wAlignment == PFA_LEFT, "got %d\n", fmt.wAlignment);
775
776 DestroyWindow(hwndRichEdit);
777}
778
779static void test_EM_SETCHARFORMAT(void)
780{
781 HWND hwndRichEdit = new_richedit(NULL);
782 CHARFORMAT2A cf2;
783 CHARFORMAT2W cfW;
784 CHARFORMATA cf1a;
785 CHARFORMATW cf1w;
786 int rc = 0;
787 int tested_effects[] = {
788 CFE_BOLD,
793 CFE_LINK,
796 0
797 };
798 int i;
799 CHARRANGE cr;
800 LOCALESIGNATURE sig;
801 BOOL rtl;
802 DWORD expect_effects;
803
805 (LPSTR) &sig, sizeof(LOCALESIGNATURE)) &&
806 (sig.lsUsb[3] & 0x08000000) != 0);
807
808 /* check charformat defaults */
809 memset(&cf2, 0, sizeof(CHARFORMAT2A));
810 cf2.cbSize = sizeof(CHARFORMAT2A);
811 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
812 ok(cf2.dwMask == CFM_ALL2, "got %08x\n", cf2.dwMask);
813 expect_effects = CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR;
814 if (cf2.wWeight > 550) expect_effects |= CFE_BOLD;
815 ok(cf2.dwEffects == expect_effects, "got %08x\n", cf2.dwEffects);
816 ok(cf2.yOffset == 0, "got %d\n", cf2.yOffset);
817 ok(cf2.sSpacing == 0, "got %d\n", cf2.sSpacing);
818 ok(cf2.lcid == GetSystemDefaultLCID(), "got %x\n", cf2.lcid);
819 ok(cf2.sStyle == 0, "got %d\n", cf2.sStyle);
820 ok(cf2.wKerning == 0, "got %d\n", cf2.wKerning);
821 ok(cf2.bAnimation == 0, "got %d\n", cf2.bAnimation);
822 ok(cf2.bRevAuthor == 0, "got %d\n", cf2.bRevAuthor);
823
824 /* Invalid flags, CHARFORMAT2 structure blanked out */
825 memset(&cf2, 0, sizeof(cf2));
826 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)0xfffffff0, (LPARAM)&cf2);
827 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
828
829 /* A valid flag, CHARFORMAT2 structure blanked out */
830 memset(&cf2, 0, sizeof(cf2));
831 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2);
832 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
833
834 /* A valid flag, CHARFORMAT2 structure blanked out */
835 memset(&cf2, 0, sizeof(cf2));
836 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2);
837 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
838
839 /* A valid flag, CHARFORMAT2 structure blanked out */
840 memset(&cf2, 0, sizeof(cf2));
841 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_WORD, (LPARAM)&cf2);
842 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
843
844 /* A valid flag, CHARFORMAT2 structure blanked out */
845 memset(&cf2, 0, sizeof(cf2));
846 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2);
847 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
848
849 /* Invalid flags, CHARFORMAT2 structure minimally filled */
850 memset(&cf2, 0, sizeof(cf2));
851 cf2.cbSize = sizeof(CHARFORMAT2A);
852 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)0xfffffff0, (LPARAM)&cf2);
853 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
854 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
855 ok(rc == FALSE, "Should not be able to undo here.\n");
856 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0);
857
858 /* A valid flag, CHARFORMAT2 structure minimally filled */
859 memset(&cf2, 0, sizeof(cf2));
860 cf2.cbSize = sizeof(CHARFORMAT2A);
861 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2);
862 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
863 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
864 ok(rc == FALSE, "Should not be able to undo here.\n");
865 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0);
866
867 /* A valid flag, CHARFORMAT2 structure minimally filled */
868 memset(&cf2, 0, sizeof(cf2));
869 cf2.cbSize = sizeof(CHARFORMAT2A);
870 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2);
871 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
872 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
873 ok(rc == FALSE, "Should not be able to undo here.\n");
874 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0);
875
876 /* A valid flag, CHARFORMAT2 structure minimally filled */
877 memset(&cf2, 0, sizeof(cf2));
878 cf2.cbSize = sizeof(CHARFORMAT2A);
879 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_WORD, (LPARAM)&cf2);
880 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
881 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
882 todo_wine ok(rc == TRUE, "Should not be able to undo here.\n");
883 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0);
884
885 /* A valid flag, CHARFORMAT2 structure minimally filled */
886 memset(&cf2, 0, sizeof(cf2));
887 cf2.cbSize = sizeof(CHARFORMAT2A);
888 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2);
889 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
890 rc = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
891 ok(rc == TRUE, "Should not be able to undo here.\n");
892 SendMessageA(hwndRichEdit, EM_EMPTYUNDOBUFFER, 0, 0);
893
894 cf2.cbSize = sizeof(CHARFORMAT2A);
895 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2);
896
897 /* Test state of modify flag before and after valid EM_SETCHARFORMAT */
898 cf2.cbSize = sizeof(CHARFORMAT2A);
899 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2);
900 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
901 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
902
903 /* wParam==0 is default char format, does not set modify */
904 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
905 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
906 ok(rc == 0, "Text marked as modified, expected not modified!\n");
907 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, 0, (LPARAM)&cf2);
908 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
909 if (! rtl)
910 {
911 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
912 ok(rc == 0, "Text marked as modified, expected not modified!\n");
913 }
914 else
915 skip("RTL language found\n");
916
917 /* wParam==SCF_SELECTION sets modify if nonempty selection */
918 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
919 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
920 ok(rc == 0, "Text marked as modified, expected not modified!\n");
921 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
922 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
923 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
924 ok(rc == 0, "Text marked as modified, expected not modified!\n");
925
926 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
927 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
928 ok(rc == 0, "Text marked as modified, expected not modified!\n");
929 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
930 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
931 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
932 ok(rc == 0, "Text marked as modified, expected not modified!\n");
933 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2);
934 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
935 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
936 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
937 ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc);
938
939 /* wParam==SCF_ALL sets modify regardless of whether text is present */
940 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
941 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
942 ok(rc == 0, "Text marked as modified, expected not modified!\n");
943 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2);
944 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
945 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
946 ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc);
947
948 DestroyWindow(hwndRichEdit);
949
950 /* EM_GETCHARFORMAT tests */
951 for (i = 0; tested_effects[i]; i++)
952 {
953 hwndRichEdit = new_richedit(NULL);
954 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
955
956 /* Need to set a TrueType font to get consistent CFM_BOLD results */
957 memset(&cf2, 0, sizeof(CHARFORMAT2A));
958 cf2.cbSize = sizeof(CHARFORMAT2A);
960 cf2.dwEffects = 0;
961 strcpy(cf2.szFaceName, "Courier New");
962 cf2.wWeight = FW_DONTCARE;
963 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2);
964
965 memset(&cf2, 0, sizeof(CHARFORMAT2A));
966 cf2.cbSize = sizeof(CHARFORMAT2A);
967 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 4);
968 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
969 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
970 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
971 ||
972 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
973 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
974 ok((cf2.dwEffects & tested_effects[i]) == 0,
975 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i, cf2.dwEffects, tested_effects[i]);
976
977 memset(&cf2, 0, sizeof(CHARFORMAT2A));
978 cf2.cbSize = sizeof(CHARFORMAT2A);
979 cf2.dwMask = tested_effects[i];
980 if (cf2.dwMask == CFE_SUBSCRIPT || cf2.dwMask == CFE_SUPERSCRIPT)
981 cf2.dwMask = CFM_SUPERSCRIPT;
982 cf2.dwEffects = tested_effects[i];
983 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2);
984 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
985
986 memset(&cf2, 0, sizeof(CHARFORMAT2A));
987 cf2.cbSize = sizeof(CHARFORMAT2A);
988 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2);
989 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
990 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
991 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
992 ||
993 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
994 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
995 ok((cf2.dwEffects & tested_effects[i]) == tested_effects[i],
996 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, tested_effects[i]);
997
998 memset(&cf2, 0, sizeof(CHARFORMAT2A));
999 cf2.cbSize = sizeof(CHARFORMAT2A);
1000 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 4);
1001 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1002 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
1003 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
1004 ||
1005 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
1006 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
1007 ok((cf2.dwEffects & tested_effects[i]) == 0,
1008 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i, cf2.dwEffects, tested_effects[i]);
1009
1010 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1011 cf2.cbSize = sizeof(CHARFORMAT2A);
1012 SendMessageA(hwndRichEdit, EM_SETSEL, 1, 3);
1013 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1014 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
1015 (cf2.dwMask & CFM_SUPERSCRIPT) == 0)
1016 ||
1017 (cf2.dwMask & tested_effects[i]) == 0),
1018 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i, cf2.dwMask, tested_effects[i]);
1019
1020 DestroyWindow(hwndRichEdit);
1021 }
1022
1023 for (i = 0; tested_effects[i]; i++)
1024 {
1025 hwndRichEdit = new_richedit(NULL);
1026 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1027
1028 /* Need to set a TrueType font to get consistent CFM_BOLD results */
1029 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1030 cf2.cbSize = sizeof(CHARFORMAT2A);
1032 cf2.dwEffects = 0;
1033 strcpy(cf2.szFaceName, "Courier New");
1034 cf2.wWeight = FW_DONTCARE;
1035 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2);
1036
1037 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1038 cf2.cbSize = sizeof(CHARFORMAT2A);
1039 cf2.dwMask = tested_effects[i];
1040 if (cf2.dwMask == CFE_SUBSCRIPT || cf2.dwMask == CFE_SUPERSCRIPT)
1041 cf2.dwMask = CFM_SUPERSCRIPT;
1042 cf2.dwEffects = tested_effects[i];
1043 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 4);
1044 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1045
1046 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1047 cf2.cbSize = sizeof(CHARFORMAT2A);
1048 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2);
1049 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1050 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
1051 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
1052 ||
1053 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
1054 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
1055 ok((cf2.dwEffects & tested_effects[i]) == 0,
1056 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x clear\n", i, cf2.dwEffects, tested_effects[i]);
1057
1058 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1059 cf2.cbSize = sizeof(CHARFORMAT2A);
1060 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 4);
1061 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1062 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
1063 (cf2.dwMask & CFM_SUPERSCRIPT) == CFM_SUPERSCRIPT)
1064 ||
1065 (cf2.dwMask & tested_effects[i]) == tested_effects[i]),
1066 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, tested_effects[i]);
1067 ok((cf2.dwEffects & tested_effects[i]) == tested_effects[i],
1068 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, tested_effects[i]);
1069
1070 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1071 cf2.cbSize = sizeof(CHARFORMAT2A);
1072 SendMessageA(hwndRichEdit, EM_SETSEL, 1, 3);
1073 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1074 ok ((((tested_effects[i] == CFE_SUBSCRIPT || tested_effects[i] == CFE_SUPERSCRIPT) &&
1075 (cf2.dwMask & CFM_SUPERSCRIPT) == 0)
1076 ||
1077 (cf2.dwMask & tested_effects[i]) == 0),
1078 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x clear\n", i, cf2.dwMask, tested_effects[i]);
1079 ok((cf2.dwEffects & tested_effects[i]) == tested_effects[i],
1080 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x set\n", i, cf2.dwEffects, tested_effects[i]);
1081
1082 DestroyWindow(hwndRichEdit);
1083 }
1084
1085 /* Effects applied on an empty selection should take effect when selection is
1086 replaced with text */
1087 hwndRichEdit = new_richedit(NULL);
1088 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1089 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */
1090
1091 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1092 cf2.cbSize = sizeof(CHARFORMAT2A);
1093 cf2.dwMask = CFM_BOLD;
1094 cf2.dwEffects = CFE_BOLD;
1095 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1096
1097 /* Selection is now nonempty */
1098 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi");
1099
1100 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1101 cf2.cbSize = sizeof(CHARFORMAT2A);
1102 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 6);
1103 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1104
1105 ok (((cf2.dwMask & CFM_BOLD) == CFM_BOLD),
1106 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD);
1107 ok((cf2.dwEffects & CFE_BOLD) == CFE_BOLD,
1108 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD);
1109
1110
1111 /* Set two effects on an empty selection */
1112 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1113 /* first clear bold, italic */
1114 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
1115 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1116 cf2.cbSize = sizeof(CHARFORMAT2A);
1117 cf2.dwMask = CFM_BOLD | CFM_ITALIC;
1118 cf2.dwEffects = 0;
1119 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1120
1121 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */
1122
1123 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1124 cf2.cbSize = sizeof(CHARFORMAT2A);
1125 cf2.dwMask = CFM_BOLD;
1126 cf2.dwEffects = CFE_BOLD;
1127 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1128 cf2.dwMask = CFM_ITALIC;
1129 cf2.dwEffects = CFE_ITALIC;
1130 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1131
1132 /* Selection is now nonempty */
1133 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi");
1134
1135 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1136 cf2.cbSize = sizeof(CHARFORMAT2A);
1137 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 6);
1138 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1139
1140 ok (((cf2.dwMask & (CFM_BOLD|CFM_ITALIC)) == (CFM_BOLD|CFM_ITALIC)),
1141 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, (CFM_BOLD|CFM_ITALIC));
1143 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, (CFE_BOLD|CFE_ITALIC));
1144
1145 /* Setting the (empty) selection to exactly the same place as before should
1146 NOT clear the insertion style! */
1147 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1148 /* first clear bold, italic */
1149 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
1150 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1151 cf2.cbSize = sizeof(CHARFORMAT2A);
1152 cf2.dwMask = CFM_BOLD | CFM_ITALIC;
1153 cf2.dwEffects = 0;
1154 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1155
1156 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */
1157
1158 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1159 cf2.cbSize = sizeof(CHARFORMAT2A);
1160 cf2.dwMask = CFM_BOLD;
1161 cf2.dwEffects = CFE_BOLD;
1162 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1163
1164 /* Empty selection in same place, insert style should NOT be forgotten here. */
1165 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2);
1166
1167 /* Selection is now nonempty */
1168 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi");
1169
1170 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1171 cf2.cbSize = sizeof(CHARFORMAT2A);
1172 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 6);
1173 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1174
1175 ok (((cf2.dwMask & CFM_BOLD) == CFM_BOLD),
1176 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD);
1177 ok((cf2.dwEffects & CFE_BOLD) == CFE_BOLD,
1178 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD);
1179
1180 /* Moving the selection will clear the insertion style */
1181 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1182 /* first clear bold, italic */
1183 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
1184 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1185 cf2.cbSize = sizeof(CHARFORMAT2A);
1186 cf2.dwMask = CFM_BOLD | CFM_ITALIC;
1187 cf2.dwEffects = 0;
1188 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1189
1190 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */
1191
1192 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1193 cf2.cbSize = sizeof(CHARFORMAT2A);
1194 cf2.dwMask = CFM_BOLD;
1195 cf2.dwEffects = CFE_BOLD;
1196 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1197
1198 /* Move selection and then put it back, insert style should be forgotten here. */
1199 SendMessageA(hwndRichEdit, EM_SETSEL, 3, 3);
1200 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 2); /* Empty selection */
1201
1202 /* Selection is now nonempty */
1203 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi");
1204
1205 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1206 cf2.cbSize = sizeof(CHARFORMAT2A);
1207 SendMessageA(hwndRichEdit, EM_SETSEL, 2, 6);
1208 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1209
1210 ok(((cf2.dwMask & CFM_BOLD) == CFM_BOLD),
1211 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD);
1212 ok((cf2.dwEffects & CFE_BOLD) == 0,
1213 "%d, cf2.dwEffects == 0x%08x not expecting effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD);
1214
1215 /* Ditto with EM_EXSETSEL */
1216 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1217 /* first clear bold, italic */
1218 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
1219 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1220 cf2.cbSize = sizeof(CHARFORMAT2A);
1221 cf2.dwMask = CFM_BOLD | CFM_ITALIC;
1222 cf2.dwEffects = 0;
1223 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1224
1225 cr.cpMin = 2; cr.cpMax = 2;
1226 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); /* Empty selection */
1227
1228 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1229 cf2.cbSize = sizeof(CHARFORMAT2A);
1230 cf2.dwMask = CFM_BOLD;
1231 cf2.dwEffects = CFE_BOLD;
1232 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1233
1234 /* Empty selection in same place, insert style should NOT be forgotten here. */
1235 cr.cpMin = 2; cr.cpMax = 2;
1236 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); /* Empty selection */
1237
1238 /* Selection is now nonempty */
1239 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"newi");
1240
1241 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1242 cf2.cbSize = sizeof(CHARFORMAT2A);
1243 cr.cpMin = 2; cr.cpMax = 6;
1244 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr); /* Empty selection */
1245 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1246
1247 ok (((cf2.dwMask & CFM_BOLD) == CFM_BOLD),
1248 "%d, cf2.dwMask == 0x%08x expected mask 0x%08x\n", i, cf2.dwMask, CFM_BOLD);
1249 ok((cf2.dwEffects & CFE_BOLD) == CFE_BOLD,
1250 "%d, cf2.dwEffects == 0x%08x expected effect 0x%08x\n", i, cf2.dwEffects, CFE_BOLD);
1251
1252 /* show that wWeight is at the correct offset in CHARFORMAT2A */
1253 memset(&cf2, 0, sizeof(cf2));
1254 cf2.cbSize = sizeof(cf2);
1255 cf2.dwMask = CFM_WEIGHT;
1256 cf2.wWeight = 100;
1257 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1258 memset(&cf2, 0, sizeof(cf2));
1259 cf2.cbSize = sizeof(cf2);
1260 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1261 ok(cf2.wWeight == 100, "got %d\n", cf2.wWeight);
1262
1263 memset(&cf2, 0, sizeof(cf2));
1264 cf2.cbSize = sizeof(cf2);
1265 cf2.dwMask = CFM_SPACING;
1266 cf2.sSpacing = 10;
1267 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1268 memset(&cf2, 0, sizeof(cf2));
1269 cf2.cbSize = sizeof(cf2);
1270 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1271 ok(cf2.sSpacing == 10, "got %d\n", cf2.sSpacing);
1272
1273 /* show that wWeight is at the correct offset in CHARFORMAT2W */
1274 memset(&cfW, 0, sizeof(cfW));
1275 cfW.cbSize = sizeof(cfW);
1276 cfW.dwMask = CFM_WEIGHT;
1277 cfW.wWeight = 100;
1278 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfW);
1279 memset(&cfW, 0, sizeof(cfW));
1280 cfW.cbSize = sizeof(cfW);
1281 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfW);
1282 ok(cfW.wWeight == 100, "got %d\n", cfW.wWeight);
1283
1284 memset(&cfW, 0, sizeof(cfW));
1285 cfW.cbSize = sizeof(cfW);
1286 cfW.dwMask = CFM_SPACING;
1287 cfW.sSpacing = 10;
1288 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfW);
1289 memset(&cfW, 0, sizeof(cfW));
1290 cfW.cbSize = sizeof(cfW);
1291 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfW);
1292 ok(cfW.sSpacing == 10, "got %d\n", cfW.sSpacing);
1293
1294 /* test CFE_UNDERLINE and bUnderlineType interaction */
1295 /* clear bold, italic */
1296 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
1297 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1298 cf2.cbSize = sizeof(CHARFORMAT2A);
1299 cf2.dwMask = CFM_BOLD | CFM_ITALIC;
1300 cf2.dwEffects = 0;
1301 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1302
1303 /* check CFE_UNDERLINE is clear and bUnderlineType is CFU_UNDERLINE */
1304 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1305 cf2.cbSize = sizeof(CHARFORMAT2A);
1306 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1308 "got %08x\n", cf2.dwMask);
1309 ok(!(cf2.dwEffects & CFE_UNDERLINE), "got %08x\n", cf2.dwEffects);
1310 ok(cf2.bUnderlineType == CFU_UNDERLINE, "got %x\n", cf2.bUnderlineType);
1311
1312 /* simply touching bUnderlineType will toggle CFE_UNDERLINE */
1315 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1316 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1317 cf2.cbSize = sizeof(CHARFORMAT2A);
1318 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1320 "got %08x\n", cf2.dwMask);
1321 ok(cf2.dwEffects & CFE_UNDERLINE, "got %08x\n", cf2.dwEffects);
1322 ok(cf2.bUnderlineType == CFU_UNDERLINE, "got %x\n", cf2.bUnderlineType);
1323
1324 /* setting bUnderline to CFU_UNDERLINENONE clears CFE_UNDERLINE */
1327 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1328 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1329 cf2.cbSize = sizeof(CHARFORMAT2A);
1330 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1332 "got %08x\n", cf2.dwMask);
1333 ok(!(cf2.dwEffects & CFE_UNDERLINE), "got %08x\n", cf2.dwEffects);
1334 ok(cf2.bUnderlineType == CFU_UNDERLINENONE, "got %x\n", cf2.bUnderlineType);
1335
1336 /* another underline type also sets CFE_UNDERLINE */
1339 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1340 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1341 cf2.cbSize = sizeof(CHARFORMAT2A);
1342 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1344 "got %08x\n", cf2.dwMask);
1345 ok(cf2.dwEffects & CFE_UNDERLINE, "got %08x\n", cf2.dwEffects);
1346 ok(cf2.bUnderlineType == CFU_UNDERLINEDOUBLE, "got %x\n", cf2.bUnderlineType);
1347
1348 /* However explicitly clearing CFE_UNDERLINE results in it remaining cleared */
1351 cf2.dwEffects = 0;
1352 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1353 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1354 cf2.cbSize = sizeof(CHARFORMAT2A);
1355 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1357 "got %08x\n", cf2.dwMask);
1358 ok(!(cf2.dwEffects & CFE_UNDERLINE), "got %08x\n", cf2.dwEffects);
1359 ok(cf2.bUnderlineType == CFU_UNDERLINEDOUBLE, "got %x\n", cf2.bUnderlineType);
1360
1361 /* And turing it back on again by just setting CFE_UNDERLINE */
1362 cf2.dwMask = CFM_UNDERLINE;
1364 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1365 memset(&cf2, 0, sizeof(CHARFORMAT2A));
1366 cf2.cbSize = sizeof(CHARFORMAT2A);
1367 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1369 "got %08x\n", cf2.dwMask);
1370 ok(cf2.dwEffects & CFE_UNDERLINE, "got %08x\n", cf2.dwEffects);
1371 ok(cf2.bUnderlineType == CFU_UNDERLINEDOUBLE, "got %x\n", cf2.bUnderlineType);
1372
1373 /* Check setting CFM_ALL2/CFM_EFFECTS2 in CHARFORMAT(A/W). */
1374 memset(&cf1a, 0, sizeof(CHARFORMATA));
1375 memset(&cf1w, 0, sizeof(CHARFORMATW));
1376 cf1a.cbSize = sizeof(CHARFORMATA);
1377 cf1w.cbSize = sizeof(CHARFORMATW);
1378 cf1a.dwMask = cf1w.dwMask = CFM_ALL2;
1379 cf1a.dwEffects = cf1w.dwEffects = CFM_EFFECTS2;
1380 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf1a);
1381 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf1a);
1382 /* flags only valid for CHARFORMAT2 should be masked out */
1383 ok((cf1a.dwMask & (CFM_ALL2 & ~CFM_ALL)) == 0, "flags were not masked out\n");
1384 ok((cf1a.dwEffects & (CFM_EFFECTS2 & ~CFM_EFFECTS)) == 0, "flags were not masked out\n");
1385 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf1w);
1386 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf1w);
1387 ok((cf1w.dwMask & (CFM_ALL2 & ~CFM_ALL)) == 0, "flags were not masked out\n");
1388 ok((cf1w.dwEffects & (CFM_EFFECTS2 & ~CFM_EFFECTS)) == 0, "flags were not masked out\n");
1389
1390 DestroyWindow(hwndRichEdit);
1391}
1392
1393static void test_EM_SETTEXTMODE(void)
1394{
1395 HWND hwndRichEdit = new_richedit(NULL);
1396 CHARFORMAT2A cf2, cf2test;
1397 CHARRANGE cr;
1398 int rc = 0;
1399
1400 /*Attempt to use mutually exclusive modes*/
1402 ok(rc == E_INVALIDARG,
1403 "EM_SETTEXTMODE: using mutually exclusive mode flags - returned: %x\n", rc);
1404
1405 /*Test that EM_SETTEXTMODE fails if text exists within the control*/
1406 /*Insert text into the control*/
1407
1408 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1409
1410 /*Attempt to change the control to plain text mode*/
1411 rc = SendMessageA(hwndRichEdit, EM_SETTEXTMODE, (WPARAM)TM_PLAINTEXT, 0);
1412 ok(rc == E_UNEXPECTED,
1413 "EM_SETTEXTMODE: changed text mode in control containing text - returned: %x\n", rc);
1414
1415 /*Test that EM_SETTEXTMODE does not allow rich edit text to be pasted.
1416 If rich text is pasted, it should have the same formatting as the rest
1417 of the text in the control*/
1418
1419 /*Italicize the text
1420 *NOTE: If the default text was already italicized, the test will simply
1421 reverse; in other words, it will copy a regular "wine" into a plain
1422 text window that uses an italicized format*/
1423 cf2.cbSize = sizeof(CHARFORMAT2A);
1424 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_DEFAULT, (LPARAM)&cf2);
1425
1426 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
1427 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
1428
1429 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
1430 ok(rc == 0, "Text marked as modified, expected not modified!\n");
1431
1432 /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine;
1433 however, SCF_ALL has been implemented*/
1434 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2);
1435 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
1436
1437 rc = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
1438 ok(rc == -1, "Text not marked as modified, expected modified! (%d)\n", rc);
1439
1440 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1441
1442 /*Select the string "wine"*/
1443 cr.cpMin = 0;
1444 cr.cpMax = 4;
1445 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1446
1447 /*Copy the italicized "wine" to the clipboard*/
1448 SendMessageA(hwndRichEdit, WM_COPY, 0, 0);
1449
1450 /*Reset the formatting to default*/
1451 cf2.dwEffects = CFE_ITALIC^cf2.dwEffects;
1452 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf2);
1453 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
1454
1455 /*Clear the text in the control*/
1456 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
1457
1458 /*Switch to Plain Text Mode*/
1459 rc = SendMessageA(hwndRichEdit, EM_SETTEXTMODE, (WPARAM)TM_PLAINTEXT, 0);
1460 ok(rc == 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control: returned: %d\n", rc);
1461
1462 /*Input "wine" again in normal format*/
1463 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1464
1465 /*Paste the italicized "wine" into the control*/
1466 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
1467
1468 /*Select a character from the first "wine" string*/
1469 cr.cpMin = 2;
1470 cr.cpMax = 3;
1471 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1472
1473 /*Retrieve its formatting*/
1475
1476 /*Select a character from the second "wine" string*/
1477 cr.cpMin = 5;
1478 cr.cpMax = 6;
1479 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1480
1481 /*Retrieve its formatting*/
1482 cf2test.cbSize = sizeof(CHARFORMAT2A);
1483 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2test);
1484
1485 /*Compare the two formattings*/
1486 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
1487 "two formats found in plain text mode - cf2.dwEffects: %x cf2test.dwEffects: %x\n",
1488 cf2.dwEffects, cf2test.dwEffects);
1489 /*Test TM_RICHTEXT by: switching back to Rich Text mode
1490 printing "wine" in the current format(normal)
1491 pasting "wine" from the clipboard(italicized)
1492 comparing the two formats(should differ)*/
1493
1494 /*Attempt to switch with text in control*/
1495 rc = SendMessageA(hwndRichEdit, EM_SETTEXTMODE, (WPARAM)TM_RICHTEXT, 0);
1496 ok(rc != 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc);
1497
1498 /*Clear control*/
1499 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
1500
1501 /*Switch into Rich Text mode*/
1502 rc = SendMessageA(hwndRichEdit, EM_SETTEXTMODE, (WPARAM)TM_RICHTEXT, 0);
1503 ok(rc == 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc);
1504
1505 /*Print "wine" in normal formatting into the control*/
1506 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1507
1508 /*Paste italicized "wine" into the control*/
1509 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
1510
1511 /*Select text from the first "wine" string*/
1512 cr.cpMin = 1;
1513 cr.cpMax = 3;
1514 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1515
1516 /*Retrieve its formatting*/
1518
1519 /*Select text from the second "wine" string*/
1520 cr.cpMin = 6;
1521 cr.cpMax = 7;
1522 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1523
1524 /*Retrieve its formatting*/
1525 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)&cf2test);
1526
1527 /*Test that the two formattings are not the same*/
1528 todo_wine ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects != cf2test.dwEffects),
1529 "expected different formats - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1530 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
1531
1532 DestroyWindow(hwndRichEdit);
1533}
1534
1535static void test_SETPARAFORMAT(void)
1536{
1537 HWND hwndRichEdit = new_richedit(NULL);
1539 HRESULT ret;
1540 LONG expectedMask = PFM_ALL2 & ~PFM_TABLEROWDELIMITER;
1541 fmt.cbSize = sizeof(PARAFORMAT2);
1542 fmt.dwMask = PFM_ALIGNMENT;
1543 fmt.wAlignment = PFA_LEFT;
1544
1545 ret = SendMessageA(hwndRichEdit, EM_SETPARAFORMAT, 0, (LPARAM)&fmt);
1546 ok(ret != 0, "expected non-zero got %d\n", ret);
1547
1548 fmt.cbSize = sizeof(PARAFORMAT2);
1549 fmt.dwMask = -1;
1550 ret = SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt);
1551 /* Ignore the PFM_TABLEROWDELIMITER bit because it changes
1552 * between richedit different native builds of riched20.dll
1553 * used on different Windows versions. */
1554 ret &= ~PFM_TABLEROWDELIMITER;
1555 fmt.dwMask &= ~PFM_TABLEROWDELIMITER;
1556
1557 ok(ret == expectedMask, "expected %x got %x\n", expectedMask, ret);
1558 ok(fmt.dwMask == expectedMask, "expected %x got %x\n", expectedMask, fmt.dwMask);
1559
1560 /* Test some other paraformat field defaults */
1561 ok( fmt.wNumbering == 0, "got %d\n", fmt.wNumbering );
1562 ok( fmt.wNumberingStart == 0, "got %d\n", fmt.wNumberingStart );
1563 ok( fmt.wNumberingStyle == 0, "got %04x\n", fmt.wNumberingStyle );
1564 ok( fmt.wNumberingTab == 0, "got %d\n", fmt.wNumberingTab );
1565
1566 DestroyWindow(hwndRichEdit);
1567}
1568
1569static void test_TM_PLAINTEXT(void)
1570{
1571 /*Tests plain text properties*/
1572
1573 HWND hwndRichEdit = new_richedit(NULL);
1574 CHARFORMAT2A cf2, cf2test;
1575 CHARRANGE cr;
1576 int rc = 0;
1577
1578 /*Switch to plain text mode*/
1579
1580 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
1581 SendMessageA(hwndRichEdit, EM_SETTEXTMODE, TM_PLAINTEXT, 0);
1582
1583 /*Fill control with text*/
1584
1585 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"Is Wine an emulator? No it's not");
1586
1587 /*Select some text and bold it*/
1588
1589 cr.cpMin = 10;
1590 cr.cpMax = 20;
1591 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1592 cf2.cbSize = sizeof(CHARFORMAT2A);
1593 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2);
1594
1595 cf2.dwMask = CFM_BOLD | cf2.dwMask;
1596 cf2.dwEffects = CFE_BOLD ^ cf2.dwEffects;
1597
1598 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1599 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
1600
1601 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_WORD | SCF_SELECTION, (LPARAM)&cf2);
1602 ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
1603
1604 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2);
1605 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
1606
1607 /*Get the formatting of those characters*/
1608
1609 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1610
1611 /*Get the formatting of some other characters*/
1612 cf2test.cbSize = sizeof(CHARFORMAT2A);
1613 cr.cpMin = 21;
1614 cr.cpMax = 30;
1615 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1616 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2test);
1617
1618 /*Test that they are the same as plain text allows only one formatting*/
1619
1620 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
1621 "two selections' formats differ - cf2.dwMask: %x, cf2test.dwMask %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1622 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
1623
1624 /*Fill the control with a "wine" string, which when inserted will be bold*/
1625
1626 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1627
1628 /*Copy the bolded "wine" string*/
1629
1630 cr.cpMin = 0;
1631 cr.cpMax = 4;
1632 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1633 SendMessageA(hwndRichEdit, WM_COPY, 0, 0);
1634
1635 /*Swap back to rich text*/
1636
1637 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
1638 SendMessageA(hwndRichEdit, EM_SETTEXTMODE, TM_RICHTEXT, 0);
1639
1640 /*Set the default formatting to bold italics*/
1641
1642 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2);
1643 cf2.dwMask |= CFM_ITALIC;
1644 cf2.dwEffects ^= CFE_ITALIC;
1645 rc = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2);
1646 ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
1647
1648 /*Set the text in the control to "wine", which will be bold and italicized*/
1649
1650 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"wine");
1651
1652 /*Paste the plain text "wine" string, which should take the insert
1653 formatting, which at the moment is bold italics*/
1654
1655 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
1656
1657 /*Select the first "wine" string and retrieve its formatting*/
1658
1659 cr.cpMin = 1;
1660 cr.cpMax = 3;
1661 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1662 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
1663
1664 /*Select the second "wine" string and retrieve its formatting*/
1665
1666 cr.cpMin = 5;
1667 cr.cpMax = 7;
1668 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1669 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2test);
1670
1671 /*Compare the two formattings. They should be the same.*/
1672
1673 ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
1674 "Copied text retained formatting - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
1675 cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
1676 DestroyWindow(hwndRichEdit);
1677}
1678
1679static void test_WM_GETTEXT(void)
1680{
1681 HWND hwndRichEdit = new_richedit(NULL);
1682 static const char text[] = "Hello. My name is RichEdit!";
1683 static const char text2[] = "Hello. My name is RichEdit!\r";
1684 static const char text2_after[] = "Hello. My name is RichEdit!\r\n";
1685 char buffer[1024] = {0};
1686 int result;
1687
1688 /* Baseline test with normal-sized buffer */
1689 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
1690 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
1692 "WM_GETTEXT returned %d, expected %d\n", result, lstrlenA(buffer));
1693 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
1695 ok(result == 0,
1696 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
1697
1698 /* Test for returned value of WM_GETTEXTLENGTH */
1699 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
1700 ok(result == lstrlenA(text),
1701 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
1702 result, lstrlenA(text));
1703
1704 /* Test for behavior in overflow case */
1705 memset(buffer, 0, 1024);
1706 result = SendMessageA(hwndRichEdit, WM_GETTEXT, strlen(text), (LPARAM)buffer);
1707 ok(result == 0 ||
1708 result == lstrlenA(text) - 1, /* XP, win2k3 */
1709 "WM_GETTEXT returned %d, expected 0 or %d\n", result, lstrlenA(text) - 1);
1711 if (result)
1712 result = strncmp(buffer, text, lstrlenA(text) - 1); /* XP, win2k3 */
1713 ok(result == 0,
1714 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
1715
1716 /* Baseline test with normal-sized buffer and carriage return */
1717 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
1718 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
1720 "WM_GETTEXT returned %d, expected %d\n", result, lstrlenA(buffer));
1721 result = strcmp(buffer,text2_after);
1722 ok(result == 0,
1723 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
1724
1725 /* Test for returned value of WM_GETTEXTLENGTH */
1726 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
1727 ok(result == lstrlenA(text2_after),
1728 "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
1729 result, lstrlenA(text2_after));
1730
1731 /* Test for behavior of CRLF conversion in case of overflow */
1732 memset(buffer, 0, 1024);
1733 result = SendMessageA(hwndRichEdit, WM_GETTEXT, strlen(text2), (LPARAM)buffer);
1734 ok(result == 0 ||
1735 result == lstrlenA(text2) - 1, /* XP, win2k3 */
1736 "WM_GETTEXT returned %d, expected 0 or %d\n", result, lstrlenA(text2) - 1);
1737 result = strcmp(buffer,text2);
1738 if (result)
1739 result = strncmp(buffer, text2, lstrlenA(text2) - 1); /* XP, win2k3 */
1740 ok(result == 0,
1741 "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
1742
1743 DestroyWindow(hwndRichEdit);
1744}
1745
1746static void test_EM_GETTEXTRANGE(void)
1747{
1748 HWND hwndRichEdit = new_richedit(NULL);
1749 const char * text1 = "foo bar\r\nfoo bar";
1750 const char * text2 = "foo bar\rfoo bar";
1751 const char * expect = "bar\rfoo";
1752 char buffer[1024] = {0};
1754 TEXTRANGEA textRange;
1755
1756 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
1757
1758 textRange.lpstrText = buffer;
1759 textRange.chrg.cpMin = 4;
1760 textRange.chrg.cpMax = 11;
1761 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1762 ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result);
1763 ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1764
1765 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
1766
1767 textRange.lpstrText = buffer;
1768 textRange.chrg.cpMin = 4;
1769 textRange.chrg.cpMax = 11;
1770 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1771 ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result);
1772 ok(!strcmp(expect, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1773
1774 /* cpMax of text length is used instead of -1 in this case */
1775 textRange.lpstrText = buffer;
1776 textRange.chrg.cpMin = 0;
1777 textRange.chrg.cpMax = -1;
1778 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1779 ok(result == strlen(text2), "EM_GETTEXTRANGE returned %ld\n", result);
1780 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1781
1782 /* cpMin < 0 causes no text to be copied, and 0 to be returned */
1783 textRange.lpstrText = buffer;
1784 textRange.chrg.cpMin = -1;
1785 textRange.chrg.cpMax = 1;
1786 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1787 ok(result == 0, "EM_GETTEXTRANGE returned %ld\n", result);
1788 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1789
1790 /* cpMax of -1 is not replaced with text length if cpMin != 0 */
1791 textRange.lpstrText = buffer;
1792 textRange.chrg.cpMin = 1;
1793 textRange.chrg.cpMax = -1;
1794 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1795 ok(result == 0, "EM_GETTEXTRANGE returned %ld\n", result);
1796 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1797
1798 /* no end character is copied if cpMax - cpMin < 0 */
1799 textRange.lpstrText = buffer;
1800 textRange.chrg.cpMin = 5;
1801 textRange.chrg.cpMax = 5;
1802 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1803 ok(result == 0, "EM_GETTEXTRANGE returned %ld\n", result);
1804 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1805
1806 /* cpMax of text length is used if cpMax > text length*/
1807 textRange.lpstrText = buffer;
1808 textRange.chrg.cpMin = 0;
1809 textRange.chrg.cpMax = 1000;
1810 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1811 ok(result == strlen(text2), "EM_GETTEXTRANGE returned %ld\n", result);
1812 ok(!strcmp(text2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1813
1814 /* Test with multibyte character */
1815 if (!is_lang_japanese)
1816 skip("Skip multibyte character tests on non-Japanese platform\n");
1817 else
1818 {
1819 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk");
1820 textRange.chrg.cpMin = 4;
1821 textRange.chrg.cpMax = 8;
1822 result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
1823 ok(result == 5, "EM_GETTEXTRANGE returned %ld\n", result);
1824 ok(!strcmp("ef\x8e\xf0g", buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
1825 }
1826
1827 DestroyWindow(hwndRichEdit);
1828}
1829
1830static void test_EM_GETSELTEXT(void)
1831{
1832 HWND hwndRichEdit = new_richedit(NULL);
1833 const char * text1 = "foo bar\r\nfoo bar";
1834 const char * text2 = "foo bar\rfoo bar";
1835 const char * expect = "bar\rfoo";
1836 char buffer[1024] = {0};
1838
1839 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
1840
1841 SendMessageA(hwndRichEdit, EM_SETSEL, 4, 11);
1842 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
1843 ok(result == 7, "EM_GETSELTEXT returned %ld\n", result);
1844 ok(!strcmp(expect, buffer), "EM_GETSELTEXT filled %s\n", buffer);
1845
1846 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
1847
1848 SendMessageA(hwndRichEdit, EM_SETSEL, 4, 11);
1849 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
1850 ok(result == 7, "EM_GETSELTEXT returned %ld\n", result);
1851 ok(!strcmp(expect, buffer), "EM_GETSELTEXT filled %s\n", buffer);
1852
1853 /* Test with multibyte character */
1854 if (!is_lang_japanese)
1855 skip("Skip multibyte character tests on non-Japanese platform\n");
1856 else
1857 {
1858 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk");
1859 SendMessageA(hwndRichEdit, EM_SETSEL, 4, 8);
1860 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
1861 ok(result == 5, "EM_GETSELTEXT returned %ld\n", result);
1862 ok(!strcmp("ef\x8e\xf0g", buffer), "EM_GETSELTEXT filled %s\n", buffer);
1863 }
1864
1865 DestroyWindow(hwndRichEdit);
1866}
1867
1868/* FIXME: need to test unimplemented options and robustly test wparam */
1869static void test_EM_SETOPTIONS(void)
1870{
1871 HWND hwndRichEdit;
1872 static const char text[] = "Hello. My name is RichEdit!";
1873 char buffer[1024] = {0};
1874 DWORD dwStyle, options, oldOptions;
1878
1879 /* Test initial options. */
1881 0, 0, 200, 60, NULL, NULL,
1883 ok(hwndRichEdit != NULL, "class: %s, error: %d\n",
1885 options = SendMessageA(hwndRichEdit, EM_GETOPTIONS, 0, 0);
1886 ok(options == 0, "Incorrect initial options %x\n", options);
1887 DestroyWindow(hwndRichEdit);
1888
1889 hwndRichEdit = CreateWindowA(RICHEDIT_CLASS20A, NULL,
1891 0, 0, 200, 60, NULL, NULL,
1893 ok(hwndRichEdit != NULL, "class: %s, error: %d\n",
1895 disable_beep( hwndRichEdit );
1896 options = SendMessageA(hwndRichEdit, EM_GETOPTIONS, 0, 0);
1897 /* WS_[VH]SCROLL cause the ECO_AUTO[VH]SCROLL options to be set */
1899 "Incorrect initial options %x\n", options);
1900
1901 /* NEGATIVE TESTING - NO OPTIONS SET */
1902 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
1903 SendMessageA(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, 0);
1904
1905 /* testing no readonly by sending 'a' to the control*/
1906 SendMessageA(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
1907 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
1908 ok(buffer[0]=='a',
1909 "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text, buffer);
1910 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
1911
1912 /* READONLY - sending 'a' to the control */
1913 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
1915 SendMessageA(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
1916 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
1917 ok(buffer[0]==text[0],
1918 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer);
1919
1920 /* EM_SETOPTIONS changes the window style, but changing the
1921 * window style does not change the options. */
1922 dwStyle = GetWindowLongA(hwndRichEdit, GWL_STYLE);
1923 ok(dwStyle & ES_READONLY, "Readonly style not set by EM_SETOPTIONS\n");
1924 SetWindowLongA(hwndRichEdit, GWL_STYLE, dwStyle & ~ES_READONLY);
1925 options = SendMessageA(hwndRichEdit, EM_GETOPTIONS, 0, 0);
1926 ok(options & ES_READONLY, "Readonly option set by SetWindowLong\n");
1927 /* Confirm that the text is still read only. */
1928 SendMessageA(hwndRichEdit, WM_CHAR, 'a', ('a' << 16) | 0x0001);
1929 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
1930 ok(buffer[0]==text[0],
1931 "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer);
1932
1933 oldOptions = options;
1934 SetWindowLongA(hwndRichEdit, GWL_STYLE, dwStyle|optionStyles);
1935 options = SendMessageA(hwndRichEdit, EM_GETOPTIONS, 0, 0);
1936 ok(options == oldOptions,
1937 "Options set by SetWindowLong (%x -> %x)\n", oldOptions, options);
1938
1939 DestroyWindow(hwndRichEdit);
1940}
1941
1942static BOOL check_CFE_LINK_selection(HWND hwnd, int sel_start, int sel_end)
1943{
1944 CHARFORMAT2A text_format;
1945 text_format.cbSize = sizeof(text_format);
1946 SendMessageA(hwnd, EM_SETSEL, sel_start, sel_end);
1948 return (text_format.dwEffects & CFE_LINK) != 0;
1949}
1950
1951static void check_CFE_LINK_rcvd(HWND hwnd, BOOL is_url, const char * url)
1952{
1953 BOOL link_present = FALSE;
1954
1955 link_present = check_CFE_LINK_selection(hwnd, 0, 1);
1956 if (is_url)
1957 { /* control text is url; should get CFE_LINK */
1958 ok(link_present, "URL Case: CFE_LINK not set for [%s].\n", url);
1959 }
1960 else
1961 {
1962 ok(!link_present, "Non-URL Case: CFE_LINK set for [%s].\n", url);
1963 }
1964}
1965
1967 return new_window("Static", 0, parent);
1968}
1969
1970static void test_EM_AUTOURLDETECT(void)
1971{
1972 /* DO NOT change the properties of the first two elements. To shorten the
1973 tests, all tests after WM_SETTEXT test just the first two elements -
1974 one non-URL and one URL */
1975 struct urls_s {
1976 const char *text;
1977 BOOL is_url;
1978 } urls[12] = {
1979 {"winehq.org", FALSE},
1980 {"http://www.winehq.org", TRUE},
1981 {"http//winehq.org", FALSE},
1982 {"ww.winehq.org", FALSE},
1983 {"www.winehq.org", TRUE},
1984 {"ftp://192.168.1.1", TRUE},
1985 {"ftp//192.168.1.1", FALSE},
1986 {"mailto:your@email.com", TRUE},
1987 {"prospero:prosperoserver", TRUE},
1988 {"telnet:test", TRUE},
1989 {"news:newserver", TRUE},
1990 {"wais:waisserver", TRUE}
1991 };
1992
1993 int i, j;
1994 int urlRet=-1;
1995 HWND hwndRichEdit, parent;
1996
1997 /* All of the following should cause the URL to be detected */
1998 const char * templates_delim[] = {
1999 "This is some text with X on it",
2000 "This is some text with (X) on it",
2001 "This is some text with X\r on it",
2002 "This is some text with ---X--- on it",
2003 "This is some text with \"X\" on it",
2004 "This is some text with 'X' on it",
2005 "This is some text with 'X' on it",
2006 "This is some text with :X: on it",
2007
2008 "This text ends with X",
2009
2010 "This is some text with X) on it",
2011 "This is some text with X--- on it",
2012 "This is some text with X\" on it",
2013 "This is some text with X' on it",
2014 "This is some text with X: on it",
2015
2016 "This is some text with (X on it",
2017 "This is some text with \rX on it",
2018 "This is some text with ---X on it",
2019 "This is some text with \"X on it",
2020 "This is some text with 'X on it",
2021 "This is some text with :X on it",
2022 };
2023 /* None of these should cause the URL to be detected */
2024 const char * templates_non_delim[] = {
2025 "This is some text with |X| on it",
2026 "This is some text with *X* on it",
2027 "This is some text with /X/ on it",
2028 "This is some text with +X+ on it",
2029 "This is some text with %X% on it",
2030 "This is some text with #X# on it",
2031 "This is some text with @X@ on it",
2032 "This is some text with \\X\\ on it",
2033 "This is some text with |X on it",
2034 "This is some text with *X on it",
2035 "This is some text with /X on it",
2036 "This is some text with +X on it",
2037 "This is some text with %X on it",
2038 "This is some text with #X on it",
2039 "This is some text with @X on it",
2040 "This is some text with \\X on it",
2041 "This is some text with _X on it",
2042 };
2043 /* All of these cause the URL detection to be extended by one more byte,
2044 thus demonstrating that the tested character is considered as part
2045 of the URL. */
2046 const char * templates_xten_delim[] = {
2047 "This is some text with X| on it",
2048 "This is some text with X* on it",
2049 "This is some text with X/ on it",
2050 "This is some text with X+ on it",
2051 "This is some text with X% on it",
2052 "This is some text with X# on it",
2053 "This is some text with X@ on it",
2054 "This is some text with X\\ on it",
2055 "This is some text with X_ on it",
2056 };
2057 /* These delims act as neutral breaks. Whether the url is ended
2058 or not depends on the next non-neutral character. We'll test
2059 with Y unchanged, in which case the url should include the
2060 deliminator and the Y. We'll also test with the Y changed
2061 to a space, in which case the url stops before the
2062 deliminator. */
2063 const char * templates_neutral_delim[] = {
2064 "This is some text with X-Y on it",
2065 "This is some text with X--Y on it",
2066 "This is some text with X!Y on it",
2067 "This is some text with X[Y on it",
2068 "This is some text with X]Y on it",
2069 "This is some text with X{Y on it",
2070 "This is some text with X}Y on it",
2071 "This is some text with X(Y on it",
2072 "This is some text with X)Y on it",
2073 "This is some text with X\"Y on it",
2074 "This is some text with X;Y on it",
2075 "This is some text with X:Y on it",
2076 "This is some text with X'Y on it",
2077 "This is some text with X?Y on it",
2078 "This is some text with X<Y on it",
2079 "This is some text with X>Y on it",
2080 "This is some text with X.Y on it",
2081 "This is some text with X,Y on it",
2082 };
2083 char buffer[1024];
2084
2086 hwndRichEdit = new_richedit(parent);
2087 /* Try and pass EM_AUTOURLDETECT some test wParam values */
2088 urlRet=SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
2089 ok(urlRet==0, "Good wParam: urlRet is: %d\n", urlRet);
2090 urlRet=SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, 1, 0);
2091 ok(urlRet==0, "Good wParam2: urlRet is: %d\n", urlRet);
2092 /* Windows returns -2147024809 (0x80070057) on bad wParam values */
2093 urlRet=SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, 8, 0);
2094 ok(urlRet==E_INVALIDARG, "Bad wParam: urlRet is: %d\n", urlRet);
2095 urlRet=SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, (WPARAM)"h", (LPARAM)"h");
2096 ok(urlRet==E_INVALIDARG, "Bad wParam2: urlRet is: %d\n", urlRet);
2097 /* for each url, check the text to see if CFE_LINK effect is present */
2098 for (i = 0; i < ARRAY_SIZE(urls); i++) {
2099
2100 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
2101 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)urls[i].text);
2102 check_CFE_LINK_rcvd(hwndRichEdit, FALSE, urls[i].text);
2103
2104 /* Link detection should happen immediately upon WM_SETTEXT */
2105 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2106 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)urls[i].text);
2107 check_CFE_LINK_rcvd(hwndRichEdit, urls[i].is_url, urls[i].text);
2108 }
2109 DestroyWindow(hwndRichEdit);
2110
2111 /* Test detection of URLs within normal text - WM_SETTEXT case. */
2112 for (i = 0; i < ARRAY_SIZE(urls); i++) {
2113 hwndRichEdit = new_richedit(parent);
2114
2115 for (j = 0; j < ARRAY_SIZE(templates_delim); j++) {
2116 char * at_pos;
2117 int at_offset;
2118 int end_offset;
2119
2120 at_pos = strchr(templates_delim[j], 'X');
2121 at_offset = at_pos - templates_delim[j];
2122 memcpy(buffer, templates_delim[j], at_offset);
2123 buffer[at_offset] = '\0';
2124 strcat(buffer, urls[i].text);
2125 strcat(buffer, templates_delim[j] + at_offset + 1);
2126 end_offset = at_offset + strlen(urls[i].text);
2127
2128 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2129 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer);
2130
2131 /* This assumes no templates start with the URL itself, and that they
2132 have at least two characters before the URL text */
2133 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2134 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2135 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2136 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2137 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2138 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2139
2140 if (urls[i].is_url)
2141 {
2142 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2143 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2144 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2145 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2146 }
2147 else
2148 {
2149 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2150 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2151 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2152 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2153 }
2154 if (buffer[end_offset] != '\0')
2155 {
2156 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2157 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2158 if (buffer[end_offset +1] != '\0')
2159 {
2160 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2161 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2162 }
2163 }
2164 }
2165
2166 for (j = 0; j < ARRAY_SIZE(templates_non_delim); j++) {
2167 char * at_pos;
2168 int at_offset;
2169 int end_offset;
2170
2171 at_pos = strchr(templates_non_delim[j], 'X');
2172 at_offset = at_pos - templates_non_delim[j];
2173 memcpy(buffer, templates_non_delim[j], at_offset);
2174 buffer[at_offset] = '\0';
2175 strcat(buffer, urls[i].text);
2176 strcat(buffer, templates_non_delim[j] + at_offset + 1);
2177 end_offset = at_offset + strlen(urls[i].text);
2178
2179 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2180 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer);
2181
2182 /* This assumes no templates start with the URL itself, and that they
2183 have at least two characters before the URL text */
2184 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2185 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2186 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2187 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2188 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2189 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2190
2191 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2192 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2193 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2194 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2195 if (buffer[end_offset] != '\0')
2196 {
2197 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2198 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2199 if (buffer[end_offset +1] != '\0')
2200 {
2201 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2202 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2203 }
2204 }
2205 }
2206
2207 for (j = 0; j < ARRAY_SIZE(templates_xten_delim); j++) {
2208 char * at_pos;
2209 int at_offset;
2210 int end_offset;
2211
2212 at_pos = strchr(templates_xten_delim[j], 'X');
2213 at_offset = at_pos - templates_xten_delim[j];
2214 memcpy(buffer, templates_xten_delim[j], at_offset);
2215 buffer[at_offset] = '\0';
2216 strcat(buffer, urls[i].text);
2217 strcat(buffer, templates_xten_delim[j] + at_offset + 1);
2218 end_offset = at_offset + strlen(urls[i].text);
2219
2220 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2221 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer);
2222
2223 /* This assumes no templates start with the URL itself, and that they
2224 have at least two characters before the URL text */
2225 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2226 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2227 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2228 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2229 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2230 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2231
2232 if (urls[i].is_url)
2233 {
2234 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2235 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2236 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2237 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2238 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2239 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer);
2240 }
2241 else
2242 {
2243 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2244 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2245 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2246 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2247 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2248 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer);
2249 }
2250 if (buffer[end_offset +1] != '\0')
2251 {
2252 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2253 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset + 2, buffer);
2254 if (buffer[end_offset +2] != '\0')
2255 {
2256 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +2, end_offset +3),
2257 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +2, end_offset +3, buffer);
2258 }
2259 }
2260 }
2261
2262 for (j = 0; j < ARRAY_SIZE(templates_neutral_delim); j++) {
2263 char * at_pos, * end_pos;
2264 int at_offset;
2265 int end_offset;
2266
2267 if (!urls[i].is_url) continue;
2268
2269 at_pos = strchr(templates_neutral_delim[j], 'X');
2270 at_offset = at_pos - templates_neutral_delim[j];
2271 memcpy(buffer, templates_neutral_delim[j], at_offset);
2272 buffer[at_offset] = '\0';
2273 strcat(buffer, urls[i].text);
2274 strcat(buffer, templates_neutral_delim[j] + at_offset + 1);
2275
2276 end_pos = strchr(buffer, 'Y');
2277 end_offset = end_pos - buffer;
2278
2279 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2280 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer);
2281
2282 /* This assumes no templates start with the URL itself, and that they
2283 have at least two characters before the URL text */
2284 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2285 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2286 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2287 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2288 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2289 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2290
2291 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2292 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2293 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2294 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2295 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2296 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer);
2297
2298 *end_pos = ' ';
2299
2300 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2301 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buffer);
2302
2303 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2304 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2305 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2306 "CFE_LINK set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2307 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2308 "CFE_LINK set in (%d-%d), text: %s\n", end_offset, end_offset +1, buffer);
2309 }
2310
2311 DestroyWindow(hwndRichEdit);
2312 hwndRichEdit = NULL;
2313 }
2314
2315 /* Test detection of URLs within normal text - WM_CHAR case. */
2316 /* Test only the first two URL examples for brevity */
2317 for (i = 0; i < 2; i++) {
2318 hwndRichEdit = new_richedit(parent);
2319
2320 /* Also for brevity, test only the first three delimiters */
2321 for (j = 0; j < 3; j++) {
2322 char * at_pos;
2323 int at_offset;
2324 int end_offset;
2325 int u, v;
2326
2327 at_pos = strchr(templates_delim[j], 'X');
2328 at_offset = at_pos - templates_delim[j];
2329 end_offset = at_offset + strlen(urls[i].text);
2330
2331 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2332 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
2333 for (u = 0; templates_delim[j][u]; u++) {
2334 if (templates_delim[j][u] == '\r') {
2335 simulate_typing_characters(hwndRichEdit, "\r");
2336 } else if (templates_delim[j][u] != 'X') {
2337 SendMessageA(hwndRichEdit, WM_CHAR, templates_delim[j][u], 1);
2338 } else {
2339 for (v = 0; urls[i].text[v]; v++) {
2340 SendMessageA(hwndRichEdit, WM_CHAR, urls[i].text[v], 1);
2341 }
2342 }
2343 }
2344 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2345
2346 /* This assumes no templates start with the URL itself, and that they
2347 have at least two characters before the URL text */
2348 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2349 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2350 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2351 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2352 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2353 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2354
2355 if (urls[i].is_url)
2356 {
2357 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2358 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2359 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2360 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2361 }
2362 else
2363 {
2364 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2365 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2366 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2367 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2368 }
2369 if (buffer[end_offset] != '\0')
2370 {
2371 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2372 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2373 if (buffer[end_offset +1] != '\0')
2374 {
2375 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2376 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2377 }
2378 }
2379
2380 /* The following will insert a paragraph break after the first character
2381 of the URL candidate, thus breaking the URL. It is expected that the
2382 CFE_LINK attribute should break across both pieces of the URL */
2383 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset+1, at_offset+1);
2384 simulate_typing_characters(hwndRichEdit, "\r");
2385 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2386
2387 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2388 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2389 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2390 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2391 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2392 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2393
2394 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2395 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2396 /* end_offset moved because of paragraph break */
2397 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2398 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset+1, buffer);
2399 ok(buffer[end_offset], "buffer \"%s\" ended prematurely. Is it missing a newline character?\n", buffer);
2400 if (buffer[end_offset] != 0 && buffer[end_offset+1] != '\0')
2401 {
2402 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset+1, end_offset +2),
2403 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset+1, end_offset +2, buffer);
2404 if (buffer[end_offset +2] != '\0')
2405 {
2406 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +2, end_offset +3),
2407 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +2, end_offset +3, buffer);
2408 }
2409 }
2410
2411 /* The following will remove the just-inserted paragraph break, thus
2412 restoring the URL */
2413 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset+2, at_offset+2);
2414 simulate_typing_characters(hwndRichEdit, "\b");
2415 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2416
2417 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2418 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2419 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2420 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2421 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2422 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2423
2424 if (urls[i].is_url)
2425 {
2426 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2427 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2428 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2429 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2430 }
2431 else
2432 {
2433 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2434 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2435 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2436 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2437 }
2438 if (buffer[end_offset] != '\0')
2439 {
2440 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2441 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2442 if (buffer[end_offset +1] != '\0')
2443 {
2444 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2445 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2446 }
2447 }
2448 }
2449 DestroyWindow(hwndRichEdit);
2450 hwndRichEdit = NULL;
2451 }
2452
2453 /* Test detection of URLs within normal text - EM_SETTEXTEX case. */
2454 /* Test just the first two URL examples for brevity */
2455 for (i = 0; i < 2; i++) {
2456 SETTEXTEX st;
2457
2458 hwndRichEdit = new_richedit(parent);
2459
2460 /* There are at least three ways in which EM_SETTEXTEX must cause URLs to
2461 be detected:
2462 1) Set entire text, a la WM_SETTEXT
2463 2) Set a selection of the text to the URL
2464 3) Set a portion of the text at a time, which eventually results in
2465 an URL
2466 All of them should give equivalent results
2467 */
2468
2469 /* Set entire text in one go, like WM_SETTEXT */
2470 for (j = 0; j < ARRAY_SIZE(templates_delim); j++) {
2471 char * at_pos;
2472 int at_offset;
2473 int end_offset;
2474
2475 st.codepage = CP_ACP;
2476 st.flags = ST_DEFAULT;
2477
2478 at_pos = strchr(templates_delim[j], 'X');
2479 at_offset = at_pos - templates_delim[j];
2480 memcpy(buffer, templates_delim[j], at_offset);
2481 buffer[at_offset] = '\0';
2482 strcat(buffer, urls[i].text);
2483 strcat(buffer, templates_delim[j] + at_offset + 1);
2484 end_offset = at_offset + strlen(urls[i].text);
2485
2486 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2487 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)buffer);
2488
2489 /* This assumes no templates start with the URL itself, and that they
2490 have at least two characters before the URL text */
2491 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2492 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2493 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2494 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2495 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2496 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2497
2498 if (urls[i].is_url)
2499 {
2500 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2501 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2502 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2503 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2504 }
2505 else
2506 {
2507 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2508 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2509 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2510 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2511 }
2512 if (buffer[end_offset] != '\0')
2513 {
2514 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2515 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2516 if (buffer[end_offset +1] != '\0')
2517 {
2518 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2519 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2520 }
2521 }
2522 }
2523
2524 /* Set selection with X to the URL */
2525 for (j = 0; j < ARRAY_SIZE(templates_delim); j++) {
2526 char * at_pos;
2527 int at_offset;
2528 int end_offset;
2529
2530 at_pos = strchr(templates_delim[j], 'X');
2531 at_offset = at_pos - templates_delim[j];
2532 end_offset = at_offset + strlen(urls[i].text);
2533
2534 st.codepage = CP_ACP;
2535 st.flags = ST_DEFAULT;
2536 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2537 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)templates_delim[j]);
2538 st.flags = ST_SELECTION;
2539 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1);
2540 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)urls[i].text);
2541 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2542
2543 /* This assumes no templates start with the URL itself, and that they
2544 have at least two characters before the URL text */
2545 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2546 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2547 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2548 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2549 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2550 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2551
2552 if (urls[i].is_url)
2553 {
2554 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2555 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2556 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2557 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2558 }
2559 else
2560 {
2561 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2562 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2563 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2564 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2565 }
2566 if (buffer[end_offset] != '\0')
2567 {
2568 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2569 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2570 if (buffer[end_offset +1] != '\0')
2571 {
2572 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2573 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2574 }
2575 }
2576 }
2577
2578 /* Set selection with X to the first character of the URL, then the rest */
2579 for (j = 0; j < ARRAY_SIZE(templates_delim); j++) {
2580 char * at_pos;
2581 int at_offset;
2582 int end_offset;
2583
2584 at_pos = strchr(templates_delim[j], 'X');
2585 at_offset = at_pos - templates_delim[j];
2586 end_offset = at_offset + strlen(urls[i].text);
2587
2588 strcpy(buffer, "YY");
2589 buffer[0] = urls[i].text[0];
2590
2591 st.codepage = CP_ACP;
2592 st.flags = ST_DEFAULT;
2593 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2594 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)templates_delim[j]);
2595 st.flags = ST_SELECTION;
2596 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1);
2597 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)buffer);
2598 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset+1, at_offset+2);
2599 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)(urls[i].text + 1));
2600 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2601
2602 /* This assumes no templates start with the URL itself, and that they
2603 have at least two characters before the URL text */
2604 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2605 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2606 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2607 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2608 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2609 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2610
2611 if (urls[i].is_url)
2612 {
2613 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2614 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2615 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2616 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2617 }
2618 else
2619 {
2620 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2621 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2622 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2623 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2624 }
2625 if (buffer[end_offset] != '\0')
2626 {
2627 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2628 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2629 if (buffer[end_offset +1] != '\0')
2630 {
2631 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2632 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2633 }
2634 }
2635 }
2636
2637 DestroyWindow(hwndRichEdit);
2638 hwndRichEdit = NULL;
2639 }
2640
2641 /* Test detection of URLs within normal text - EM_REPLACESEL case. */
2642 /* Test just the first two URL examples for brevity */
2643 for (i = 0; i < 2; i++) {
2644 hwndRichEdit = new_richedit(parent);
2645
2646 /* Set selection with X to the URL */
2647 for (j = 0; j < ARRAY_SIZE(templates_delim); j++) {
2648 char * at_pos;
2649 int at_offset;
2650 int end_offset;
2651
2652 at_pos = strchr(templates_delim[j], 'X');
2653 at_offset = at_pos - templates_delim[j];
2654 end_offset = at_offset + strlen(urls[i].text);
2655
2656 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2657 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)templates_delim[j]);
2658 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1);
2659 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)urls[i].text);
2660 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2661
2662 /* This assumes no templates start with the URL itself, and that they
2663 have at least two characters before the URL text */
2664 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2665 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2666 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2667 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2668 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2669 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2670
2671 if (urls[i].is_url)
2672 {
2673 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2674 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2675 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2676 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2677 }
2678 else
2679 {
2680 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2681 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2682 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2683 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2684 }
2685 if (buffer[end_offset] != '\0')
2686 {
2687 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2688 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2689 if (buffer[end_offset +1] != '\0')
2690 {
2691 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2692 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2693 }
2694 }
2695 }
2696
2697 /* Set selection with X to the first character of the URL, then the rest */
2698 for (j = 0; j < ARRAY_SIZE(templates_delim); j++) {
2699 char * at_pos;
2700 int at_offset;
2701 int end_offset;
2702
2703 at_pos = strchr(templates_delim[j], 'X');
2704 at_offset = at_pos - templates_delim[j];
2705 end_offset = at_offset + strlen(urls[i].text);
2706
2707 strcpy(buffer, "YY");
2708 buffer[0] = urls[i].text[0];
2709
2710 SendMessageA(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
2711 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)templates_delim[j]);
2712 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset, at_offset+1);
2713 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)buffer);
2714 SendMessageA(hwndRichEdit, EM_SETSEL, at_offset+1, at_offset+2);
2715 SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)(urls[i].text + 1));
2716 SendMessageA(hwndRichEdit, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2717
2718 /* This assumes no templates start with the URL itself, and that they
2719 have at least two characters before the URL text */
2720 ok(!check_CFE_LINK_selection(hwndRichEdit, 0, 1),
2721 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", 0, 1, buffer);
2722 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -2, at_offset -1),
2723 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -2, at_offset -1, buffer);
2724 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset -1, at_offset),
2725 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset -1, at_offset, buffer);
2726
2727 if (urls[i].is_url)
2728 {
2729 ok(check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2730 "CFE_LINK not set in (%d-%d), text: %s\n", at_offset, at_offset +1, buffer);
2731 ok(check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2732 "CFE_LINK not set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2733 }
2734 else
2735 {
2736 ok(!check_CFE_LINK_selection(hwndRichEdit, at_offset, at_offset +1),
2737 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", at_offset, at_offset + 1, buffer);
2738 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset -1, end_offset),
2739 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset -1, end_offset, buffer);
2740 }
2741 if (buffer[end_offset] != '\0')
2742 {
2743 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset, end_offset +1),
2744 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset, end_offset + 1, buffer);
2745 if (buffer[end_offset +1] != '\0')
2746 {
2747 ok(!check_CFE_LINK_selection(hwndRichEdit, end_offset +1, end_offset +2),
2748 "CFE_LINK incorrectly set in (%d-%d), text: %s\n", end_offset +1, end_offset +2, buffer);
2749 }
2750 }
2751 }
2752
2753 DestroyWindow(hwndRichEdit);
2754 hwndRichEdit = NULL;
2755 }
2756
2758}
2759
2760static void test_EM_SCROLL(void)
2761{
2762 int i, j;
2763 int r; /* return value */
2764 int expr; /* expected return value */
2765 HWND hwndRichEdit = new_richedit(NULL);
2766 int y_before, y_after; /* units of lines of text */
2767
2768 /* test a richedit box containing a single line of text */
2769 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");/* one line of text */
2770 expr = 0x00010000;
2771 for (i = 0; i < 4; i++) {
2772 static const int cmd[4] = { SB_PAGEDOWN, SB_PAGEUP, SB_LINEDOWN, SB_LINEUP };
2773
2774 r = SendMessageA(hwndRichEdit, EM_SCROLL, cmd[i], 0);
2775 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2776 ok(expr == r, "EM_SCROLL improper return value returned (i == %d). "
2777 "Got 0x%08x, expected 0x%08x\n", i, r, expr);
2778 ok(y_after == 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 "
2779 "(i == %d)\n", y_after, i);
2780 }
2781
2782 /*
2783 * test a richedit box that will scroll. There are two general
2784 * cases: the case without any long lines and the case with a long
2785 * line.
2786 */
2787 for (i = 0; i < 2; i++) { /* iterate through different bodies of text */
2788 if (i == 0)
2789 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a\nb\nc\nd\ne");
2790 else
2791 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)
2792 "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
2793 "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
2794 "LONG LINE \nb\nc\nd\ne");
2795 for (j = 0; j < 12; j++) /* reset scroll position to top */
2796 SendMessageA(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0);
2797
2798 /* get first visible line */
2799 y_before = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2800 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0); /* page down */
2801
2802 /* get new current first visible line */
2803 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2804
2805 ok(((r & 0xffffff00) == 0x00010000) &&
2806 ((r & 0x000000ff) != 0x00000000),
2807 "EM_SCROLL page down didn't scroll by a small positive number of "
2808 "lines (r == 0x%08x)\n", r);
2809 ok(y_after > y_before, "EM_SCROLL page down not functioning "
2810 "(line %d scrolled to line %d\n", y_before, y_after);
2811
2812 y_before = y_after;
2813
2814 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0); /* page up */
2815 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2816 ok(((r & 0xffffff00) == 0x0001ff00),
2817 "EM_SCROLL page up didn't scroll by a small negative number of lines "
2818 "(r == 0x%08x)\n", r);
2819 ok(y_after < y_before, "EM_SCROLL page up not functioning (line "
2820 "%d scrolled to line %d\n", y_before, y_after);
2821
2822 y_before = y_after;
2823
2824 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */
2825
2826 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2827
2828 ok(r == 0x00010001, "EM_SCROLL line down didn't scroll by one line "
2829 "(r == 0x%08x)\n", r);
2830 ok(y_after -1 == y_before, "EM_SCROLL line down didn't go down by "
2831 "1 line (%d scrolled to %d)\n", y_before, y_after);
2832
2833 y_before = y_after;
2834
2835 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */
2836
2837 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2838
2839 ok(r == 0x0001ffff, "EM_SCROLL line up didn't scroll by one line "
2840 "(r == 0x%08x)\n", r);
2841 ok(y_after +1 == y_before, "EM_SCROLL line up didn't go up by 1 "
2842 "line (%d scrolled to %d)\n", y_before, y_after);
2843
2844 y_before = y_after;
2845
2846 r = SendMessageA(hwndRichEdit, EM_SCROLL,
2847 SB_LINEUP, 0); /* lineup beyond top */
2848
2849 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2850
2851 ok(r == 0x00010000,
2852 "EM_SCROLL line up returned indicating movement (0x%08x)\n", r);
2853 ok(y_before == y_after,
2854 "EM_SCROLL line up beyond top worked (%d)\n", y_after);
2855
2856 y_before = y_after;
2857
2858 r = SendMessageA(hwndRichEdit, EM_SCROLL,
2859 SB_PAGEUP, 0);/*page up beyond top */
2860
2861 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2862
2863 ok(r == 0x00010000,
2864 "EM_SCROLL page up returned indicating movement (0x%08x)\n", r);
2865 ok(y_before == y_after,
2866 "EM_SCROLL page up beyond top worked (%d)\n", y_after);
2867
2868 for (j = 0; j < 12; j++) /* page down all the way to the bottom */
2869 SendMessageA(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0);
2870 y_before = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2871 r = SendMessageA(hwndRichEdit, EM_SCROLL,
2872 SB_PAGEDOWN, 0); /* page down beyond bot */
2873 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2874
2875 ok(r == 0x00010000,
2876 "EM_SCROLL page down returned indicating movement (0x%08x)\n", r);
2877 ok(y_before == y_after,
2878 "EM_SCROLL page down beyond bottom worked (%d -> %d)\n",
2879 y_before, y_after);
2880
2881 y_before = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2882 r = SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down beyond bot */
2883 y_after = SendMessageA(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
2884
2885 ok(r == 0x00010000,
2886 "EM_SCROLL line down returned indicating movement (0x%08x)\n", r);
2887 ok(y_before == y_after,
2888 "EM_SCROLL line down beyond bottom worked (%d -> %d)\n",
2889 y_before, y_after);
2890 }
2891 DestroyWindow(hwndRichEdit);
2892}
2893
2894static unsigned int recursionLevel = 0;
2895static unsigned int WM_SIZE_recursionLevel = 0;
2898
2900{
2901 LRESULT r;
2902
2903 if (bailedOutOfRecursion) return 0;
2904 if (recursionLevel >= 32) {
2906 return 0;
2907 }
2908
2910 switch (message) {
2911 case WM_SIZE:
2913 r = richeditProc(hwnd, message, wParam, lParam);
2914 /* Because, uhhhh... I never heard of ES_DISABLENOSCROLL */
2917 break;
2918 default:
2919 r = richeditProc(hwnd, message, wParam, lParam);
2920 break;
2921 }
2923 return r;
2924}
2925
2927{
2928 HWND hwndRichEdit;
2929 const char * text="a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n";
2930 SCROLLINFO si;
2931 WNDCLASSA cls;
2932 BOOL r;
2933
2934 /* These tests show that richedit should temporarily refrain from automatically
2935 hiding or showing its scrollbars (vertical at least) when an explicit request
2936 is made via ShowScrollBar() or similar, outside of standard richedit logic.
2937 Some applications depend on forced showing (when otherwise richedit would
2938 hide the vertical scrollbar) and are thrown on an endless recursive loop
2939 if richedit auto-hides the scrollbar again. Apparently they never heard of
2940 the ES_DISABLENOSCROLL style... */
2941
2942 hwndRichEdit = new_richedit(NULL);
2943
2944 /* Test default scrollbar visibility behavior */
2945 memset(&si, 0, sizeof(si));
2946 si.cbSize = sizeof(si);
2947 si.fMask = SIF_PAGE | SIF_RANGE;
2948 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2949 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2950 "Vertical scrollbar is visible, should be invisible.\n");
2951 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
2952 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2953 si.nPage, si.nMin, si.nMax);
2954
2955 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
2956 memset(&si, 0, sizeof(si));
2957 si.cbSize = sizeof(si);
2958 si.fMask = SIF_PAGE | SIF_RANGE;
2959 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2960 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2961 "Vertical scrollbar is visible, should be invisible.\n");
2962 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
2963 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
2964 si.nPage, si.nMin, si.nMax);
2965
2966 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
2967 memset(&si, 0, sizeof(si));
2968 si.cbSize = sizeof(si);
2969 si.fMask = SIF_PAGE | SIF_RANGE;
2970 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2971 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
2972 "Vertical scrollbar is invisible, should be visible.\n");
2973 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2974 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2975 si.nPage, si.nMin, si.nMax);
2976
2977 /* Oddly, setting text to NULL does *not* reset the scrollbar range,
2978 even though it hides the scrollbar */
2979 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
2980 memset(&si, 0, sizeof(si));
2981 si.cbSize = sizeof(si);
2982 si.fMask = SIF_PAGE | SIF_RANGE;
2983 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2984 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2985 "Vertical scrollbar is visible, should be invisible.\n");
2986 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2987 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
2988 si.nPage, si.nMin, si.nMax);
2989
2990 /* Setting non-scrolling text again does *not* reset scrollbar range */
2991 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
2992 memset(&si, 0, sizeof(si));
2993 si.cbSize = sizeof(si);
2994 si.fMask = SIF_PAGE | SIF_RANGE;
2995 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
2996 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
2997 "Vertical scrollbar is visible, should be invisible.\n");
2998 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
2999 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3000 si.nPage, si.nMin, si.nMax);
3001
3002 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3003 memset(&si, 0, sizeof(si));
3004 si.cbSize = sizeof(si);
3005 si.fMask = SIF_PAGE | SIF_RANGE;
3006 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3007 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3008 "Vertical scrollbar is visible, should be invisible.\n");
3009 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3010 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3011 si.nPage, si.nMin, si.nMax);
3012
3013 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
3014 memset(&si, 0, sizeof(si));
3015 si.cbSize = sizeof(si);
3016 si.fMask = SIF_PAGE | SIF_RANGE;
3017 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3018 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3019 "Vertical scrollbar is visible, should be invisible.\n");
3020 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3021 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3022 si.nPage, si.nMin, si.nMax);
3023
3024 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
3025 memset(&si, 0, sizeof(si));
3026 si.cbSize = sizeof(si);
3027 si.fMask = SIF_PAGE | SIF_RANGE;
3028 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3029 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3030 "Vertical scrollbar is visible, should be invisible.\n");
3031 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3032 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3033 si.nPage, si.nMin, si.nMax);
3034
3035 DestroyWindow(hwndRichEdit);
3036
3037 /* Test again, with ES_DISABLENOSCROLL style */
3039
3040 /* Test default scrollbar visibility behavior */
3041 memset(&si, 0, sizeof(si));
3042 si.cbSize = sizeof(si);
3043 si.fMask = SIF_PAGE | SIF_RANGE;
3044 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3045 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3046 "Vertical scrollbar is invisible, should be visible.\n");
3047 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 1,
3048 "reported page/range is %d (%d..%d) expected 0 (0..1)\n",
3049 si.nPage, si.nMin, si.nMax);
3050
3051 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3052 memset(&si, 0, sizeof(si));
3053 si.cbSize = sizeof(si);
3054 si.fMask = SIF_PAGE | SIF_RANGE;
3055 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3056 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3057 "Vertical scrollbar is invisible, should be visible.\n");
3058 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 1,
3059 "reported page/range is %d (%d..%d) expected 0 (0..1)\n",
3060 si.nPage, si.nMin, si.nMax);
3061
3062 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
3063 memset(&si, 0, sizeof(si));
3064 si.cbSize = sizeof(si);
3065 si.fMask = SIF_PAGE | SIF_RANGE;
3066 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3067 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3068 "Vertical scrollbar is invisible, should be visible.\n");
3069 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
3070 "reported page/range is %d (%d..%d)\n",
3071 si.nPage, si.nMin, si.nMax);
3072
3073 /* Oddly, setting text to NULL does *not* reset the scrollbar range */
3074 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3075 memset(&si, 0, sizeof(si));
3076 si.cbSize = sizeof(si);
3077 si.fMask = SIF_PAGE | SIF_RANGE;
3078 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3079 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3080 "Vertical scrollbar is invisible, should be visible.\n");
3081 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
3082 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3083 si.nPage, si.nMin, si.nMax);
3084
3085 /* Setting non-scrolling text again does *not* reset scrollbar range */
3086 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
3087 memset(&si, 0, sizeof(si));
3088 si.cbSize = sizeof(si);
3089 si.fMask = SIF_PAGE | SIF_RANGE;
3090 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3091 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3092 "Vertical scrollbar is invisible, should be visible.\n");
3093 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
3094 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3095 si.nPage, si.nMin, si.nMax);
3096
3097 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3098 memset(&si, 0, sizeof(si));
3099 si.cbSize = sizeof(si);
3100 si.fMask = SIF_PAGE | SIF_RANGE;
3101 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3102 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3103 "Vertical scrollbar is invisible, should be visible.\n");
3104 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
3105 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3106 si.nPage, si.nMin, si.nMax);
3107
3108 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
3109 memset(&si, 0, sizeof(si));
3110 si.cbSize = sizeof(si);
3111 si.fMask = SIF_PAGE | SIF_RANGE;
3112 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3113 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3114 "Vertical scrollbar is invisible, should be visible.\n");
3115 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
3116 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3117 si.nPage, si.nMin, si.nMax);
3118
3119 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
3120 memset(&si, 0, sizeof(si));
3121 si.cbSize = sizeof(si);
3122 si.fMask = SIF_PAGE | SIF_RANGE;
3123 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3124 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3125 "Vertical scrollbar is invisible, should be visible.\n");
3126 ok(si.nPage != 0 && si.nMin == 0 && si.nMax > 1,
3127 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3128 si.nPage, si.nMin, si.nMax);
3129
3130 DestroyWindow(hwndRichEdit);
3131
3132 /* Test behavior with explicit visibility request, using ShowScrollBar() */
3133 hwndRichEdit = new_richedit(NULL);
3134
3135 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */
3136 ShowScrollBar(hwndRichEdit, SB_VERT, TRUE);
3137 memset(&si, 0, sizeof(si));
3138 si.cbSize = sizeof(si);
3139 si.fMask = SIF_PAGE | SIF_RANGE;
3140 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3141 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3142 "Vertical scrollbar is invisible, should be visible.\n");
3143 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
3144 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
3145 si.nPage, si.nMin, si.nMax);
3146
3147 /* Ditto, see above */
3148 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3149 memset(&si, 0, sizeof(si));
3150 si.cbSize = sizeof(si);
3151 si.fMask = SIF_PAGE | SIF_RANGE;
3152 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3153 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3154 "Vertical scrollbar is invisible, should be visible.\n");
3155 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
3156 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
3157 si.nPage, si.nMin, si.nMax);
3158
3159 /* Ditto, see above */
3160 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
3161 memset(&si, 0, sizeof(si));
3162 si.cbSize = sizeof(si);
3163 si.fMask = SIF_PAGE | SIF_RANGE;
3164 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3165 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3166 "Vertical scrollbar is invisible, should be visible.\n");
3167 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
3168 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
3169 si.nPage, si.nMin, si.nMax);
3170
3171 /* Ditto, see above */
3172 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a\na");
3173 memset(&si, 0, sizeof(si));
3174 si.cbSize = sizeof(si);
3175 si.fMask = SIF_PAGE | SIF_RANGE;
3176 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3177 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3178 "Vertical scrollbar is invisible, should be visible.\n");
3179 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
3180 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
3181 si.nPage, si.nMin, si.nMax);
3182
3183 /* Ditto, see above */
3184 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3185 memset(&si, 0, sizeof(si));
3186 si.cbSize = sizeof(si);
3187 si.fMask = SIF_PAGE | SIF_RANGE;
3188 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3189 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3190 "Vertical scrollbar is invisible, should be visible.\n");
3191 ok(si.nPage == 0 && si.nMin == 0 && si.nMax == 100,
3192 "reported page/range is %d (%d..%d) expected 0 (0..100)\n",
3193 si.nPage, si.nMin, si.nMax);
3194
3195 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
3196 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3197 memset(&si, 0, sizeof(si));
3198 si.cbSize = sizeof(si);
3199 si.fMask = SIF_PAGE | SIF_RANGE;
3200 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3201 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3202 "Vertical scrollbar is visible, should be invisible.\n");
3203 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3204 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3205 si.nPage, si.nMin, si.nMax);
3206
3207 DestroyWindow(hwndRichEdit);
3208
3209 hwndRichEdit = new_richedit(NULL);
3210
3211 ShowScrollBar(hwndRichEdit, SB_VERT, FALSE);
3212 memset(&si, 0, sizeof(si));
3213 si.cbSize = sizeof(si);
3214 si.fMask = SIF_PAGE | SIF_RANGE;
3215 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3216 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3217 "Vertical scrollbar is visible, should be invisible.\n");
3218 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3219 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3220 si.nPage, si.nMin, si.nMax);
3221
3222 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3223 memset(&si, 0, sizeof(si));
3224 si.cbSize = sizeof(si);
3225 si.fMask = SIF_PAGE | SIF_RANGE;
3226 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3227 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3228 "Vertical scrollbar is visible, should be invisible.\n");
3229 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3230 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3231 si.nPage, si.nMin, si.nMax);
3232
3233 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
3234 memset(&si, 0, sizeof(si));
3235 si.cbSize = sizeof(si);
3236 si.fMask = SIF_PAGE | SIF_RANGE;
3237 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3238 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3239 "Vertical scrollbar is visible, should be invisible.\n");
3240 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3241 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3242 si.nPage, si.nMin, si.nMax);
3243
3244 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3245 memset(&si, 0, sizeof(si));
3246 si.cbSize = sizeof(si);
3247 si.fMask = SIF_PAGE | SIF_RANGE;
3248 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3249 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3250 "Vertical scrollbar is visible, should be invisible.\n");
3251 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3252 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3253 si.nPage, si.nMin, si.nMax);
3254
3255 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
3256 memset(&si, 0, sizeof(si));
3257 si.cbSize = sizeof(si);
3258 si.fMask = SIF_PAGE | SIF_RANGE;
3259 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3260 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3261 "Vertical scrollbar is invisible, should be visible.\n");
3262 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3263 "reported page/range is %d (%d..%d)\n",
3264 si.nPage, si.nMin, si.nMax);
3265
3266 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */
3267 ShowScrollBar(hwndRichEdit, SB_VERT, FALSE);
3268 memset(&si, 0, sizeof(si));
3269 si.cbSize = sizeof(si);
3270 si.fMask = SIF_PAGE | SIF_RANGE;
3271 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3272 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3273 "Vertical scrollbar is visible, should be invisible.\n");
3274 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3275 "reported page/range is %d (%d..%d)\n",
3276 si.nPage, si.nMin, si.nMax);
3277
3278 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
3279 memset(&si, 0, sizeof(si));
3280 si.cbSize = sizeof(si);
3281 si.fMask = SIF_PAGE | SIF_RANGE;
3282 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3283 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3284 "Vertical scrollbar is visible, should be invisible.\n");
3285 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3286 "reported page/range is %d (%d..%d)\n",
3287 si.nPage, si.nMin, si.nMax);
3288
3289 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that
3290 EM_SCROLL will make visible any forcefully invisible scrollbar */
3291 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0);
3292 memset(&si, 0, sizeof(si));
3293 si.cbSize = sizeof(si);
3294 si.fMask = SIF_PAGE | SIF_RANGE;
3295 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3296 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3297 "Vertical scrollbar is invisible, should be visible.\n");
3298 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3299 "reported page/range is %d (%d..%d)\n",
3300 si.nPage, si.nMin, si.nMax);
3301
3302 ShowScrollBar(hwndRichEdit, SB_VERT, FALSE);
3303 memset(&si, 0, sizeof(si));
3304 si.cbSize = sizeof(si);
3305 si.fMask = SIF_PAGE | SIF_RANGE;
3306 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3307 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3308 "Vertical scrollbar is visible, should be invisible.\n");
3309 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3310 "reported page/range is %d (%d..%d)\n",
3311 si.nPage, si.nMin, si.nMax);
3312
3313 /* Again, EM_SCROLL, with SB_LINEUP */
3314 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0);
3315 memset(&si, 0, sizeof(si));
3316 si.cbSize = sizeof(si);
3317 si.fMask = SIF_PAGE | SIF_RANGE;
3318 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3319 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3320 "Vertical scrollbar is invisible, should be visible.\n");
3321 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3322 "reported page/range is %d (%d..%d)\n",
3323 si.nPage, si.nMin, si.nMax);
3324
3325 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3326 memset(&si, 0, sizeof(si));
3327 si.cbSize = sizeof(si);
3328 si.fMask = SIF_PAGE | SIF_RANGE;
3329 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3330 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3331 "Vertical scrollbar is visible, should be invisible.\n");
3332 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3333 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3334 si.nPage, si.nMin, si.nMax);
3335
3336 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
3337 memset(&si, 0, sizeof(si));
3338 si.cbSize = sizeof(si);
3339 si.fMask = SIF_PAGE | SIF_RANGE;
3340 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3341 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3342 "Vertical scrollbar is invisible, should be visible.\n");
3343 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3344 "reported page/range is %d (%d..%d)\n",
3345 si.nPage, si.nMin, si.nMax);
3346
3347 DestroyWindow(hwndRichEdit);
3348
3349
3350 /* Test behavior with explicit visibility request, using SetWindowLongA()() */
3351 hwndRichEdit = new_richedit(NULL);
3352
3353#define ENABLE_WS_VSCROLL(hwnd) \
3354 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) | WS_VSCROLL)
3355#define DISABLE_WS_VSCROLL(hwnd) \
3356 SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) & ~WS_VSCROLL)
3357
3358 /* Previously failed because builtin incorrectly re-hides scrollbar forced visible */
3359 ENABLE_WS_VSCROLL(hwndRichEdit);
3360 memset(&si, 0, sizeof(si));
3361 si.cbSize = sizeof(si);
3362 si.fMask = SIF_PAGE | SIF_RANGE;
3363 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3364 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3365 "Vertical scrollbar is invisible, should be visible.\n");
3366 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3367 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3368 si.nPage, si.nMin, si.nMax);
3369
3370 /* Ditto, see above */
3371 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3372 memset(&si, 0, sizeof(si));
3373 si.cbSize = sizeof(si);
3374 si.fMask = SIF_PAGE | SIF_RANGE;
3375 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3376 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3377 "Vertical scrollbar is invisible, should be visible.\n");
3378 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3379 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3380 si.nPage, si.nMin, si.nMax);
3381
3382 /* Ditto, see above */
3383 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
3384 memset(&si, 0, sizeof(si));
3385 si.cbSize = sizeof(si);
3386 si.fMask = SIF_PAGE | SIF_RANGE;
3387 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3388 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3389 "Vertical scrollbar is invisible, should be visible.\n");
3390 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3391 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3392 si.nPage, si.nMin, si.nMax);
3393
3394 /* Ditto, see above */
3395 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a\na");
3396 memset(&si, 0, sizeof(si));
3397 si.cbSize = sizeof(si);
3398 si.fMask = SIF_PAGE | SIF_RANGE;
3399 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3400 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3401 "Vertical scrollbar is invisible, should be visible.\n");
3402 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3403 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3404 si.nPage, si.nMin, si.nMax);
3405
3406 /* Ditto, see above */
3407 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3408 memset(&si, 0, sizeof(si));
3409 si.cbSize = sizeof(si);
3410 si.fMask = SIF_PAGE | SIF_RANGE;
3411 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3412 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3413 "Vertical scrollbar is invisible, should be visible.\n");
3414 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3415 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3416 si.nPage, si.nMin, si.nMax);
3417
3418 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
3419 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3420 memset(&si, 0, sizeof(si));
3421 si.cbSize = sizeof(si);
3422 si.fMask = SIF_PAGE | SIF_RANGE;
3423 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3424 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3425 "Vertical scrollbar is visible, should be invisible.\n");
3426 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3427 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3428 si.nPage, si.nMin, si.nMax);
3429
3430 DestroyWindow(hwndRichEdit);
3431
3432 hwndRichEdit = new_richedit(NULL);
3433
3434 DISABLE_WS_VSCROLL(hwndRichEdit);
3435 memset(&si, 0, sizeof(si));
3436 si.cbSize = sizeof(si);
3437 si.fMask = SIF_PAGE | SIF_RANGE;
3438 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3439 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3440 "Vertical scrollbar is visible, should be invisible.\n");
3441 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3442 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3443 si.nPage, si.nMin, si.nMax);
3444
3445 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3446 memset(&si, 0, sizeof(si));
3447 si.cbSize = sizeof(si);
3448 si.fMask = SIF_PAGE | SIF_RANGE;
3449 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3450 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3451 "Vertical scrollbar is visible, should be invisible.\n");
3452 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3453 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3454 si.nPage, si.nMin, si.nMax);
3455
3456 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
3457 memset(&si, 0, sizeof(si));
3458 si.cbSize = sizeof(si);
3459 si.fMask = SIF_PAGE | SIF_RANGE;
3460 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3461 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3462 "Vertical scrollbar is visible, should be invisible.\n");
3463 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3464 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3465 si.nPage, si.nMin, si.nMax);
3466
3467 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3468 memset(&si, 0, sizeof(si));
3469 si.cbSize = sizeof(si);
3470 si.fMask = SIF_PAGE | SIF_RANGE;
3471 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3472 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3473 "Vertical scrollbar is visible, should be invisible.\n");
3474 ok(si.nPage == 0 && si.nMin == 0 && (si.nMax == 0 || si.nMax == 100),
3475 "reported page/range is %d (%d..%d) expected all 0 or nMax=100\n",
3476 si.nPage, si.nMin, si.nMax);
3477
3478 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
3479 memset(&si, 0, sizeof(si));
3480 si.cbSize = sizeof(si);
3481 si.fMask = SIF_PAGE | SIF_RANGE;
3482 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3483 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3484 "Vertical scrollbar is invisible, should be visible.\n");
3485 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3486 "reported page/range is %d (%d..%d)\n",
3487 si.nPage, si.nMin, si.nMax);
3488
3489 /* Previously, builtin incorrectly re-shows explicitly hidden scrollbar */
3490 DISABLE_WS_VSCROLL(hwndRichEdit);
3491 memset(&si, 0, sizeof(si));
3492 si.cbSize = sizeof(si);
3493 si.fMask = SIF_PAGE | SIF_RANGE;
3494 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3495 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3496 "Vertical scrollbar is visible, should be invisible.\n");
3497 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3498 "reported page/range is %d (%d..%d)\n",
3499 si.nPage, si.nMin, si.nMax);
3500
3501 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
3502 memset(&si, 0, sizeof(si));
3503 si.cbSize = sizeof(si);
3504 si.fMask = SIF_PAGE | SIF_RANGE;
3505 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3506 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3507 "Vertical scrollbar is visible, should be invisible.\n");
3508 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3509 "reported page/range is %d (%d..%d) expected nMax/nPage nonzero\n",
3510 si.nPage, si.nMin, si.nMax);
3511
3512 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
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 invisible, should be visible.\n");
3519 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3520 "reported page/range is %d (%d..%d)\n",
3521 si.nPage, si.nMin, si.nMax);
3522
3523 DISABLE_WS_VSCROLL(hwndRichEdit);
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,
3531 "reported page/range is %d (%d..%d)\n",
3532 si.nPage, si.nMin, si.nMax);
3533
3534 /* Testing effect of EM_SCROLL on scrollbar visibility. It seems that
3535 EM_SCROLL will make visible any forcefully invisible scrollbar */
3536 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0);
3537 memset(&si, 0, sizeof(si));
3538 si.cbSize = sizeof(si);
3539 si.fMask = SIF_PAGE | SIF_RANGE;
3540 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3541 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3542 "Vertical scrollbar is invisible, should be visible.\n");
3543 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3544 "reported page/range is %d (%d..%d)\n",
3545 si.nPage, si.nMin, si.nMax);
3546
3547 DISABLE_WS_VSCROLL(hwndRichEdit);
3548 memset(&si, 0, sizeof(si));
3549 si.cbSize = sizeof(si);
3550 si.fMask = SIF_PAGE | SIF_RANGE;
3551 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3552 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) == 0),
3553 "Vertical scrollbar is visible, should be invisible.\n");
3554 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3555 "reported page/range is %d (%d..%d)\n",
3556 si.nPage, si.nMin, si.nMax);
3557
3558 /* Again, EM_SCROLL, with SB_LINEUP */
3559 SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0);
3560 memset(&si, 0, sizeof(si));
3561 si.cbSize = sizeof(si);
3562 si.fMask = SIF_PAGE | SIF_RANGE;
3563 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
3564 ok (((GetWindowLongA(hwndRichEdit, GWL_STYLE) & WS_VSCROLL) != 0),
3565 "Vertical scrollbar is invisible, should be visible.\n");
3566 ok(si.nPage != 0 && si.nMin == 0 && si.nMax != 0,
3567 "reported page/range is %d (%d..%d)\n",
3568 si.nPage, si.nMin, si.nMax);
3569
3570 DestroyWindow(hwndRichEdit);
3571
3572 /* This window proc models what is going on with Corman Lisp 3.0.
3573 At WM_SIZE, this proc unconditionally calls ShowScrollBar() to
3574 force the scrollbar into visibility. Recursion should NOT happen
3575 as a result of this action.
3576 */
3578 if (r) {
3579 richeditProc = cls.lpfnWndProc;
3581 cls.lpszClassName = "RicheditStupidOverride";
3582 if(!RegisterClassA(&cls)) assert(0);
3583
3584 recursionLevel = 0;
3587 hwndRichEdit = new_window(cls.lpszClassName, ES_MULTILINE, NULL);
3589 "WM_SIZE/scrollbar mutual recursion detected, expected none!\n");
3590
3591 recursionLevel = 0;
3594 MoveWindow(hwndRichEdit, 0, 0, 250, 100, TRUE);
3596 "WM_SIZE/scrollbar mutual recursion detected, expected none!\n");
3597
3598 /* Unblock window in order to process WM_DESTROY */
3599 recursionLevel = 0;
3602 DestroyWindow(hwndRichEdit);
3603 }
3604}
3605
3606static void test_EM_SETUNDOLIMIT(void)
3607{
3608 /* cases we test for:
3609 * default behaviour - limiting at 100 undo's
3610 * undo disabled - setting a limit of 0
3611 * undo limited - undo limit set to some to some number, like 2
3612 * bad input - sending a negative number should default to 100 undo's */
3613
3614 HWND hwndRichEdit = new_richedit(NULL);
3615 CHARRANGE cr;
3616 int i;
3617 int result;
3618
3619 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"x");
3620 cr.cpMin = 0;
3621 cr.cpMax = -1;
3622 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
3623
3624 SendMessageA(hwndRichEdit, WM_COPY, 0, 0);
3625 /*Load "x" into the clipboard. Paste is an easy, undo'able operation.
3626 also, multiple pastes don't combine like WM_CHAR would */
3627
3628 /* first case - check the default */
3629 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
3630 for (i=0; i<101; i++) /* Put 101 undo's on the stack */
3631 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
3632 for (i=0; i<100; i++) /* Undo 100 of them */
3633 SendMessageA(hwndRichEdit, WM_UNDO, 0, 0);
3634 ok(!SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0),
3635 "EM_SETUNDOLIMIT allowed more than a hundred undo's by default.\n");
3636
3637 /* second case - cannot undo */
3638 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0);
3639 SendMessageA(hwndRichEdit, EM_SETUNDOLIMIT, 0, 0);
3640 SendMessageA(hwndRichEdit,
3641 WM_PASTE, 0, 0); /* Try to put something in the undo stack */
3642 ok(!SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0),
3643 "EM_SETUNDOLIMIT allowed undo with UNDOLIMIT set to 0\n");
3644
3645 /* third case - set it to an arbitrary number */
3646 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0);
3647 SendMessageA(hwndRichEdit, EM_SETUNDOLIMIT, 2, 0);
3648 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
3649 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
3650 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
3651 /* If SETUNDOLIMIT is working, there should only be two undo's after this */
3652 ok(SendMessageA(hwndRichEdit, EM_CANUNDO, 0,0),
3653 "EM_SETUNDOLIMIT didn't allow the first undo with UNDOLIMIT set to 2\n");
3654 SendMessageA(hwndRichEdit, WM_UNDO, 0, 0);
3655 ok(SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0),
3656 "EM_SETUNDOLIMIT didn't allow a second undo with UNDOLIMIT set to 2\n");
3657 SendMessageA(hwndRichEdit, WM_UNDO, 0, 0);
3658 ok(!SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0),
3659 "EM_SETUNDOLIMIT allowed a third undo with UNDOLIMIT set to 2\n");
3660
3661 /* fourth case - setting negative numbers should default to 100 undos */
3662 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
3663 result = SendMessageA(hwndRichEdit, EM_SETUNDOLIMIT, -1, 0);
3664 ok (result == 100,
3665 "EM_SETUNDOLIMIT returned %d when set to -1, instead of 100\n",result);
3666
3667 DestroyWindow(hwndRichEdit);
3668}
3669
3670static void test_ES_PASSWORD(void)
3671{
3672 /* This isn't hugely testable, so we're just going to run it through its paces */
3673
3674 HWND hwndRichEdit = new_richedit(NULL);
3675 WCHAR result;
3676
3677 /* First, check the default of a regular control */
3678 result = SendMessageA(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
3679 ok (result == 0,
3680 "EM_GETPASSWORDCHAR returned %c by default, instead of NULL\n",result);
3681
3682 /* Now, set it to something normal */
3683 SendMessageA(hwndRichEdit, EM_SETPASSWORDCHAR, 'x', 0);
3684 result = SendMessageA(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
3685 ok (result == 120,
3686 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result);
3687
3688 /* Now, set it to something odd */
3689 SendMessageA(hwndRichEdit, EM_SETPASSWORDCHAR, (WCHAR)1234, 0);
3690 result = SendMessageA(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
3691 ok (result == 1234,
3692 "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result);
3693 DestroyWindow(hwndRichEdit);
3694}
3695
3697
3699 LPBYTE pbBuff,
3700 LONG cb,
3701 LONG *pcb)
3702{
3703 char** str = (char**)dwCookie;
3704 *pcb = cb;
3705 if (*pcb > 0) {
3706 memcpy(*str, pbBuff, *pcb);
3707 *str += *pcb;
3708 }
3709 streamout_written = *pcb;
3710 return 0;
3711}
3712
3713static void test_WM_SETTEXT(void)
3714{
3715 HWND hwndRichEdit = new_richedit(NULL);
3716 const char * TestItem1 = "TestSomeText";
3717 const char * TestItem2 = "TestSomeText\r";
3718 const char * TestItem2_after = "TestSomeText\r\n";
3719 const char * TestItem3 = "TestSomeText\rSomeMoreText\r";
3720 const char * TestItem3_after = "TestSomeText\r\nSomeMoreText\r\n";
3721 const char * TestItem4 = "TestSomeText\n\nTestSomeText";
3722 const char * TestItem4_after = "TestSomeText\r\n\r\nTestSomeText";
3723 const char * TestItem5 = "TestSomeText\r\r\nTestSomeText";
3724 const char * TestItem5_after = "TestSomeText TestSomeText";
3725 const char * TestItem6 = "TestSomeText\r\r\n\rTestSomeText";
3726 const char * TestItem6_after = "TestSomeText \r\nTestSomeText";
3727 const char * TestItem7 = "TestSomeText\r\n\r\r\n\rTestSomeText";
3728 const char * TestItem7_after = "TestSomeText\r\n \r\nTestSomeText";
3729
3730 const char rtftextA[] = "{\\rtf sometext}";
3731 const char urtftextA[] = "{\\urtf sometext}";
3732 const WCHAR rtftextW[] = {'{','\\','r','t','f',' ','s','o','m','e','t','e','x','t','}',0};
3733 const WCHAR urtftextW[] = {'{','\\','u','r','t','f',' ','s','o','m','e','t','e','x','t','}',0};
3734 const WCHAR sometextW[] = {'s','o','m','e','t','e','x','t',0};
3735
3736 char buf[1024] = {0};
3737 WCHAR bufW[1024] = {0};
3739
3740 /* This test attempts to show that WM_SETTEXT on a riched20 control causes
3741 any solitary \r to be converted to \r\n on return. Properly paired
3742 \r\n are not affected. It also shows that the special sequence \r\r\n
3743 gets converted to a single space.
3744 */
3745
3746#define TEST_SETTEXT(a, b) \
3747 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)a); \
3748 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \
3749 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf); \
3750 ok (result == lstrlenA(buf), \
3751 "WM_GETTEXT returned %ld instead of expected %u\n", \
3752 result, lstrlenA(buf)); \
3753 result = strcmp(b, buf); \
3754 ok(result == 0, \
3755 "WM_SETTEXT round trip: strcmp = %ld, text=\"%s\"\n", result, buf);
3756
3757 TEST_SETTEXT(TestItem1, TestItem1)
3758 TEST_SETTEXT(TestItem2, TestItem2_after)
3759 TEST_SETTEXT(TestItem3, TestItem3_after)
3760 TEST_SETTEXT(TestItem3_after, TestItem3_after)
3761 TEST_SETTEXT(TestItem4, TestItem4_after)
3762 TEST_SETTEXT(TestItem5, TestItem5_after)
3763 TEST_SETTEXT(TestItem6, TestItem6_after)
3764 TEST_SETTEXT(TestItem7, TestItem7_after)
3765
3766 /* The following tests demonstrate that WM_SETTEXT supports RTF strings */
3767 TEST_SETTEXT(rtftextA, "sometext") /* interpreted as ascii rtf */
3768 TEST_SETTEXT(urtftextA, "sometext") /* interpreted as ascii rtf */
3769 TEST_SETTEXT(rtftextW, "{") /* interpreted as ascii text */
3770 TEST_SETTEXT(urtftextW, "{") /* interpreted as ascii text */
3771 DestroyWindow(hwndRichEdit);
3772#undef TEST_SETTEXT
3773
3774#define TEST_SETTEXTW(a, b) \
3775 result = SendMessageW(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)a); \
3776 ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \
3777 result = SendMessageW(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufW); \
3778 ok (result == lstrlenW(bufW), \
3779 "WM_GETTEXT returned %ld instead of expected %u\n", \
3780 result, lstrlenW(bufW)); \
3781 result = lstrcmpW(b, bufW); \
3782 ok(result == 0, "WM_SETTEXT round trip: strcmp = %ld\n", result);
3783
3784 hwndRichEdit = CreateWindowW(RICHEDIT_CLASS20W, NULL,
3786 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
3787 ok(hwndRichEdit != NULL, "class: RichEdit20W, error: %d\n", (int) GetLastError());
3788 TEST_SETTEXTW(rtftextA, sometextW) /* interpreted as ascii rtf */
3789 TEST_SETTEXTW(urtftextA, sometextW) /* interpreted as ascii rtf */
3790 TEST_SETTEXTW(rtftextW, rtftextW) /* interpreted as ascii text */
3791 TEST_SETTEXTW(urtftextW, urtftextW) /* interpreted as ascii text */
3792 DestroyWindow(hwndRichEdit);
3793#undef TEST_SETTEXTW
3794
3795 /* Single-line richedit */
3796 hwndRichEdit = new_richedit_with_style(NULL, 0);
3797 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"line1\r\nline2");
3798 ok(result == 1, "WM_SETTEXT returned %ld, expected 12\n", result);
3799 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf);
3800 ok(result == 5, "WM_GETTEXT returned %ld, expected 5\n", result);
3801 ok(!strcmp(buf, "line1"), "WM_GETTEXT returned incorrect string '%s'\n", buf);
3802 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"{\\rtf1 ABC\\rtlpar\\par DEF\\par HIJ\\pard\\par}");
3803 ok(result == 1, "WM_SETTEXT returned %ld, expected 1\n", result);
3804 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf);
3805 ok(result == 3, "WM_GETTEXT returned %ld, expected 3\n", result);
3806 ok(!strcmp(buf, "ABC"), "WM_GETTEXT returned incorrect string '%s'\n", buf);
3807 DestroyWindow(hwndRichEdit);
3808}
3809
3810/* Set *pcb to one to show that the remaining cb-1 bytes are not
3811 resent to the callkack. */
3813 LPBYTE pbBuff,
3814 LONG cb,
3815 LONG *pcb)
3816{
3817 char** str = (char**)dwCookie;
3818 ok(*pcb == cb || *pcb == 0, "cb %d, *pcb %d\n", cb, *pcb);
3819 *pcb = 0;
3820 if (cb > 0) {
3821 memcpy(*str, pbBuff, cb);
3822 *str += cb;
3823 *pcb = 1;
3824 }
3825 return 0;
3826}
3827
3828static int count_pars(const char *buf)
3829{
3830 const char *p = buf;
3831 int count = 0;
3832 while ((p = strstr( p, "\\par" )) != NULL)
3833 {
3834 if (!isalpha( p[4] ))
3835 count++;
3836 p++;
3837 }
3838 return count;
3839}
3840
3841static void test_EM_STREAMOUT(void)
3842{
3843 HWND hwndRichEdit = new_richedit(NULL);
3844 int r;
3845 EDITSTREAM es;
3846 char buf[1024] = {0};
3847 char * p;
3849
3850 const char * TestItem1 = "TestSomeText";
3851 const char * TestItem2 = "TestSomeText\r";
3852 const char * TestItem3 = "TestSomeText\r\n";
3853
3854 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem1);
3855 p = buf;
3856 es.dwCookie = (DWORD_PTR)&p;
3857 es.dwError = 0;
3858 es.pfnCallback = test_WM_SETTEXT_esCallback;
3859 memset(buf, 0, sizeof(buf));
3860 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_TEXT, (LPARAM)&es);
3861 r = strlen(buf);
3862 ok(r == 12, "streamed text length is %d, expecting 12\n", r);
3863 ok(strcmp(buf, TestItem1) == 0,
3864 "streamed text different, got %s\n", buf);
3865 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written);
3866
3867 /* RTF mode writes the final end of para \r if it's part of the selection */
3868 p = buf;
3869 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF, (LPARAM)&es);
3870 ok (count_pars(buf) == 1, "got %s\n", buf);
3871 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written);
3872 p = buf;
3873 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 12);
3875 ok (count_pars(buf) == 0, "got %s\n", buf);
3876 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written);
3877 p = buf;
3878 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
3880 ok (count_pars(buf) == 1, "got %s\n", buf);
3881 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written);
3882
3883 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem2);
3884 p = buf;
3885 es.dwCookie = (DWORD_PTR)&p;
3886 es.dwError = 0;
3887 es.pfnCallback = test_WM_SETTEXT_esCallback;
3888 memset(buf, 0, sizeof(buf));
3889 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_TEXT, (LPARAM)&es);
3890 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written);
3891 r = strlen(buf);
3892 /* Here again, \r gets converted to \r\n, like WM_GETTEXT */
3893 ok(r == 14, "streamed text length is %d, expecting 14\n", r);
3894 ok(strcmp(buf, TestItem3) == 0,
3895 "streamed text different from, got %s\n", buf);
3896
3897 /* And again RTF mode writes the final end of para \r if it's part of the selection */
3898 p = buf;
3899 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF, (LPARAM)&es);
3900 ok (count_pars(buf) == 2, "got %s\n", buf);
3901 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written);
3902 p = buf;
3903 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 13);
3905 ok (count_pars(buf) == 1, "got %s\n", buf);
3906 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written);
3907 p = buf;
3908 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
3910 ok (count_pars(buf) == 2, "got %s\n", buf);
3911 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written);
3912
3913 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem3);
3914 p = buf;
3915 es.dwCookie = (DWORD_PTR)&p;
3916 es.dwError = 0;
3917 es.pfnCallback = test_WM_SETTEXT_esCallback;
3918 memset(buf, 0, sizeof(buf));
3919 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_TEXT, (LPARAM)&es);
3920 ok(result == streamout_written, "got %ld expected %d\n", result, streamout_written);
3921 r = strlen(buf);
3922 ok(r == 14, "streamed text length is %d, expecting 14\n", r);
3923 ok(strcmp(buf, TestItem3) == 0,
3924 "streamed text different, got %s\n", buf);
3925
3926 /* Use a callback that sets *pcb to one */
3927 p = buf;
3928 es.dwCookie = (DWORD_PTR)&p;
3929 es.dwError = 0;
3930 es.pfnCallback = test_esCallback_written_1;
3931 memset(buf, 0, sizeof(buf));
3932 result = SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_TEXT, (LPARAM)&es);
3933 r = strlen(buf);
3934 ok(r == 14, "streamed text length is %d, expecting 14\n", r);
3935 ok(strcmp(buf, TestItem3) == 0,
3936 "streamed text different, got %s\n", buf);
3937 ok(result == 0, "got %ld expected 0\n", result);
3938
3939
3940 DestroyWindow(hwndRichEdit);
3941}
3942
3944{
3945 HWND hwndRichEdit = new_richedit(NULL);
3946 EDITSTREAM es;
3947 char buf[1024] = {0};
3948 char * p;
3949 char * fontTbl;
3950 int brackCount;
3951
3952 const char * TestItem = "TestSomeText";
3953
3954 /* fills in the richedit control with some text */
3955 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem);
3956
3957 /* streams out the text in rtf format */
3958 p = buf;
3959 es.dwCookie = (DWORD_PTR)&p;
3960 es.dwError = 0;
3961 es.pfnCallback = test_WM_SETTEXT_esCallback;
3962 memset(buf, 0, sizeof(buf));
3963 SendMessageA(hwndRichEdit, EM_STREAMOUT, SF_RTF, (LPARAM)&es);
3964
3965 /* scans for \fonttbl, error if not found */
3966 fontTbl = strstr(buf, "\\fonttbl");
3967 ok(fontTbl != NULL, "missing \\fonttbl section\n");
3968 if(fontTbl)
3969 {
3970 /* scans for terminating closing bracket */
3971 brackCount = 1;
3972 while(*fontTbl && brackCount)
3973 {
3974 if(*fontTbl == '{')
3975 brackCount++;
3976 else if(*fontTbl == '}')
3977 brackCount--;
3978 fontTbl++;
3979 }
3980 /* checks whether closing bracket is ok */
3981 ok(brackCount == 0, "missing closing bracket in \\fonttbl block\n");
3982 if(!brackCount)
3983 {
3984 /* char before closing fonttbl block should be a closed bracket */
3985 fontTbl -= 2;
3986 ok(*fontTbl == '}', "spurious character '%02x' before \\fonttbl closing bracket\n", *fontTbl);
3987
3988 /* char after fonttbl block should be a crlf */
3989 fontTbl += 2;
3990 ok(*fontTbl == 0x0d && *(fontTbl+1) == 0x0a, "missing crlf after \\fonttbl block\n");
3991 }
3992 }
3993 DestroyWindow(hwndRichEdit);
3994}
3995
3997{
3999 char buf[1024], *p = buf;
4000 EDITSTREAM es;
4001
4003
4004 memset(buf, 0, sizeof(buf));
4005 es.dwCookie = (DWORD_PTR)&p;
4006 es.dwError = 0;
4007 es.pfnCallback = test_WM_SETTEXT_esCallback;
4008
4010 ok((p = strstr(buf, "\\pard")) != NULL, "missing \\pard\n");
4011 ok(((p = strstr(p, "\\fs")) && isdigit(p[3])), "missing \\fs\n");
4012
4014}
4015
4016static void test_EM_SETTEXTEX(void)
4017{
4018 HWND hwndRichEdit, parent;
4019 SCROLLINFO si;
4020 int sel_start, sel_end;
4021 SETTEXTEX setText;
4022 GETTEXTEX getText;
4023 WCHAR TestItem1[] = {'T', 'e', 's', 't',
4024 'S', 'o', 'm', 'e',
4025 'T', 'e', 'x', 't', 0};
4026 WCHAR TestItem1alt[] = {'T', 'T', 'e', 's',
4027 't', 'S', 'o', 'm',
4028 'e', 'T', 'e', 'x',
4029 't', 't', 'S', 'o',
4030 'm', 'e', 'T', 'e',
4031 'x', 't', 0};
4032 WCHAR TestItem1altn[] = {'T','T','e','s','t','S','o','m','e','T','e','x','t',
4033 '\r','t','S','o','m','e','T','e','x','t',0};
4034 WCHAR TestItem2[] = {'T', 'e', 's', 't',
4035 'S', 'o', 'm', 'e',
4036 'T', 'e', 'x', 't',
4037 '\r', 0};
4038 const char * TestItem2_after = "TestSomeText\r\n";
4039 WCHAR TestItem3[] = {'T', 'e', 's', 't',
4040 'S', 'o', 'm', 'e',
4041 'T', 'e', 'x', 't',
4042 '\r','\n','\r','\n', 0};
4043 WCHAR TestItem3alt[] = {'T', 'e', 's', 't',
4044 'S', 'o', 'm', 'e',
4045 'T', 'e', 'x', 't',
4046 '\n','\n', 0};
4047 WCHAR TestItem3_after[] = {'T', 'e', 's', 't',
4048 'S', 'o', 'm', 'e',
4049 'T', 'e', 'x', 't',
4050 '\r','\r', 0};
4051 WCHAR TestItem4[] = {'T', 'e', 's', 't',
4052 'S', 'o', 'm', 'e',
4053 'T', 'e', 'x', 't',
4054 '\r','\r','\n','\r',
4055 '\n', 0};
4056 WCHAR TestItem4_after[] = {'T', 'e', 's', 't',
4057 'S', 'o', 'm', 'e',
4058 'T', 'e', 'x', 't',
4059 ' ','\r', 0};
4060#define MAX_BUF_LEN 1024
4062 char bufACP[MAX_BUF_LEN];
4063 char * p;
4064 int result;
4065 CHARRANGE cr;
4066 EDITSTREAM es;
4067 WNDCLASSA cls;
4068
4069 /* Test the scroll position with and without a parent window.
4070 *
4071 * For some reason the scroll position is 0 after EM_SETTEXTEX
4072 * with the ST_SELECTION flag only when the control has a parent
4073 * window, even though the selection is at the end. */
4074 cls.style = 0;
4076 cls.cbClsExtra = 0;
4077 cls.cbWndExtra = 0;
4078 cls.hInstance = GetModuleHandleA(0);
4079 cls.hIcon = 0;
4082 cls.lpszMenuName = NULL;
4083 cls.lpszClassName = "ParentTestClass";
4084 if(!RegisterClassA(&cls)) assert(0);
4085
4087 0, 0, 200, 60, NULL, NULL, NULL, NULL);
4088 ok (parent != 0, "Failed to create parent window\n");
4089
4090 hwndRichEdit = CreateWindowExA(0,
4093 0, 0, 200, 60, parent, NULL,
4095
4096 setText.codepage = CP_ACP;
4097 setText.flags = ST_SELECTION;
4098 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText,
4099 (LPARAM)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
4100 todo_wine ok(result == 18, "EM_SETTEXTEX returned %d, expected 18\n", result);
4101 si.cbSize = sizeof(si);
4102 si.fMask = SIF_ALL;
4103 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
4104 todo_wine ok(si.nPos == 0, "Position is incorrectly at %d\n", si.nPos);
4105 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
4106 ok(sel_start == 18, "Selection start incorrectly at %d\n", sel_start);
4107 ok(sel_end == 18, "Selection end incorrectly at %d\n", sel_end);
4108
4110
4111 /* Test without a parent window */
4112 hwndRichEdit = new_richedit(NULL);
4113 setText.codepage = CP_ACP;
4114 setText.flags = ST_SELECTION;
4115 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText,
4116 (LPARAM)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
4117 todo_wine ok(result == 18, "EM_SETTEXTEX returned %d, expected 18\n", result);
4118 si.cbSize = sizeof(si);
4119 si.fMask = SIF_ALL;
4120 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
4121 ok(si.nPos != 0, "Position is incorrectly at %d\n", si.nPos);
4122 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
4123 ok(sel_start == 18, "Selection start incorrectly at %d\n", sel_start);
4124 ok(sel_end == 18, "Selection end incorrectly at %d\n", sel_end);
4125
4126 /* The scroll position should also be 0 after EM_SETTEXTEX with ST_DEFAULT,
4127 * but this time it is because the selection is at the beginning. */
4128 setText.codepage = CP_ACP;
4129 setText.flags = ST_DEFAULT;
4130 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText,
4131 (LPARAM)"{\\rtf 1\\par 2\\par 3\\par 4\\par 5\\par 6\\par 7\\par 8\\par 9\\par}");
4132 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4133 si.cbSize = sizeof(si);
4134 si.fMask = SIF_ALL;
4135 GetScrollInfo(hwndRichEdit, SB_VERT, &si);
4136 ok(si.nPos == 0, "Position is incorrectly at %d\n", si.nPos);
4137 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
4138 ok(sel_start == 0, "Selection start incorrectly at %d\n", sel_start);
4139 ok(sel_end == 0, "Selection end incorrectly at %d\n", sel_end);
4140
4141 setText.codepage = 1200; /* no constant for unicode */
4142 getText.codepage = 1200; /* no constant for unicode */
4143 getText.cb = MAX_BUF_LEN;
4144 getText.flags = GT_DEFAULT;
4145 getText.lpDefaultChar = NULL;
4146 getText.lpUsedDefChar = NULL;
4147
4148 setText.flags = 0;
4149 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
4150 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4151 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4152 ok(lstrcmpW(buf, TestItem1) == 0,
4153 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
4154
4155 /* Unlike WM_SETTEXT/WM_GETTEXT pair, EM_SETTEXTEX/EM_GETTEXTEX does not
4156 convert \r to \r\n on return: !ST_SELECTION && Unicode && !\rtf
4157 */
4158 setText.codepage = 1200; /* no constant for unicode */
4159 getText.codepage = 1200; /* no constant for unicode */
4160 getText.cb = MAX_BUF_LEN;
4161 getText.flags = GT_DEFAULT;
4162 getText.lpDefaultChar = NULL;
4163 getText.lpUsedDefChar = NULL;
4164 setText.flags = 0;
4165 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem2);
4166 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4167 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4168 ok(lstrcmpW(buf, TestItem2) == 0,
4169 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
4170
4171 /* However, WM_GETTEXT *does* see \r\n where EM_GETTEXTEX would see \r */
4172 SendMessageA(hwndRichEdit, WM_GETTEXT, MAX_BUF_LEN, (LPARAM)buf);
4173 ok(strcmp((const char *)buf, TestItem2_after) == 0,
4174 "WM_GETTEXT did *not* see \\r converted to \\r\\n pairs.\n");
4175
4176 /* Baseline test for just-enough buffer space for string */
4177 getText.cb = (lstrlenW(TestItem2) + 1) * sizeof(WCHAR);
4178 getText.codepage = 1200; /* no constant for unicode */
4179 getText.flags = GT_DEFAULT;
4180 getText.lpDefaultChar = NULL;
4181 getText.lpUsedDefChar = NULL;
4182 memset(buf, 0, sizeof(buf));
4183 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4184 ok(lstrcmpW(buf, TestItem2) == 0,
4185 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
4186
4187 /* When there is enough space for one character, but not both, of the CRLF
4188 pair at the end of the string, the CR is not copied at all. That is,
4189 the caller must not see CRLF pairs truncated to CR at the end of the
4190 string.
4191 */
4192 getText.cb = (lstrlenW(TestItem2) + 1) * sizeof(WCHAR);
4193 getText.codepage = 1200; /* no constant for unicode */
4194 getText.flags = GT_USECRLF; /* <-- asking for CR -> CRLF conversion */
4195 getText.lpDefaultChar = NULL;
4196 getText.lpUsedDefChar = NULL;
4197 memset(buf, 0, sizeof(buf));
4198 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4199 ok(lstrcmpW(buf, TestItem1) == 0,
4200 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
4201
4202
4203 /* \r\n pairs get changed into \r: !ST_SELECTION && Unicode && !\rtf */
4204 setText.codepage = 1200; /* no constant for unicode */
4205 getText.codepage = 1200; /* no constant for unicode */
4206 getText.cb = MAX_BUF_LEN;
4207 getText.flags = GT_DEFAULT;
4208 getText.lpDefaultChar = NULL;
4209 getText.lpUsedDefChar = NULL;
4210 setText.flags = 0;
4211 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem3);
4212 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4213 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4214 ok(lstrcmpW(buf, TestItem3_after) == 0,
4215 "EM_SETTEXTEX did not convert properly\n");
4216
4217 /* \n also gets changed to \r: !ST_SELECTION && Unicode && !\rtf */
4218 setText.codepage = 1200; /* no constant for unicode */
4219 getText.codepage = 1200; /* no constant for unicode */
4220 getText.cb = MAX_BUF_LEN;
4221 getText.flags = GT_DEFAULT;
4222 getText.lpDefaultChar = NULL;
4223 getText.lpUsedDefChar = NULL;
4224 setText.flags = 0;
4225 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem3alt);
4226 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4227 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4228 ok(lstrcmpW(buf, TestItem3_after) == 0,
4229 "EM_SETTEXTEX did not convert properly\n");
4230
4231 /* \r\r\n gets changed into single space: !ST_SELECTION && Unicode && !\rtf */
4232 setText.codepage = 1200; /* no constant for unicode */
4233 getText.codepage = 1200; /* no constant for unicode */
4234 getText.cb = MAX_BUF_LEN;
4235 getText.flags = GT_DEFAULT;
4236 getText.lpDefaultChar = NULL;
4237 getText.lpUsedDefChar = NULL;
4238 setText.flags = 0;
4239 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem4);
4240 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4241 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4242 ok(lstrcmpW(buf, TestItem4_after) == 0,
4243 "EM_SETTEXTEX did not convert properly\n");
4244
4245 /* !ST_SELECTION && Unicode && !\rtf */
4246 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, 0);
4247 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4248
4249 ok (result == 1,
4250 "EM_SETTEXTEX returned %d, instead of 1\n",result);
4251 ok(!buf[0], "EM_SETTEXTEX with NULL lParam should clear rich edit.\n");
4252
4253 /* put some text back: !ST_SELECTION && Unicode && !\rtf */
4254 setText.flags = 0;
4255 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
4256 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4257 /* select some text */
4258 cr.cpMax = 1;
4259 cr.cpMin = 3;
4260 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
4261 /* replace current selection: ST_SELECTION && Unicode && !\rtf */
4262 setText.flags = ST_SELECTION;
4263 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, 0);
4264 ok(result == 0,
4265 "EM_SETTEXTEX with NULL lParam to replace selection"
4266 " with no text should return 0. Got %i\n",
4267 result);
4268
4269 /* put some text back: !ST_SELECTION && Unicode && !\rtf */
4270 setText.flags = 0;
4271 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
4272 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4273 /* select some text */
4274 cr.cpMax = 1;
4275 cr.cpMin = 3;
4276 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
4277 /* replace current selection: ST_SELECTION && Unicode && !\rtf */
4278 setText.flags = ST_SELECTION;
4279 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
4280 /* get text */
4281 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4282 ok(result == lstrlenW(TestItem1),
4283 "EM_SETTEXTEX with NULL lParam to replace selection"
4284 " with no text should return 0. Got %i\n",
4285 result);
4286 ok(lstrlenW(buf) == 22,
4287 "EM_SETTEXTEX to replace selection with more text failed: %i.\n",
4288 lstrlenW(buf) );
4289
4290 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings */
4291 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"TestSomeText"); /* TestItem1 */
4292 p = (char *)buf;
4293 es.dwCookie = (DWORD_PTR)&p;
4294 es.dwError = 0;
4295 es.pfnCallback = test_WM_SETTEXT_esCallback;
4296 memset(buf, 0, sizeof(buf));
4297 SendMessageA(hwndRichEdit, EM_STREAMOUT,
4298 (WPARAM)(SF_RTF), (LPARAM)&es);
4299 trace("EM_STREAMOUT produced:\n%s\n", (char *)buf);
4300
4301 /* !ST_SELECTION && !Unicode && \rtf */
4302 setText.codepage = CP_ACP;/* EM_STREAMOUT saved as ANSI string */
4303 getText.codepage = 1200; /* no constant for unicode */
4304 getText.cb = MAX_BUF_LEN;
4305 getText.flags = GT_DEFAULT;
4306 getText.lpDefaultChar = NULL;
4307 getText.lpUsedDefChar = NULL;
4308
4309 setText.flags = 0;
4310 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)buf);
4311 ok(result == 1, "EM_SETTEXTEX returned %d, expected 1\n", result);
4312 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4313 ok(lstrcmpW(buf, TestItem1) == 0,
4314 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
4315
4316 /* The following test demonstrates that EM_SETTEXTEX treats text as ASCII if it
4317 * starts with ASCII characters "{\rtf" even when the codepage is unicode. */
4318 setText.codepage = 1200; /* Lie about code page (actual ASCII) */
4319 getText.codepage = CP_ACP;
4320 getText.cb = MAX_BUF_LEN;
4321 getText.flags = GT_DEFAULT;
4322 getText.lpDefaultChar = NULL;
4323 getText.lpUsedDefChar = NULL;
4324
4325 setText.flags = ST_SELECTION;
4326 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
4327 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"{\\rtf not unicode}");
4328 todo_wine ok(result == 11, "EM_SETTEXTEX incorrectly returned %d\n", result);
4329 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)bufACP);
4330 ok(lstrcmpA(bufACP, "not unicode") == 0, "'%s' != 'not unicode'\n", bufACP);
4331
4332 /* The following test demonstrates that EM_SETTEXTEX supports RTF strings with a selection */
4333 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"TestSomeText"); /* TestItem1 */
4334 p = (char *)buf;
4335 es.dwCookie = (DWORD_PTR)&p;
4336 es.dwError = 0;
4337 es.pfnCallback = test_WM_SETTEXT_esCallback;
4338 memset(buf, 0, sizeof(buf));
4339 SendMessageA(hwndRichEdit, EM_STREAMOUT,
4340 (WPARAM)(SF_RTF), (LPARAM)&es);
4341 trace("EM_STREAMOUT produced:\n%s\n", (char *)buf);
4342
4343 /* select some text */
4344 cr.cpMax = 1;
4345 cr.cpMin = 3;
4346 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
4347
4348 /* ST_SELECTION && !Unicode && \rtf */
4349 setText.codepage = CP_ACP;/* EM_STREAMOUT saved as ANSI string */
4350 getText.codepage = 1200; /* no constant for unicode */
4351 getText.cb = MAX_BUF_LEN;
4352 getText.flags = GT_DEFAULT;
4353 getText.lpDefaultChar = NULL;
4354 getText.lpUsedDefChar = NULL;
4355
4356 setText.flags = ST_SELECTION;
4357 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)buf);
4358 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4359 ok_w3("Expected \"%s\" or \"%s\", got \"%s\"\n", TestItem1alt, TestItem1altn, buf);
4360
4361 /* The following test demonstrates that EM_SETTEXTEX replacing a selection */
4362 setText.codepage = 1200; /* no constant for unicode */
4363 getText.codepage = CP_ACP;
4364 getText.cb = MAX_BUF_LEN;
4365
4366 setText.flags = 0;
4367 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1); /* TestItem1 */
4368 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)bufACP);
4369
4370 /* select some text */
4371 cr.cpMax = 1;
4372 cr.cpMin = 3;
4373 SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
4374
4375 /* ST_SELECTION && !Unicode && !\rtf */
4376 setText.codepage = CP_ACP;
4377 getText.codepage = 1200; /* no constant for unicode */
4378 getText.cb = MAX_BUF_LEN;
4379 getText.flags = GT_DEFAULT;
4380 getText.lpDefaultChar = NULL;
4381 getText.lpUsedDefChar = NULL;
4382
4383 setText.flags = ST_SELECTION;
4384 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)bufACP);
4385 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
4386 ok(lstrcmpW(buf, TestItem1alt) == 0,
4387 "EM_GETTEXTEX results not what was set by EM_SETTEXTEX when"
4388 " using ST_SELECTION and non-Unicode\n");
4389
4390 /* Test setting text using rich text format */
4391 setText.flags = 0;
4392 setText.codepage = CP_ACP;
4393 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"{\\rtf richtext}");
4394 getText.codepage = CP_ACP;
4395 getText.cb = MAX_BUF_LEN;
4396 getText.flags = GT_DEFAULT;
4397 getText.lpDefaultChar = NULL;
4398 getText.lpUsedDefChar = NULL;
4399 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)bufACP);
4400 ok(!strcmp(bufACP, "richtext"), "expected 'richtext' but got '%s'\n", bufACP);
4401
4402 setText.flags = 0;
4403 setText.codepage = CP_ACP;
4404 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"{\\urtf morerichtext}");
4405 getText.codepage = CP_ACP;
4406 getText.cb = MAX_BUF_LEN;
4407 getText.flags = GT_DEFAULT;
4408 getText.lpDefaultChar = NULL;
4409 getText.lpUsedDefChar = NULL;
4410 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)bufACP);
4411 ok(!strcmp(bufACP, "morerichtext"), "expected 'morerichtext' but got '%s'\n", bufACP);
4412
4413 /* test for utf8 text with BOM */
4414 setText.flags = 0;
4415 setText.codepage = CP_ACP;
4416 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"\xef\xbb\xbfTestUTF8WithBOM");
4417 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP);
4418 ok(result == 15, "EM_SETTEXTEX: Test UTF8 with BOM returned %d, expected 15\n", result);
4419 result = strcmp(bufACP, "TestUTF8WithBOM");
4420 ok(result == 0, "EM_SETTEXTEX: Test UTF8 with BOM set wrong text: Result: %s\n", bufACP);
4421
4422 setText.flags = 0;
4423 setText.codepage = CP_UTF8;
4424 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"\xef\xbb\xbfTestUTF8WithBOM");
4425 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP);
4426 ok(result == 15, "EM_SETTEXTEX: Test UTF8 with BOM returned %d, expected 15\n", result);
4427 result = strcmp(bufACP, "TestUTF8WithBOM");
4428 ok(result == 0, "EM_SETTEXTEX: Test UTF8 with BOM set wrong text: Result: %s\n", bufACP);
4429
4430 /* Test multibyte character */
4431 if (!is_lang_japanese)
4432 skip("Skip multibyte character tests on non-Japanese platform\n");
4433 else
4434 {
4435 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
4436 setText.flags = ST_SELECTION;
4437 setText.codepage = CP_ACP;
4438 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"abc\x8e\xf0");
4439 todo_wine ok(result == 5, "EM_SETTEXTEX incorrectly returned %d, expected 5\n", result);
4440 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP);
4441 ok(result == 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result);
4442 ok(!strcmp(bufACP, "abc\x8e\xf0"),
4443 "EM_SETTEXTEX: Test multibyte character set wrong text: Result: %s\n", bufACP);
4444
4445 setText.flags = ST_DEFAULT;
4446 setText.codepage = CP_ACP;
4447 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"abc\x8e\xf0");
4448 ok(result == 1, "EM_SETTEXTEX incorrectly returned %d, expected 1\n", result);
4449 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP);
4450 ok(result == 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result);
4451 ok(!strcmp(bufACP, "abc\x8e\xf0"),
4452 "EM_SETTEXTEX: Test multibyte character set wrong text: Result: %s\n", bufACP);
4453
4454 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
4455 setText.flags = ST_SELECTION;
4456 setText.codepage = CP_ACP;
4457 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"{\\rtf abc\x8e\xf0}");
4458 todo_wine ok(result == 4, "EM_SETTEXTEX incorrectly returned %d, expected 4\n", result);
4459 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP);
4460 ok(result == 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result);
4461 todo_wine ok(!strcmp(bufACP, "abc\x8e\xf0"),
4462 "EM_SETTEXTEX: Test multibyte character set wrong text: Result: %s\n", bufACP);
4463 }
4464
4465 DestroyWindow(hwndRichEdit);
4466
4467 /* Single-line richedit */
4468 hwndRichEdit = new_richedit_with_style(NULL, 0);
4469 setText.flags = ST_DEFAULT;
4470 setText.codepage = CP_ACP;
4471 result = SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)"line1\r\nline2");
4472 ok(result == 1, "EM_SETTEXTEX incorrectly returned %d, expected 1\n", result);
4473 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)bufACP);
4474 ok(result == 5, "WM_GETTEXT incorrectly returned %d, expected 5\n", result);
4475 ok(!strcmp(bufACP, "line1"), "EM_SETTEXTEX: Test single-line text: Result: %s\n", bufACP);
4476 DestroyWindow(hwndRichEdit);
4477}
4478
4479static void test_EM_LIMITTEXT(void)
4480{
4481 int ret;
4482
4483 HWND hwndRichEdit = new_richedit(NULL);
4484
4485 /* The main purpose of this test is to demonstrate that the nonsense in MSDN
4486 * about setting the length to -1 for multiline edit controls doesn't happen.
4487 */
4488
4489 /* Don't check default gettextlimit case. That's done in other tests */
4490
4491 /* Set textlimit to 100 */
4492 SendMessageA(hwndRichEdit, EM_LIMITTEXT, 100, 0);
4493 ret = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4494 ok (ret == 100,
4495 "EM_LIMITTEXT: set to 100, returned: %d, expected: 100\n", ret);
4496
4497 /* Set textlimit to 0 */
4498 SendMessageA(hwndRichEdit, EM_LIMITTEXT, 0, 0);
4499 ret = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4500 ok (ret == 65536,
4501 "EM_LIMITTEXT: set to 0, returned: %d, expected: 65536\n", ret);
4502
4503 /* Set textlimit to -1 */
4504 SendMessageA(hwndRichEdit, EM_LIMITTEXT, -1, 0);
4505 ret = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4506 ok (ret == -1,
4507 "EM_LIMITTEXT: set to -1, returned: %d, expected: -1\n", ret);
4508
4509 /* Set textlimit to -2 */
4510 SendMessageA(hwndRichEdit, EM_LIMITTEXT, -2, 0);
4511 ret = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4512 ok (ret == -2,
4513 "EM_LIMITTEXT: set to -2, returned: %d, expected: -2\n", ret);
4514
4515 DestroyWindow (hwndRichEdit);
4516}
4517
4518
4519static void test_EM_EXLIMITTEXT(void)
4520{
4521 int i, selBegin, selEnd, len1, len2;
4522 int result;
4523 char text[1024 + 1];
4524 char buffer[1024 + 1];
4525 int textlimit = 0; /* multiple of 100 */
4526 HWND hwndRichEdit = new_richedit(NULL);
4527
4528 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4529 ok(32767 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 32767, i); /* default */
4530
4531 textlimit = 256000;
4532 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
4533 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4534 /* set higher */
4535 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i);
4536
4537 textlimit = 1000;
4538 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
4539 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4540 /* set lower */
4541 ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i);
4542
4543 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, 0);
4544 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4545 /* default for WParam = 0 */
4546 ok(65536 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 65536, i);
4547
4548 textlimit = sizeof(text)-1;
4549 memset(text, 'W', textlimit);
4550 text[sizeof(text)-1] = 0;
4551 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
4552 /* maxed out text */
4553 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
4554
4555 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); /* select everything */
4556 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
4557 len1 = selEnd - selBegin;
4558
4559 SendMessageA(hwndRichEdit, WM_KEYDOWN, VK_BACK, 1);
4560 SendMessageA(hwndRichEdit, WM_CHAR, VK_BACK, 1);
4561 SendMessageA(hwndRichEdit, WM_KEYUP, VK_BACK, 1);
4562 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
4563 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
4564 len2 = selEnd - selBegin;
4565
4566 ok(len1 != len2,
4567 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4568 len1,len2,i);
4569
4570 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'A', 1);
4571 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 1);
4572 SendMessageA(hwndRichEdit, WM_KEYUP, 'A', 1);
4573 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
4574 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
4575 len1 = selEnd - selBegin;
4576
4577 ok(len1 != len2,
4578 "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4579 len1,len2,i);
4580
4581 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'A', 1);
4582 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 1);
4583 SendMessageA(hwndRichEdit, WM_KEYUP, 'A', 1); /* full; should be no effect */
4584 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
4585 SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
4586 len2 = selEnd - selBegin;
4587
4588 ok(len1 == len2,
4589 "EM_EXLIMITTEXT: No Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
4590 len1,len2,i);
4591
4592 /* set text up to the limit, select all the text, then add a char */
4593 textlimit = 5;
4594 memset(text, 'W', textlimit);
4595 text[textlimit] = 0;
4596 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
4597 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
4598 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
4599 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 1);
4600 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
4601 result = strcmp(buffer, "A");
4602 ok(0 == result, "got string = \"%s\"\n", buffer);
4603
4604 /* WM_SETTEXT not limited */
4605 textlimit = 10;
4606 memset(text, 'W', textlimit);
4607 text[textlimit] = 0;
4608 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit-5);
4609 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
4610 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
4611 i = strlen(buffer);
4612 ok(10 == i, "expected 10 chars\n");
4613 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4614 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
4615
4616 /* try inserting more text at end */
4617 i = SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0);
4618 ok(0 == i, "WM_CHAR wasn't processed\n");
4619 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
4620 i = strlen(buffer);
4621 ok(10 == i, "expected 10 chars, got %i\n", i);
4622 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4623 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
4624
4625 /* try inserting text at beginning */
4626 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 0);
4627 i = SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0);
4628 ok(0 == i, "WM_CHAR wasn't processed\n");
4629 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
4630 i = strlen(buffer);
4631 ok(10 == i, "expected 10 chars, got %i\n", i);
4632 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4633 ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
4634
4635 /* WM_CHAR is limited */
4636 textlimit = 1;
4637 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
4638 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1); /* select everything */
4639 i = SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0);
4640 ok(0 == i, "WM_CHAR wasn't processed\n");
4641 i = SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0);
4642 ok(0 == i, "WM_CHAR wasn't processed\n");
4643 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
4644 i = strlen(buffer);
4645 ok(1 == i, "expected 1 chars, got %i instead\n", i);
4646
4647 DestroyWindow(hwndRichEdit);
4648}
4649
4650static void test_EM_GETLIMITTEXT(void)
4651{
4652 int i;
4653 HWND hwndRichEdit = new_richedit(NULL);
4654
4655 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4656 ok(32767 == i, "expected: %d, actual: %d\n", 32767, i); /* default value */
4657
4658 SendMessageA(hwndRichEdit, EM_EXLIMITTEXT, 0, 50000);
4659 i = SendMessageA(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
4660 ok(50000 == i, "expected: %d, actual: %d\n", 50000, i);
4661
4662 DestroyWindow(hwndRichEdit);
4663}
4664
4665static void test_WM_SETFONT(void)
4666{
4667 /* There is no invalid input or error conditions for this function.
4668 * NULL wParam and lParam just fall back to their default values
4669 * It should be noted that even if you use a gibberish name for your fonts
4670 * here, it will still work because the name is stored. They will display as
4671 * System, but will report their name to be whatever they were created as */
4672
4673 HWND hwndRichEdit = new_richedit(NULL);
4674 HFONT testFont1 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
4676 FF_DONTCARE, "Marlett");
4677 HFONT testFont2 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
4679 FF_DONTCARE, "MS Sans Serif");
4680 HFONT testFont3 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
4682 FF_DONTCARE, "Courier");
4683 LOGFONTA sentLogFont;
4684 CHARFORMAT2A returnedCF2A;
4685
4686 returnedCF2A.cbSize = sizeof(returnedCF2A);
4687
4688 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"x");
4689 SendMessageA(hwndRichEdit, WM_SETFONT, (WPARAM)testFont1, MAKELPARAM(TRUE, 0));
4690 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&returnedCF2A);
4691
4692 GetObjectA(testFont1, sizeof(LOGFONTA), &sentLogFont);
4693 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
4694 "EM_GETCHARFORMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n",
4695 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
4696
4697 SendMessageA(hwndRichEdit, WM_SETFONT, (WPARAM)testFont2, MAKELPARAM(TRUE, 0));
4698 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&returnedCF2A);
4699 GetObjectA(testFont2, sizeof(LOGFONTA), &sentLogFont);
4700 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
4701 "EM_GETCHARFORMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n",
4702 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
4703
4704 SendMessageA(hwndRichEdit, WM_SETFONT, (WPARAM)testFont3, MAKELPARAM(TRUE, 0));
4705 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&returnedCF2A);
4706 GetObjectA(testFont3, sizeof(LOGFONTA), &sentLogFont);
4707 ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
4708 "EM_GETCHARFORMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n",
4709 sentLogFont.lfFaceName,returnedCF2A.szFaceName);
4710
4711 /* This last test is special since we send in NULL. We clear the variables
4712 * and just compare to "System" instead of the sent in font name. */
4713 ZeroMemory(&returnedCF2A,sizeof(returnedCF2A));
4714 ZeroMemory(&sentLogFont,sizeof(sentLogFont));
4715 returnedCF2A.cbSize = sizeof(returnedCF2A);
4716
4717 SendMessageA(hwndRichEdit, WM_SETFONT, 0, MAKELPARAM((WORD) TRUE, 0));
4718 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&returnedCF2A);
4719 GetObjectA(NULL, sizeof(LOGFONTA), &sentLogFont);
4720 ok (!strcmp("System",returnedCF2A.szFaceName),
4721 "EM_GETCHARFORMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A.szFaceName);
4722
4723 DestroyWindow(hwndRichEdit);
4724}
4725
4726
4728 LPBYTE pbBuff,
4729 LONG cb,
4730 LONG *pcb)
4731{
4732 const char** str = (const char**)dwCookie;
4733 int size = strlen(*str);
4734 if(size > 3) /* let's make it piecemeal for fun */
4735 size = 3;
4736 *pcb = cb;
4737 if (*pcb > size) {
4738 *pcb = size;
4739 }
4740 if (*pcb > 0) {
4741 memcpy(pbBuff, *str, *pcb);
4742 *str += *pcb;
4743 }
4744 return 0;
4745}
4746
4747static void test_EM_GETMODIFY(void)
4748{
4749 HWND hwndRichEdit = new_richedit(NULL);
4751 SETTEXTEX setText;
4752 WCHAR TestItem1[] = {'T', 'e', 's', 't',
4753 'S', 'o', 'm', 'e',
4754 'T', 'e', 'x', 't', 0};
4755 WCHAR TestItem2[] = {'T', 'e', 's', 't',
4756 'S', 'o', 'm', 'e',
4757 'O', 't', 'h', 'e', 'r',
4758 'T', 'e', 'x', 't', 0};
4759 const char* streamText = "hello world";
4760 CHARFORMAT2A cf2;
4761 PARAFORMAT2 pf2;
4762 EDITSTREAM es;
4763
4764 HFONT testFont = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET,
4766 FF_DONTCARE, "Courier");
4767
4768 setText.codepage = 1200; /* no constant for unicode */
4769 setText.flags = ST_KEEPUNDO;
4770
4771
4772 /* modify flag shouldn't be set when richedit is first created */
4773 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4774 ok (result == 0,
4775 "EM_GETMODIFY returned non-zero, instead of zero on create\n");
4776
4777 /* setting modify flag should actually set it */
4778 SendMessageA(hwndRichEdit, EM_SETMODIFY, TRUE, 0);
4779 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4780 ok (result != 0,
4781 "EM_GETMODIFY returned zero, instead of non-zero on EM_SETMODIFY\n");
4782
4783 /* clearing modify flag should actually clear it */
4784 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4785 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4786 ok (result == 0,
4787 "EM_GETMODIFY returned non-zero, instead of zero on EM_SETMODIFY\n");
4788
4789 /* setting font doesn't change modify flag */
4790 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4791 SendMessageA(hwndRichEdit, WM_SETFONT, (WPARAM)testFont, MAKELPARAM(TRUE, 0));
4792 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4793 ok (result == 0,
4794 "EM_GETMODIFY returned non-zero, instead of zero on setting font\n");
4795
4796 /* setting text should set modify flag */
4797 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4798 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
4799 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4800 ok (result != 0,
4801 "EM_GETMODIFY returned zero, instead of non-zero on setting text\n");
4802
4803 /* undo previous text doesn't reset modify flag */
4804 SendMessageA(hwndRichEdit, WM_UNDO, 0, 0);
4805 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4806 ok (result != 0,
4807 "EM_GETMODIFY returned zero, instead of non-zero on undo after setting text\n");
4808
4809 /* set text with no flag to keep undo stack should not set modify flag */
4810 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4811 setText.flags = 0;
4812 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
4813 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4814 ok (result == 0,
4815 "EM_GETMODIFY returned non-zero, instead of zero when setting text while not keeping undo stack\n");
4816
4817 /* WM_SETTEXT doesn't modify */
4818 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4819 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem2);
4820 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4821 ok (result == 0,
4822 "EM_GETMODIFY returned non-zero for WM_SETTEXT\n");
4823
4824 /* clear the text */
4825 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4826 SendMessageA(hwndRichEdit, WM_CLEAR, 0, 0);
4827 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4828 ok (result == 0,
4829 "EM_GETMODIFY returned non-zero, instead of zero for WM_CLEAR\n");
4830
4831 /* replace text */
4832 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4833 SendMessageA(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
4834 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2);
4835 SendMessageA(hwndRichEdit, EM_REPLACESEL, TRUE, (LPARAM)TestItem2);
4836 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4837 ok (result != 0,
4838 "EM_GETMODIFY returned zero, instead of non-zero when replacing text\n");
4839
4840 /* copy/paste text 1 */
4841 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4842 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2);
4843 SendMessageA(hwndRichEdit, WM_COPY, 0, 0);
4844 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
4845 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4846 ok (result != 0,
4847 "EM_GETMODIFY returned zero, instead of non-zero when pasting identical text\n");
4848
4849 /* copy/paste text 2 */
4850 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4851 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 2);
4852 SendMessageA(hwndRichEdit, WM_COPY, 0, 0);
4853 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 3);
4854 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
4855 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4856 ok (result != 0,
4857 "EM_GETMODIFY returned zero, instead of non-zero when pasting different text\n");
4858
4859 /* press char */
4860 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4861 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 1);
4862 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0);
4863 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4864 ok (result != 0,
4865 "EM_GETMODIFY returned zero, instead of non-zero for WM_CHAR\n");
4866
4867 /* press del */
4868 SendMessageA(hwndRichEdit, WM_CHAR, 'A', 0);
4869 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4870 SendMessageA(hwndRichEdit, WM_KEYDOWN, VK_BACK, 0);
4871 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4872 ok (result != 0,
4873 "EM_GETMODIFY returned zero, instead of non-zero for backspace\n");
4874
4875 /* set char format */
4876 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4877 cf2.cbSize = sizeof(CHARFORMAT2A);
4878 SendMessageA(hwndRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf2);
4879 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
4880 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
4881 SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2);
4882 result = SendMessageA(hwndRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2);
4883 ok(result == 1, "EM_SETCHARFORMAT returned %ld instead of 1\n", result);
4884 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4885 ok (result != 0,
4886 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETCHARFORMAT\n");
4887
4888 /* set para format */
4889 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4890 pf2.cbSize = sizeof(PARAFORMAT2);
4891 SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&pf2);
4892 pf2.dwMask = PFM_ALIGNMENT | pf2.dwMask;
4893 pf2.wAlignment = PFA_RIGHT;
4894 SendMessageA(hwndRichEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
4895 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4896 ok (result == 0,
4897 "EM_GETMODIFY returned zero, instead of non-zero for EM_SETPARAFORMAT\n");
4898
4899 /* EM_STREAM */
4900 SendMessageA(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
4901 es.dwCookie = (DWORD_PTR)&streamText;
4902 es.dwError = 0;
4903 es.pfnCallback = test_EM_GETMODIFY_esCallback;
4904 SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es);
4905 result = SendMessageA(hwndRichEdit, EM_GETMODIFY, 0, 0);
4906 ok (result != 0,
4907 "EM_GETMODIFY returned zero, instead of non-zero for EM_STREAM\n");
4908
4909 DestroyWindow(hwndRichEdit);
4910}
4911
4919};
4920
4921static const struct exsetsel_s exsetsel_tests[] = {
4922 /* sanity tests */
4923 {5, 10, 10, 5, 10 },
4924 {15, 17, 17, 15, 17 },
4925 /* test cpMax > strlen() */
4926 {0, 100, 18, 0, 18 },
4927 /* test cpMin < 0 && cpMax >= 0 after cpMax > strlen() */
4928 {-1, 1, 17, 17, 17 },
4929 /* test cpMin == cpMax */
4930 {5, 5, 5, 5, 5 },
4931 /* test cpMin < 0 && cpMax >= 0 (bug 4462) */
4932 {-1, 0, 5, 5, 5 },
4933 {-1, 17, 5, 5, 5 },
4934 {-1, 18, 5, 5, 5 },
4935 /* test cpMin < 0 && cpMax < 0 */
4936 {-1, -1, 17, 17, 17 },
4937 {-4, -5, 17, 17, 17 },
4938 /* test cpMin >=0 && cpMax < 0 (bug 6814) */
4939 {0, -1, 18, 0, 18 },
4940 {17, -5, 18, 17, 18 },
4941 {18, -3, 17, 17, 17 },
4942 /* test if cpMin > cpMax */
4943 {15, 19, 18, 15, 18 },
4944 {19, 15, 18, 15, 18 },
4945 /* cpMin == strlen() && cpMax > cpMin */
4946 {17, 18, 18, 17, 18 },
4947 {17, 50, 18, 17, 18 },
4948};
4949
4950static void check_EM_EXSETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) {
4951 CHARRANGE cr;
4953 int start, end;
4954
4955 cr.cpMin = setsel->min;
4956 cr.cpMax = setsel->max;
4958
4959 ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
4960
4962
4963 todo_wine_if (setsel->todo)
4964 ok(start == setsel->expected_getsel_start && end == setsel->expected_getsel_end, "EM_EXSETSEL(%d): expected (%d,%d) actual:(%d,%d)\n",
4965 id, setsel->expected_getsel_start, setsel->expected_getsel_end, start, end);
4966}
4967
4968static void test_EM_EXSETSEL(void)
4969{
4970 HWND hwndRichEdit = new_richedit(NULL);
4971 int i;
4972 const int num_tests = ARRAY_SIZE(exsetsel_tests);
4973
4974 /* sending some text to the window */
4975 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection");
4976 /* 01234567890123456*/
4977 /* 10 */
4978
4979 for (i = 0; i < num_tests; i++) {
4980 check_EM_EXSETSEL(hwndRichEdit, &exsetsel_tests[i], i);
4981 }
4982
4983 if (!is_lang_japanese)
4984 skip("Skip multibyte character tests on non-Japanese platform\n");
4985 else
4986 {
4987 CHARRANGE cr;
4988 char bufA[MAX_BUF_LEN] = {0};
4990
4991 /* Test with multibyte character */
4992 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk");
4993 /* 012345 6 78901 */
4994 cr.cpMin = 4; cr.cpMax = 8;
4995 result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
4996 ok(result == 8, "EM_EXSETSEL return %ld expected 8\n", result);
4997 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, sizeof(bufA), (LPARAM)bufA);
4998 ok(!strcmp(bufA, "ef\x8e\xf0g"), "EM_GETSELTEXT return incorrect string\n");
4999 SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5000 ok(cr.cpMin == 4, "Selection start incorrectly: %d expected 4\n", cr.cpMin);
5001 ok(cr.cpMax == 8, "Selection end incorrectly: %d expected 8\n", cr.cpMax);
5002 }
5003
5004 DestroyWindow(hwndRichEdit);
5005}
5006
5007static void check_EM_SETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) {
5009 int start, end;
5010
5011 result = SendMessageA(hwnd, EM_SETSEL, setsel->min, setsel->max);
5012
5013 ok(result == setsel->expected_retval, "EM_SETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
5014
5016
5017 todo_wine_if (setsel->todo)
5018 ok(start == setsel->expected_getsel_start && end == setsel->expected_getsel_end, "EM_SETSEL(%d): expected (%d,%d) actual:(%d,%d)\n",
5019 id, setsel->expected_getsel_start, setsel->expected_getsel_end, start, end);
5020}
5021
5022static void test_EM_SETSEL(void)
5023{
5024 char buffA[32] = {0};
5025 HWND hwndRichEdit = new_richedit(NULL);
5026 int i;
5027 const int num_tests = ARRAY_SIZE(exsetsel_tests);
5028
5029 /* sending some text to the window */
5030 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection");
5031 /* 01234567890123456*/
5032 /* 10 */
5033
5034 for (i = 0; i < num_tests; i++) {
5035 check_EM_SETSEL(hwndRichEdit, &exsetsel_tests[i], i);
5036 }
5037
5038 SendMessageA(hwndRichEdit, EM_SETSEL, 17, 18);
5039 buffA[0] = 123;
5040 SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffA);
5041 ok(buffA[0] == 0, "selection text %s\n", buffA);
5042
5043 if (!is_lang_japanese)
5044 skip("Skip multibyte character tests on non-Japanese platform\n");
5045 else
5046 {
5047 int sel_start, sel_end;
5049
5050 /* Test with multibyte character */
5051 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk");
5052 /* 012345 6 78901 */
5053 result = SendMessageA(hwndRichEdit, EM_SETSEL, 4, 8);
5054 ok(result == 8, "EM_SETSEL return %ld expected 8\n", result);
5055 result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, sizeof(buffA), (LPARAM)buffA);
5056 ok(!strcmp(buffA, "ef\x8e\xf0g"), "EM_GETSELTEXT return incorrect string\n");
5057 result = SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
5058 ok(sel_start == 4, "Selection start incorrectly: %d expected 4\n", sel_start);
5059 ok(sel_end == 8, "Selection end incorrectly: %d expected 8\n", sel_end);
5060 }
5061
5062 DestroyWindow(hwndRichEdit);
5063}
5064
5066{
5067 HWND hwndRichEdit = new_richedit(NULL);
5068 char buffer[1024] = {0};
5069 int r;
5070 GETTEXTEX getText;
5071 CHARRANGE cr;
5072 CHAR rtfstream[] = "{\\rtf1 TestSomeText}";
5073 CHAR urtfstream[] = "{\\urtf1 TestSomeText}";
5074
5075 /* sending some text to the window */
5076 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection");
5077 /* 01234567890123456*/
5078 /* 10 */
5079
5080 /* FIXME add more tests */
5081 SendMessageA(hwndRichEdit, EM_SETSEL, 7, 17);
5082 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, 0);
5083 ok(0 == r, "EM_REPLACESEL returned %d, expected 0\n", r);
5084 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5085 r = strcmp(buffer, "testing");
5086 ok(0 == r, "expected %d, got %d\n", 0, r);
5087
5088 DestroyWindow(hwndRichEdit);
5089
5090 hwndRichEdit = new_richedit(NULL);
5091
5092 trace("Testing EM_REPLACESEL behavior with redraw=%d\n", redraw);
5093 SendMessageA(hwndRichEdit, WM_SETREDRAW, redraw, 0);
5094
5095 /* Test behavior with carriage returns and newlines */
5096 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5097 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"RichEdit1");
5098 ok(9 == r, "EM_REPLACESEL returned %d, expected 9\n", r);
5099 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5100 r = strcmp(buffer, "RichEdit1");
5101 ok(0 == r, "expected %d, got %d\n", 0, r);
5102 getText.cb = 1024;
5103 getText.codepage = CP_ACP;
5104 getText.flags = GT_DEFAULT;
5105 getText.lpDefaultChar = NULL;
5106 getText.lpUsedDefChar = NULL;
5107 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5108 ok(strcmp(buffer, "RichEdit1") == 0,
5109 "EM_GETTEXTEX results not what was set by EM_REPLACESEL\n");
5110
5111 /* Test number of lines reported after EM_REPLACESEL */
5112 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5113 ok(r == 1, "EM_GETLINECOUNT returned %d, expected 1\n", r);
5114
5115 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5116 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"RichEdit1\r");
5117 ok(10 == r, "EM_REPLACESEL returned %d, expected 10\n", r);
5118 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5119 r = strcmp(buffer, "RichEdit1\r\n");
5120 ok(0 == r, "expected %d, got %d\n", 0, r);
5121 getText.cb = 1024;
5122 getText.codepage = CP_ACP;
5123 getText.flags = GT_DEFAULT;
5124 getText.lpDefaultChar = NULL;
5125 getText.lpUsedDefChar = NULL;
5126 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5127 ok(strcmp(buffer, "RichEdit1\r") == 0,
5128 "EM_GETTEXTEX returned incorrect string\n");
5129
5130 /* Test number of lines reported after EM_REPLACESEL */
5131 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5132 ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r);
5133
5134 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5135 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"RichEdit1\r\n");
5136 ok(r == 11, "EM_REPLACESEL returned %d, expected 11\n", r);
5137
5138 /* Test number of lines reported after EM_REPLACESEL */
5139 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5140 ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r);
5141
5142 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5143 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5144 ok(cr.cpMin == 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr.cpMin);
5145 ok(cr.cpMax == 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr.cpMax);
5146
5147 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5148 r = strcmp(buffer, "RichEdit1\r\n");
5149 ok(0 == r, "expected %d, got %d\n", 0, r);
5150 getText.cb = 1024;
5151 getText.codepage = CP_ACP;
5152 getText.flags = GT_DEFAULT;
5153 getText.lpDefaultChar = NULL;
5154 getText.lpUsedDefChar = NULL;
5155 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5156 ok(strcmp(buffer, "RichEdit1\r") == 0,
5157 "EM_GETTEXTEX returned incorrect string\n");
5158
5159 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5160 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5161 ok(cr.cpMin == 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr.cpMin);
5162 ok(cr.cpMax == 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr.cpMax);
5163
5164 /* The following tests show that richedit should handle the special \r\r\n
5165 sequence by turning it into a single space on insertion. However,
5166 EM_REPLACESEL on WinXP returns the number of characters in the original
5167 string.
5168 */
5169
5170 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5171 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r");
5172 ok(2 == r, "EM_REPLACESEL returned %d, expected 4\n", r);
5173 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5174 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5175 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin);
5176 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax);
5177
5178 /* Test the actual string */
5179 getText.cb = 1024;
5180 getText.codepage = CP_ACP;
5181 getText.flags = GT_DEFAULT;
5182 getText.lpDefaultChar = NULL;
5183 getText.lpUsedDefChar = NULL;
5184 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5185 ok(strcmp(buffer, "\r\r") == 0,
5186 "EM_GETTEXTEX returned incorrect string\n");
5187
5188 /* Test number of lines reported after EM_REPLACESEL */
5189 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5190 ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r);
5191
5192 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5193 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r\n");
5194 ok(r == 3, "EM_REPLACESEL returned %d, expected 3\n", r);
5195 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5196 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5197 ok(cr.cpMin == 1, "EM_EXGETSEL returned cpMin=%d, expected 1\n", cr.cpMin);
5198 ok(cr.cpMax == 1, "EM_EXGETSEL returned cpMax=%d, expected 1\n", cr.cpMax);
5199
5200 /* Test the actual string */
5201 getText.cb = 1024;
5202 getText.codepage = CP_ACP;
5203 getText.flags = GT_DEFAULT;
5204 getText.lpDefaultChar = NULL;
5205 getText.lpUsedDefChar = NULL;
5206 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5207 ok(strcmp(buffer, " ") == 0,
5208 "EM_GETTEXTEX returned incorrect string\n");
5209
5210 /* Test number of lines reported after EM_REPLACESEL */
5211 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5212 ok(r == 1, "EM_GETLINECOUNT returned %d, expected 1\n", r);
5213
5214 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5215 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r\r\r\r\n\r\r\r");
5216 ok(r == 9, "EM_REPLACESEL returned %d, expected 9\n", r);
5217 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5218 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5219 ok(cr.cpMin == 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr.cpMin);
5220 ok(cr.cpMax == 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr.cpMax);
5221
5222 /* Test the actual string */
5223 getText.cb = 1024;
5224 getText.codepage = CP_ACP;
5225 getText.flags = GT_DEFAULT;
5226 getText.lpDefaultChar = NULL;
5227 getText.lpUsedDefChar = NULL;
5228 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5229 ok(strcmp(buffer, "\r\r\r \r\r\r") == 0,
5230 "EM_GETTEXTEX returned incorrect string\n");
5231
5232 /* Test number of lines reported after EM_REPLACESEL */
5233 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5234 ok(r == 7, "EM_GETLINECOUNT returned %d, expected 7\n", r);
5235
5236 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5237 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r\n\r\n");
5238 ok(r == 5, "EM_REPLACESEL returned %d, expected 5\n", r);
5239 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5240 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5241 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin);
5242 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax);
5243
5244 /* Test the actual string */
5245 getText.cb = 1024;
5246 getText.codepage = CP_ACP;
5247 getText.flags = GT_DEFAULT;
5248 getText.lpDefaultChar = NULL;
5249 getText.lpUsedDefChar = NULL;
5250 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5251 ok(strcmp(buffer, " \r") == 0,
5252 "EM_GETTEXTEX returned incorrect string\n");
5253
5254 /* Test number of lines reported after EM_REPLACESEL */
5255 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5256 ok(r == 2, "EM_GETLINECOUNT returned %d, expected 2\n", r);
5257
5258 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5259 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\r\r\n\r\r");
5260 ok(r == 5, "EM_REPLACESEL returned %d, expected 5\n", r);
5261 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5262 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5263 ok(cr.cpMin == 3, "EM_EXGETSEL returned cpMin=%d, expected 3\n", cr.cpMin);
5264 ok(cr.cpMax == 3, "EM_EXGETSEL returned cpMax=%d, expected 3\n", cr.cpMax);
5265
5266 /* Test the actual string */
5267 getText.cb = 1024;
5268 getText.codepage = CP_ACP;
5269 getText.flags = GT_DEFAULT;
5270 getText.lpDefaultChar = NULL;
5271 getText.lpUsedDefChar = NULL;
5272 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5273 ok(strcmp(buffer, " \r\r") == 0,
5274 "EM_GETTEXTEX returned incorrect string\n");
5275
5276 /* Test number of lines reported after EM_REPLACESEL */
5277 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5278 ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r);
5279
5280 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5281 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\rX\r\n\r\r");
5282 ok(r == 6, "EM_REPLACESEL returned %d, expected 6\n", r);
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 == 5, "EM_EXGETSEL returned cpMin=%d, expected 5\n", cr.cpMin);
5286 ok(cr.cpMax == 5, "EM_EXGETSEL returned cpMax=%d, expected 5\n", cr.cpMax);
5287
5288 /* Test the actual string */
5289 getText.cb = 1024;
5290 getText.codepage = CP_ACP;
5291 getText.flags = GT_DEFAULT;
5292 getText.lpDefaultChar = NULL;
5293 getText.lpUsedDefChar = NULL;
5294 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5295 ok(strcmp(buffer, "\rX\r\r\r") == 0,
5296 "EM_GETTEXTEX returned incorrect string\n");
5297
5298 /* Test number of lines reported after EM_REPLACESEL */
5299 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5300 ok(r == 5, "EM_GETLINECOUNT returned %d, expected 5\n", r);
5301
5302 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5303 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\n\n");
5304 ok(2 == r, "EM_REPLACESEL returned %d, expected 2\n", r);
5305 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5306 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5307 ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin);
5308 ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax);
5309
5310 /* Test the actual string */
5311 getText.cb = 1024;
5312 getText.codepage = CP_ACP;
5313 getText.flags = GT_DEFAULT;
5314 getText.lpDefaultChar = NULL;
5315 getText.lpUsedDefChar = NULL;
5316 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5317 ok(strcmp(buffer, "\r\r") == 0,
5318 "EM_GETTEXTEX returned incorrect string\n");
5319
5320 /* Test number of lines reported after EM_REPLACESEL */
5321 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5322 ok(r == 3, "EM_GETLINECOUNT returned %d, expected 3\n", r);
5323
5324 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5325 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"\n\n\n\n\r\r\r\r\n");
5326 ok(r == 9, "EM_REPLACESEL returned %d, expected 9\n", r);
5327 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5328 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5329 ok(cr.cpMin == 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr.cpMin);
5330 ok(cr.cpMax == 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr.cpMax);
5331
5332 /* Test the actual string */
5333 getText.cb = 1024;
5334 getText.codepage = CP_ACP;
5335 getText.flags = GT_DEFAULT;
5336 getText.lpDefaultChar = NULL;
5337 getText.lpUsedDefChar = NULL;
5338 SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buffer);
5339 ok(strcmp(buffer, "\r\r\r\r\r\r ") == 0,
5340 "EM_GETTEXTEX returned incorrect string\n");
5341
5342 /* Test number of lines reported after EM_REPLACESEL */
5343 r = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
5344 ok(r == 7, "EM_GETLINECOUNT returned %d, expected 7\n", r);
5345
5346 /* Test with multibyte character */
5347 if (!is_lang_japanese)
5348 skip("Skip multibyte character tests on non-Japanese platform\n");
5349 else
5350 {
5351 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5352 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"abc\x8e\xf0");
5353 todo_wine ok(r == 5, "EM_REPLACESEL returned %d, expected 5\n", r);
5354 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5355 ok(r == 0, "EM_EXGETSEL returned %d, expected 0\n", r);
5356 ok(cr.cpMin == 4, "EM_EXGETSEL returned cpMin=%d, expected 4\n", cr.cpMin);
5357 ok(cr.cpMax == 4, "EM_EXGETSEL returned cpMax=%d, expected 4\n", cr.cpMax);
5358 r = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5359 ok(!strcmp(buffer, "abc\x8e\xf0"), "WM_GETTEXT returned incorrect string\n");
5360 ok(r == 5, "WM_GETTEXT returned %d, expected 5\n", r);
5361
5362 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5363 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"{\\rtf abc\x8e\xf0}");
5364 todo_wine ok(r == 4, "EM_REPLACESEL returned %d, expected 4\n", r);
5365 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5366 ok(r == 0, "EM_EXGETSEL returned %d, expected 0\n", r);
5367 todo_wine ok(cr.cpMin == 4, "EM_EXGETSEL returned cpMin=%d, expected 4\n", cr.cpMin);
5368 todo_wine ok(cr.cpMax == 4, "EM_EXGETSEL returned cpMax=%d, expected 4\n", cr.cpMax);
5369 r = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5370 todo_wine ok(!strcmp(buffer, "abc\x8e\xf0"), "WM_GETTEXT returned incorrect string\n");
5371 todo_wine ok(r == 5, "WM_GETTEXT returned %d, expected 5\n", r);
5372 }
5373
5374 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5375 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)rtfstream);
5376 todo_wine ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r);
5377 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5378 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5379 todo_wine ok(cr.cpMin == 12, "EM_EXGETSEL returned cpMin=%d, expected 12\n", cr.cpMin);
5380 todo_wine ok(cr.cpMax == 12, "EM_EXGETSEL returned cpMax=%d, expected 12\n", cr.cpMax);
5381 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5382 todo_wine ok(!strcmp(buffer, "TestSomeText"), "WM_GETTEXT returned incorrect string\n");
5383
5384 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5385 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)urtfstream);
5386 todo_wine ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r);
5387 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5388 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5389 todo_wine ok(cr.cpMin == 12, "EM_EXGETSEL returned cpMin=%d, expected 12\n", cr.cpMin);
5390 todo_wine ok(cr.cpMax == 12, "EM_EXGETSEL returned cpMax=%d, expected 12\n", cr.cpMax);
5391 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5392 todo_wine ok(!strcmp(buffer, "TestSomeText"), "WM_GETTEXT returned incorrect string\n");
5393
5394 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"Wine");
5395 SendMessageA(hwndRichEdit, EM_SETSEL, 1, 2);
5396 todo_wine r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)rtfstream);
5397 todo_wine ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r);
5398 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5399 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5400 todo_wine ok(cr.cpMin == 13, "EM_EXGETSEL returned cpMin=%d, expected 13\n", cr.cpMin);
5401 todo_wine ok(cr.cpMax == 13, "EM_EXGETSEL returned cpMax=%d, expected 13\n", cr.cpMax);
5402 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5403 todo_wine ok(!strcmp(buffer, "WTestSomeTextne"), "WM_GETTEXT returned incorrect string\n");
5404
5405 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"{\\rtf1 Wine}");
5406 SendMessageA(hwndRichEdit, EM_SETSEL, 1, 2);
5407 todo_wine r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)rtfstream);
5408 todo_wine ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r);
5409 r = SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
5410 ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
5411 todo_wine ok(cr.cpMin == 13, "EM_EXGETSEL returned cpMin=%d, expected 13\n", cr.cpMin);
5412 todo_wine ok(cr.cpMax == 13, "EM_EXGETSEL returned cpMax=%d, expected 13\n", cr.cpMax);
5413 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5414 todo_wine ok(!strcmp(buffer, "WTestSomeTextne"), "WM_GETTEXT returned incorrect string\n");
5415
5416 if (!redraw)
5417 /* This is needed to avoid interfering with keybd_event calls
5418 * on other tests that simulate keyboard events. */
5419 SendMessageA(hwndRichEdit, WM_SETREDRAW, TRUE, 0);
5420
5421 DestroyWindow(hwndRichEdit);
5422
5423 /* Single-line richedit */
5424 hwndRichEdit = new_richedit_with_style(NULL, 0);
5425 r = SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"line1\r\nline2");
5426 ok(r == 12, "EM_REPLACESEL returned %d, expected 12\n", r);
5427 r = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5428 ok(r == 5, "WM_GETTEXT returned %d, expected 5\n", r);
5429 ok(!strcmp(buffer, "line1"), "WM_GETTEXT returned incorrect string '%s'\n", buffer);
5430 DestroyWindow(hwndRichEdit);
5431}
5432
5433/* Native riched20 inspects the keyboard state (e.g. GetKeyState)
5434 * to test the state of the modifiers (Ctrl/Alt/Shift).
5435 *
5436 * Therefore Ctrl-<key> keystrokes need to be simulated with
5437 * keybd_event or by using SetKeyboardState to set the modifiers
5438 * and SendMessage to simulate the keystrokes.
5439 */
5441{
5446 return result;
5447}
5448
5449static void test_WM_PASTE(void)
5450{
5451 int result;
5452 char buffer[1024] = {0};
5453 const char* text1 = "testing paste\r";
5454 const char* text1_step1 = "testing paste\r\ntesting paste\r\n";
5455 const char* text1_after = "testing paste\r\n";
5456 const char* text2 = "testing paste\r\rtesting paste";
5457 const char* text2_after = "testing paste\r\n\r\ntesting paste";
5458 const char* text3 = "testing paste\r\npaste\r\ntesting paste";
5459 HWND hwndRichEdit = new_richedit(NULL);
5460
5461 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
5462 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 14);
5463
5464 send_ctrl_key(hwndRichEdit, 'C'); /* Copy */
5465 SendMessageA(hwndRichEdit, EM_SETSEL, 14, 14);
5466 send_ctrl_key(hwndRichEdit, 'V'); /* Paste */
5467 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5468 /* Pasted text should be visible at this step */
5469 result = strcmp(text1_step1, buffer);
5470 ok(result == 0,
5471 "test paste: strcmp = %i, text='%s'\n", result, buffer);
5472
5473 send_ctrl_key(hwndRichEdit, 'Z'); /* Undo */
5474 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5475 /* Text should be the same as before (except for \r -> \r\n conversion) */
5476 result = strcmp(text1_after, buffer);
5477 ok(result == 0,
5478 "test paste: strcmp = %i, text='%s'\n", result, buffer);
5479
5480 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
5481 SendMessageA(hwndRichEdit, EM_SETSEL, 8, 13);
5482 send_ctrl_key(hwndRichEdit, 'C'); /* Copy */
5483 SendMessageA(hwndRichEdit, EM_SETSEL, 14, 14);
5484 send_ctrl_key(hwndRichEdit, 'V'); /* Paste */
5485 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5486 /* Pasted text should be visible at this step */
5487 result = strcmp(text3, buffer);
5488 ok(result == 0,
5489 "test paste: strcmp = %i\n", result);
5490 send_ctrl_key(hwndRichEdit, 'Z'); /* Undo */
5491 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5492 /* Text should be the same as before (except for \r -> \r\n conversion) */
5493 result = strcmp(text2_after, buffer);
5494 ok(result == 0,
5495 "test paste: strcmp = %i\n", result);
5496 send_ctrl_key(hwndRichEdit, 'Y'); /* Redo */
5497 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5498 /* Text should revert to post-paste state */
5499 result = strcmp(buffer,text3);
5500 ok(result == 0,
5501 "test paste: strcmp = %i\n", result);
5502
5503 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5504 /* Send WM_CHAR to simulate Ctrl-V */
5505 SendMessageA(hwndRichEdit, WM_CHAR, 22,
5506 (MapVirtualKeyA('V', MAPVK_VK_TO_VSC) << 16) | 1);
5507 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5508 /* Shouldn't paste because pasting is handled by WM_KEYDOWN */
5509 result = strcmp(buffer,"");
5510 ok(result == 0,
5511 "test paste: strcmp = %i, actual = '%s'\n", result, buffer);
5512
5513 /* Send keystrokes with WM_KEYDOWN after setting the modifiers
5514 * with SetKeyboard state. */
5515
5516 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5517 /* Simulates paste (Ctrl-V) */
5519 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'V',
5520 (MapVirtualKeyA('V', MAPVK_VK_TO_VSC) << 16) | 1);
5522 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5523 result = strcmp(buffer,"paste");
5524 ok(result == 0,
5525 "test paste: strcmp = %i, actual = '%s'\n", result, buffer);
5526
5527 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
5528 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 7);
5529 /* Simulates copy (Ctrl-C) */
5531 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'C',
5532 (MapVirtualKeyA('C', MAPVK_VK_TO_VSC) << 16) | 1);
5534 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5535 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
5536 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5537 result = strcmp(buffer,"testing");
5538 ok(result == 0,
5539 "test paste: strcmp = %i, actual = '%s'\n", result, buffer);
5540
5541 /* Cut with WM_KEYDOWN to simulate Ctrl-X */
5542 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"cut");
5543 /* Simulates select all (Ctrl-A) */
5545 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'A',
5546 (MapVirtualKeyA('A', MAPVK_VK_TO_VSC) << 16) | 1);
5547 /* Simulates select cut (Ctrl-X) */
5548 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'X',
5549 (MapVirtualKeyA('X', MAPVK_VK_TO_VSC) << 16) | 1);
5551 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5552 result = strcmp(buffer,"");
5553 ok(result == 0,
5554 "test paste: strcmp = %i, actual = '%s'\n", result, buffer);
5555 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, 0);
5556 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
5557 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5558 result = strcmp(buffer,"cut\r\n");
5559 ok(result == 0,
5560 "test paste: strcmp = %i, actual = '%s'\n", result, buffer);
5561 /* Simulates undo (Ctrl-Z) */
5563 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'Z',
5564 (MapVirtualKeyA('Z', MAPVK_VK_TO_VSC) << 16) | 1);
5565 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5566 result = strcmp(buffer,"");
5567 ok(result == 0,
5568 "test paste: strcmp = %i, actual = '%s'\n", result, buffer);
5569 /* Simulates redo (Ctrl-Y) */
5570 SendMessageA(hwndRichEdit, WM_KEYDOWN, 'Y',
5571 (MapVirtualKeyA('Y', MAPVK_VK_TO_VSC) << 16) | 1);
5572 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5573 result = strcmp(buffer,"cut\r\n");
5574 ok(result == 0,
5575 "test paste: strcmp = %i, actual = '%s'\n", result, buffer);
5577
5578 /* Copy multiline text to clipboard for future use */
5579 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text3);
5580 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
5581 SendMessageA(hwndRichEdit, WM_COPY, 0, 0);
5582 SendMessageA(hwndRichEdit, EM_SETSEL, 0, 0);
5583
5584 /* Paste into read-only control */
5585 result = SendMessageA(hwndRichEdit, EM_SETREADONLY, TRUE, 0);
5586 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
5587 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5588 result = strcmp(buffer, text3);
5589 ok(result == 0,
5590 "test paste: strcmp = %i, actual = '%s'\n", result, buffer);
5591
5592 /* Cut from read-only control */
5593 SendMessageA(hwndRichEdit, EM_SETSEL, 0, -1);
5594 SendMessageA(hwndRichEdit, WM_CUT, 0, 0);
5595 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5596 result = strcmp(buffer, text3);
5597 ok(result == 0,
5598 "test paste: strcmp = %i, actual = '%s'\n", result, buffer);
5599
5600 /* FIXME: Wine doesn't flush Ole clipboard when window is destroyed so do it manually */
5602 DestroyWindow(hwndRichEdit);
5603
5604 /* Paste multi-line text into single-line control */
5605 hwndRichEdit = new_richedit_with_style(NULL, 0);
5606 SendMessageA(hwndRichEdit, WM_PASTE, 0, 0);
5607 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5608 result = strcmp(buffer, "testing paste");
5609 ok(result == 0,
5610 "test paste: strcmp = %i, actual = '%s'\n", result, buffer);
5611 DestroyWindow(hwndRichEdit);
5612}
5613
5614static void test_EM_FORMATRANGE(void)
5615{
5616 int r, i, tpp_x, tpp_y;
5617 HDC hdc;
5618 HWND hwndRichEdit = new_richedit(NULL);
5619 FORMATRANGE fr;
5620 BOOL skip_non_english;
5621 static const struct {
5622 const char *string; /* The string */
5623 int first; /* First 'pagebreak', 0 for don't care */
5624 int second; /* Second 'pagebreak', 0 for don't care */
5625 } fmtstrings[] = {
5626 {"WINE wine", 0, 0},
5627 {"WINE wineWine", 0, 0},
5628 {"WINE\r\nwine\r\nwine", 5, 10},
5629 {"WINE\r\nWINEwine\r\nWINEwine", 5, 14},
5630 {"WINE\r\n\r\nwine\r\nwine", 5, 6}
5631 };
5632
5633 skip_non_english = (PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH);
5634 if (skip_non_english)
5635 skip("Skipping some tests on non-English platform\n");
5636
5637 hdc = GetDC(hwndRichEdit);
5638 ok(hdc != NULL, "Could not get HDC\n");
5639
5640 /* Calculate the twips per pixel */
5641 tpp_x = 1440 / GetDeviceCaps(hdc, LOGPIXELSX);
5642 tpp_y = 1440 / GetDeviceCaps(hdc, LOGPIXELSY);
5643
5644 /* Test the simple case where all the text fits in the page rect. */
5645 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"a");
5646 fr.hdc = fr.hdcTarget = hdc;
5647 fr.rc.top = fr.rcPage.top = fr.rc.left = fr.rcPage.left = 0;
5648 fr.rc.right = fr.rcPage.right = 500 * tpp_x;
5649 fr.rc.bottom = fr.rcPage.bottom = 500 * tpp_y;
5650 fr.chrg.cpMin = 0;
5651 fr.chrg.cpMax = -1;
5652 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, FALSE, (LPARAM)&fr);
5653 todo_wine ok(r == 2, "r=%d expected r=2\n", r);
5654
5655 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"ab");
5656 fr.rc.bottom = fr.rcPage.bottom;
5657 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, FALSE, (LPARAM)&fr);
5658 todo_wine ok(r == 3, "r=%d expected r=3\n", r);
5659
5660 SendMessageA(hwndRichEdit, EM_FORMATRANGE, FALSE, 0);
5661
5662 for (i = 0; i < ARRAY_SIZE(fmtstrings); i++)
5663 {
5664 GETTEXTLENGTHEX gtl;
5665 SIZE stringsize;
5666 int len;
5667
5668 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)fmtstrings[i].string);
5669
5671 gtl.codepage = CP_ACP;
5672 len = SendMessageA(hwndRichEdit, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
5673
5674 /* Get some size information for the string */
5675 GetTextExtentPoint32A(hdc, fmtstrings[i].string, strlen(fmtstrings[i].string), &stringsize);
5676
5677 /* Define the box to be half the width needed and a bit larger than the height.
5678 * Changes to the width means we have at least 2 pages. Changes to the height
5679 * is done so we can check the changing of fr.rc.bottom.
5680 */
5681 fr.hdc = fr.hdcTarget = hdc;
5682 fr.rc.top = fr.rcPage.top = fr.rc.left = fr.rcPage.left = 0;
5683 fr.rc.right = fr.rcPage.right = (stringsize.cx / 2) * tpp_x;
5684 fr.rc.bottom = fr.rcPage.bottom = (stringsize.cy + 10) * tpp_y;
5685
5686 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, TRUE, 0);
5687 todo_wine {
5688 ok(r == len, "Expected %d, got %d\n", len, r);
5689 }
5690
5691 /* We know that the page can't hold the full string. See how many characters
5692 * are on the first one
5693 */
5694 fr.chrg.cpMin = 0;
5695 fr.chrg.cpMax = -1;
5696 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM)&fr);
5697 todo_wine {
5698 if (! skip_non_english)
5699 ok(fr.rc.bottom == (stringsize.cy * tpp_y), "Expected bottom to be %d, got %d\n", (stringsize.cy * tpp_y), fr.rc.bottom);
5700 }
5701 if (fmtstrings[i].first)
5702 todo_wine {
5703 ok(r == fmtstrings[i].first, "Expected %d, got %d\n", fmtstrings[i].first, r);
5704 }
5705 else
5706 ok(r < len, "Expected < %d, got %d\n", len, r);
5707
5708 /* Do another page */
5709 fr.chrg.cpMin = r;
5710 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM)&fr);
5711 if (fmtstrings[i].second)
5712 todo_wine {
5713 ok(r == fmtstrings[i].second, "Expected %d, got %d\n", fmtstrings[i].second, r);
5714 }
5715 else if (! skip_non_english)
5716 ok (r < len, "Expected < %d, got %d\n", len, r);
5717
5718 /* There is at least on more page, but we don't care */
5719
5720 r = SendMessageA(hwndRichEdit, EM_FORMATRANGE, TRUE, 0);
5721 todo_wine {
5722 ok(r == len, "Expected %d, got %d\n", len, r);
5723 }
5724 }
5725
5726 ReleaseDC(NULL, hdc);
5727 DestroyWindow(hwndRichEdit);
5728}
5729
5730static int nCallbackCount = 0;
5731
5733 LONG cb, LONG* pcb)
5734{
5735 const char text[] = {'t','e','s','t'};
5736
5737 if (sizeof(text) <= cb)
5738 {
5739 if ((int)dwCookie != nCallbackCount)
5740 {
5741 *pcb = 0;
5742 return 0;
5743 }
5744
5745 memcpy (pbBuff, text, sizeof(text));
5746 *pcb = sizeof(text);
5747
5749
5750 return 0;
5751 }
5752 else
5753 return 1; /* indicates callback failed */
5754}
5755
5757 LPBYTE pbBuff,
5758 LONG cb,
5759 LONG *pcb)
5760{
5761 const char** str = (const char**)dwCookie;
5762 int size = strlen(*str);
5763 *pcb = cb;
5764 if (*pcb > size) {
5765 *pcb = size;
5766 }
5767 if (*pcb > 0) {
5768 memcpy(pbBuff, *str, *pcb);
5769 *str += *pcb;
5770 }
5771 return 0;
5772}
5773
5775 LPBYTE pbBuff,
5776 LONG cb,
5777 LONG *pcb)
5778{
5779 DWORD *phase = (DWORD *)dwCookie;
5780
5781 if(*phase == 0){
5782 static const char first[] = "\xef\xbb\xbf\xc3\x96\xc3";
5783 *pcb = sizeof(first) - 1;
5784 memcpy(pbBuff, first, *pcb);
5785 }else if(*phase == 1){
5786 static const char second[] = "\x8f\xc3\x8b";
5787 *pcb = sizeof(second) - 1;
5788 memcpy(pbBuff, second, *pcb);
5789 }else
5790 *pcb = 0;
5791
5792 ++*phase;
5793
5794 return 0;
5795}
5796
5798{
5799 DWORD *phase = (DWORD *)cookie;
5800
5801 if (*phase == 0)
5802 {
5803 static const char first[] = "{\\rtf1\\ansi{Th\0is";
5804 *written = sizeof(first);
5805 memcpy(buf, first, *written);
5806 }
5807 else if (*phase == 1)
5808 {
5809 static const char second[] = " is a test}}";
5810 *written = sizeof(second);
5811 memcpy(buf, second, *written);
5812 }
5813 else
5814 *written = 0;
5815
5816 ++*phase;
5817
5818 return 0;
5819}
5820
5823 char *buffer;
5824};
5825
5826/* This callback is used to handled the null characters in a string. */
5828 LPBYTE pbBuff,
5829 LONG cb,
5830 LONG *pcb)
5831{
5832 struct StringWithLength* str = (struct StringWithLength*)dwCookie;
5833 int size = str->length;
5834 *pcb = cb;
5835 if (*pcb > size) {
5836 *pcb = size;
5837 }
5838 if (*pcb > 0) {
5839 memcpy(pbBuff, str->buffer, *pcb);
5840 str->buffer += *pcb;
5841 str->length -= *pcb;
5842 }
5843 return 0;
5844}
5845
5846static void test_EM_STREAMIN(void)
5847{
5848 HWND hwndRichEdit = new_richedit(NULL);
5849 DWORD phase;
5851 EDITSTREAM es;
5852 char buffer[1024] = {0}, tmp[16];
5855
5856 const char * streamText0 = "{\\rtf1\\fi100\\li200\\rtlpar\\qr TestSomeText}";
5857 const char * streamText0a = "{\\rtf1\\fi100\\li200\\rtlpar\\qr TestSomeText\\par}";
5858 const char * streamText0b = "{\\rtf1 TestSomeText\\par\\par}";
5859 const char * ptr;
5860
5861 const char * streamText1 =
5862 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n"
5863 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n"
5864 "}\r\n";
5865
5866 /* In richedit 2.0 mode, this should NOT be accepted, unlike 1.0 */
5867 const char * streamText2 =
5868 "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;"
5869 "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255"
5870 "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 "
5871 "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 "
5872 "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 "
5873 "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 "
5874 "\\tx11448 \\tx11872 \\tx12296 \\tx12720 \\tx13144 \\cf2 RichEdit1\\line }";
5875
5876 const char * streamText3 = "RichEdit1";
5877
5878 const char * streamTextUTF8BOM = "\xef\xbb\xbfTestUTF8WithBOM";
5879
5880 const char * streamText4 =
5881 "This text just needs to be long enough to cause run to be split onto "
5882 "two separate lines and make sure the null terminating character is "
5883 "handled properly.\0";
5884
5885 const WCHAR UTF8Split_exp[4] = {0xd6, 0xcf, 0xcb, 0};
5886
5887 int length4 = strlen(streamText4) + 1;
5888 struct StringWithLength cookieForStream4 = {
5889 length4,
5890 (char *)streamText4,
5891 };
5892
5893 const WCHAR streamText5[] = { 'T', 'e', 's', 't', 'S', 'o', 'm', 'e', 'T', 'e', 'x', 't' };
5894 int length5 = ARRAY_SIZE(streamText5);
5895 struct StringWithLength cookieForStream5 = {
5896 sizeof(streamText5),
5897 (char *)streamText5,
5898 };
5899
5900 /* Minimal test without \par at the end */
5901 es.dwCookie = (DWORD_PTR)&streamText0;
5902 es.dwError = 0;
5903 es.pfnCallback = test_EM_STREAMIN_esCallback;
5904 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
5905 ok(result == 12, "got %ld, expected %d\n", result, 12);
5906
5907 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5908 ok (result == 12,
5909 "EM_STREAMIN: Test 0 returned %ld, expected 12\n", result);
5910 result = strcmp (buffer,"TestSomeText");
5911 ok (result == 0,
5912 "EM_STREAMIN: Test 0 set wrong text: Result: %s\n",buffer);
5913 ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0);
5914 /* Show that para fmts are ignored */
5915 range.cpMin = 2;
5916 range.cpMax = 2;
5917 result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&range);
5918 memset(&fmt, 0xcc, sizeof(fmt));
5919 fmt.cbSize = sizeof(fmt);
5920 result = SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt);
5921 ok(fmt.dxStartIndent == 0, "got %d\n", fmt.dxStartIndent);
5922 ok(fmt.dxOffset == 0, "got %d\n", fmt.dxOffset);
5923 ok(fmt.wAlignment == PFA_LEFT, "got %d\n", fmt.wAlignment);
5924 ok((fmt.wEffects & PFE_RTLPARA) == 0, "got %x\n", fmt.wEffects);
5925
5926 /* Native richedit 2.0 ignores last \par */
5927 ptr = streamText0a;
5928 es.dwCookie = (DWORD_PTR)&ptr;
5929 es.dwError = 0;
5930 es.pfnCallback = test_EM_STREAMIN_esCallback;
5931 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
5932 ok(result == 12, "got %ld, expected %d\n", result, 12);
5933
5934 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5935 ok (result == 12,
5936 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result);
5937 result = strcmp (buffer,"TestSomeText");
5938 ok (result == 0,
5939 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer);
5940 ok(es.dwError == 0, "EM_STREAMIN: Test 0-a set error %d, expected %d\n", es.dwError, 0);
5941 /* This time para fmts are processed */
5942 range.cpMin = 2;
5943 range.cpMax = 2;
5944 result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&range);
5945 memset(&fmt, 0xcc, sizeof(fmt));
5946 fmt.cbSize = sizeof(fmt);
5947 result = SendMessageA(hwndRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt);
5948 ok(fmt.dxStartIndent == 300, "got %d\n", fmt.dxStartIndent);
5949 ok(fmt.dxOffset == -100, "got %d\n", fmt.dxOffset);
5950 ok(fmt.wAlignment == PFA_RIGHT, "got %d\n", fmt.wAlignment);
5951 ok((fmt.wEffects & PFE_RTLPARA) == PFE_RTLPARA, "got %x\n", fmt.wEffects);
5952
5953 /* Native richedit 2.0 ignores last \par, next-to-last \par appears */
5954 es.dwCookie = (DWORD_PTR)&streamText0b;
5955 es.dwError = 0;
5956 es.pfnCallback = test_EM_STREAMIN_esCallback;
5957 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
5958 ok(result == 13, "got %ld, expected %d\n", result, 13);
5959
5960 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5961 ok (result == 14,
5962 "EM_STREAMIN: Test 0-b returned %ld, expected 14\n", result);
5963 result = strcmp (buffer,"TestSomeText\r\n");
5964 ok (result == 0,
5965 "EM_STREAMIN: Test 0-b set wrong text: Result: %s\n",buffer);
5966 ok(es.dwError == 0, "EM_STREAMIN: Test 0-b set error %d, expected %d\n", es.dwError, 0);
5967
5968 /* Show that when using SFF_SELECTION the last \par is not ignored. */
5969 ptr = streamText0a;
5970 es.dwCookie = (DWORD_PTR)&ptr;
5971 es.dwError = 0;
5972 es.pfnCallback = test_EM_STREAMIN_esCallback;
5973 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
5974 ok(result == 12, "got %ld, expected %d\n", result, 12);
5975
5976 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5977 ok (result == 12,
5978 "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result);
5979 result = strcmp (buffer,"TestSomeText");
5980 ok (result == 0,
5981 "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer);
5982 ok(es.dwError == 0, "EM_STREAMIN: Test 0-a set error %d, expected %d\n", es.dwError, 0);
5983
5984 range.cpMin = 0;
5985 range.cpMax = -1;
5986 result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&range);
5987 ok (result == 13, "got %ld\n", result);
5988
5989 ptr = streamText0a;
5990 es.dwCookie = (DWORD_PTR)&ptr;
5991 es.dwError = 0;
5992 es.pfnCallback = test_EM_STREAMIN_esCallback;
5993
5995 ok(result == 13, "got %ld, expected 13\n", result);
5996
5997 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
5998 ok (result == 14,
5999 "EM_STREAMIN: Test SFF_SELECTION 0-a returned %ld, expected 14\n", result);
6000 result = strcmp (buffer,"TestSomeText\r\n");
6001 ok (result == 0,
6002 "EM_STREAMIN: Test SFF_SELECTION 0-a set wrong text: Result: %s\n",buffer);
6003 ok(es.dwError == 0, "EM_STREAMIN: Test SFF_SELECTION 0-a set error %d, expected %d\n", es.dwError, 0);
6004
6005 es.dwCookie = (DWORD_PTR)&streamText1;
6006 es.dwError = 0;
6007 es.pfnCallback = test_EM_STREAMIN_esCallback;
6008 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
6009 ok(result == 12, "got %ld, expected %d\n", result, 12);
6010
6011 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6012 ok (result == 12,
6013 "EM_STREAMIN: Test 1 returned %ld, expected 12\n", result);
6014 result = strcmp (buffer,"TestSomeText");
6015 ok (result == 0,
6016 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer);
6017 ok(es.dwError == 0, "EM_STREAMIN: Test 1 set error %d, expected %d\n", es.dwError, 0);
6018
6019 es.dwCookie = (DWORD_PTR)&streamText2;
6020 es.dwError = 0;
6021 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
6022 ok(result == 0, "got %ld, expected %d\n", result, 0);
6023
6024 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6025 ok (result == 0,
6026 "EM_STREAMIN: Test 2 returned %ld, expected 0\n", result);
6027 ok(!buffer[0], "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
6028 ok(es.dwError == -16, "EM_STREAMIN: Test 2 set error %d, expected %d\n", es.dwError, -16);
6029
6030 es.dwCookie = (DWORD_PTR)&streamText3;
6031 es.dwError = 0;
6032 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
6033 ok(result == 0, "got %ld, expected %d\n", result, 0);
6034
6035 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6036 ok (result == 0,
6037 "EM_STREAMIN: Test 3 returned %ld, expected 0\n", result);
6038 ok(!buffer[0], "EM_STREAMIN: Test 3 set wrong text: Result: %s\n",buffer);
6039 ok(es.dwError == -16, "EM_STREAMIN: Test 3 set error %d, expected %d\n", es.dwError, -16);
6040
6041 es.dwCookie = (DWORD_PTR)&streamTextUTF8BOM;
6042 es.dwError = 0;
6043 es.pfnCallback = test_EM_STREAMIN_esCallback;
6044 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es);
6045 ok(result == 18, "got %ld, expected %d\n", result, 18);
6046
6047 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6048 ok(result == 15,
6049 "EM_STREAMIN: Test UTF8WithBOM returned %ld, expected 15\n", result);
6050 result = strcmp (buffer,"TestUTF8WithBOM");
6051 ok(result == 0,
6052 "EM_STREAMIN: Test UTF8WithBOM set wrong text: Result: %s\n",buffer);
6053 ok(es.dwError == 0, "EM_STREAMIN: Test UTF8WithBOM set error %d, expected %d\n", es.dwError, 0);
6054
6055 phase = 0;
6056 es.dwCookie = (DWORD_PTR)&phase;
6057 es.dwError = 0;
6059 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es);
6060 ok(result == 8, "got %ld\n", result);
6061
6062 WideCharToMultiByte(CP_ACP, 0, UTF8Split_exp, -1, tmp, sizeof(tmp), NULL, NULL);
6063
6064 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6065 ok(result == 3,
6066 "EM_STREAMIN: Test UTF8Split returned %ld\n", result);
6067 result = memcmp (buffer, tmp, 3);
6068 ok(result == 0,
6069 "EM_STREAMIN: Test UTF8Split set wrong text: Result: %s\n",buffer);
6070 ok(es.dwError == 0, "EM_STREAMIN: Test UTF8Split set error %d, expected %d\n", es.dwError, 0);
6071
6072 es.dwCookie = (DWORD_PTR)&cookieForStream4;
6073 es.dwError = 0;
6074 es.pfnCallback = test_EM_STREAMIN_esCallback2;
6075 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es);
6076 ok(result == length4, "got %ld, expected %d\n", result, length4);
6077
6078 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6079 ok (result == length4,
6080 "EM_STREAMIN: Test 4 returned %ld, expected %d\n", result, length4);
6081 ok(es.dwError == 0, "EM_STREAMIN: Test 4 set error %d, expected %d\n", es.dwError, 0);
6082
6083 es.dwCookie = (DWORD_PTR)&cookieForStream5;
6084 es.dwError = 0;
6085 es.pfnCallback = test_EM_STREAMIN_esCallback2;
6086 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT | SF_UNICODE, (LPARAM)&es);
6087 ok(result == sizeof(streamText5), "got %ld, expected %u\n", result, (UINT)sizeof(streamText5));
6088
6089 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6090 ok (result == length5,
6091 "EM_STREAMIN: Test 5 returned %ld, expected %d\n", result, length5);
6092 ok(es.dwError == 0, "EM_STREAMIN: Test 5 set error %d, expected %d\n", es.dwError, 0);
6093
6094 DestroyWindow(hwndRichEdit);
6095
6096 /* Single-line richedit */
6097 hwndRichEdit = new_richedit_with_style(NULL, 0);
6098 ptr = "line1\r\nline2";
6099 es.dwCookie = (DWORD_PTR)&ptr;
6100 es.dwError = 0;
6101 es.pfnCallback = test_EM_STREAMIN_esCallback;
6102 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es);
6103 ok(result == 12, "got %ld, expected %d\n", result, 12);
6104 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6105 ok (!strcmp(buffer, "line1"),
6106 "EM_STREAMIN: Unexpected text '%s'\n", buffer);
6107
6108 /* Test 0-bytes inside text */
6109 hwndRichEdit = new_richedit_with_style(NULL, 0);
6110 phase = 0;
6111 es.dwCookie = (DWORD_PTR)&phase;
6112 es.dwError = 0;
6113 es.pfnCallback = test_EM_STREAMIN_null_bytes;
6114 result = SendMessageA(hwndRichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
6115 ok(result == 16, "got %ld, expected %d\n", result, 16);
6116 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6117 ok (!strcmp(buffer, "Th is is a test"), "EM_STREAMIN: Unexpected text '%s'\n", buffer);
6118}
6119
6120static void test_EM_StreamIn_Undo(void)
6121{
6122 /* The purpose of this test is to determine when a EM_StreamIn should be
6123 * undoable. This is important because WM_PASTE currently uses StreamIn and
6124 * pasting should always be undoable but streaming isn't always.
6125 *
6126 * cases to test:
6127 * StreamIn plain text without SFF_SELECTION.
6128 * StreamIn plain text with SFF_SELECTION set but a zero-length selection
6129 * StreamIn plain text with SFF_SELECTION and a valid, normal selection
6130 * StreamIn plain text with SFF_SELECTION and a backwards-selection (from>to)
6131 * Feel free to add tests for other text modes or StreamIn things.
6132 */
6133
6134
6135 HWND hwndRichEdit = new_richedit(NULL);
6137 EDITSTREAM es;
6138 char buffer[1024] = {0};
6139 const char randomtext[] = "Some text";
6140
6141 es.pfnCallback = EditStreamCallback;
6142
6143 /* StreamIn, no SFF_SELECTION */
6144 es.dwCookie = nCallbackCount;
6145 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
6146 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)randomtext);
6147 SendMessageA(hwndRichEdit, EM_SETSEL,0,0);
6148 SendMessageA(hwndRichEdit, EM_STREAMIN, SF_TEXT, (LPARAM)&es);
6149 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6150 result = strcmp (buffer,"test");
6151 ok (result == 0,
6152 "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer);
6153
6154 result = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
6155 ok (result == FALSE,
6156 "EM_STREAMIN without SFF_SELECTION wrongly allows undo\n");
6157
6158 /* StreamIn, SFF_SELECTION, but nothing selected */
6159 es.dwCookie = nCallbackCount;
6160 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
6161 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)randomtext);
6162 SendMessageA(hwndRichEdit, EM_SETSEL,0,0);
6164 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6165 result = strcmp (buffer,"testSome text");
6166 ok (result == 0,
6167 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
6168
6169 result = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
6170 ok (result == TRUE,
6171 "EM_STREAMIN with SFF_SELECTION but no selection set "
6172 "should create an undo\n");
6173
6174 /* StreamIn, SFF_SELECTION, with a selection */
6175 es.dwCookie = nCallbackCount;
6176 SendMessageA(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
6177 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)randomtext);
6178 SendMessageA(hwndRichEdit, EM_SETSEL,4,5);
6180 SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
6181 result = strcmp (buffer,"Sometesttext");
6182 ok (result == 0,
6183 "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
6184
6185 result = SendMessageA(hwndRichEdit, EM_CANUNDO, 0, 0);
6186 ok (result == TRUE,
6187 "EM_STREAMIN with SFF_SELECTION and selection set "
6188 "should create an undo\n");
6189
6190 DestroyWindow(hwndRichEdit);
6191}
6192
6194{
6195 SETTEXTEX stex = { ST_DEFAULT, CP_ACP };
6196 return SendMessageA(hwnd, EM_SETTEXTEX, (WPARAM)&stex, 0) != 0;
6197}
6198
6200{
6201 static const WCHAR tW[] = {'t',0};
6202 static const WCHAR teW[] = {'t','e',0};
6203 static const WCHAR textW[] = {'t','e','s','t',0};
6204 static const char textA[] = "test";
6205 char bufA[64];
6206 WCHAR bufW[64];
6207 HWND hwnd;
6208 int em_settextex_supported, ret;
6209
6210#define set_textA(hwnd, wm_set_text, txt) \
6211 do { \
6212 SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; \
6213 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
6214 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
6215 ret = SendMessageA(hwnd, wm_set_text, wparam, (LPARAM)txt); \
6216 ok(ret, "SendMessageA(%02x) error %u\n", wm_set_text, GetLastError()); \
6217 } while(0)
6218#define expect_textA(hwnd, wm_get_text, txt) \
6219 do { \
6220 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
6221 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)&gtex; \
6222 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
6223 memset(bufA, 0xAA, sizeof(bufA)); \
6224 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
6225 ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
6226 ret = lstrcmpA(bufA, txt); \
6227 ok(!ret, "%02x: strings do not match: expected %s got %s\n", wm_get_text, txt, bufA); \
6228 } while(0)
6229
6230#define set_textW(hwnd, wm_set_text, txt) \
6231 do { \
6232 SETTEXTEX stex = { ST_DEFAULT, 1200 }; \
6233 WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
6234 assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
6235 ret = SendMessageW(hwnd, wm_set_text, wparam, (LPARAM)txt); \
6236 ok(ret, "SendMessageW(%02x) error %u\n", wm_set_text, GetLastError()); \
6237 } while(0)
6238#define expect_textW(hwnd, wm_get_text, txt) \
6239 do { \
6240 GETTEXTEX gtex = { 64, GT_DEFAULT, 1200, NULL, NULL }; \
6241 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)&gtex; \
6242 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
6243 memset(bufW, 0xAA, sizeof(bufW)); \
6244 ret = SendMessageW(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
6245 ok(ret, "SendMessageW(%02x) error %u\n", wm_get_text, GetLastError()); \
6246 ret = lstrcmpW(bufW, txt); \
6247 ok(!ret, "%02x: strings do not match: expected[0] %x got[0] %x\n", wm_get_text, txt[0], bufW[0]); \
6248 } while(0)
6249#define expect_empty(hwnd, wm_get_text) \
6250 do { \
6251 GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
6252 WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)&gtex; \
6253 assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
6254 memset(bufA, 0xAA, sizeof(bufA)); \
6255 ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
6256 ok(!ret, "empty richedit should return 0, got %d\n", ret); \
6257 ok(!*bufA, "empty richedit should return empty string, got %s\n", bufA); \
6258 } while(0)
6259
6260 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
6261 0, 0, 200, 60, 0, 0, 0, 0);
6262 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
6263
6265 ok(ret, "RichEdit20W should be unicode under NT\n");
6266
6267 /* EM_SETTEXTEX is supported starting from version 3.0 */
6268 em_settextex_supported = is_em_settextex_supported(hwnd);
6269 trace("EM_SETTEXTEX is %ssupported on this platform\n",
6270 em_settextex_supported ? "" : "NOT ");
6271
6274
6275 ret = SendMessageA(hwnd, WM_CHAR, textW[0], 0);
6276 ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret);
6280
6281 ret = SendMessageA(hwnd, WM_CHAR, textA[1], 0);
6282 ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret);
6286
6290
6295
6296 if (em_settextex_supported)
6297 {
6302 }
6303
6309
6310 if (em_settextex_supported)
6311 {
6317 }
6319
6320 hwnd = CreateWindowExA(0, "RichEdit20A", NULL, WS_POPUP,
6321 0, 0, 200, 60, 0, 0, 0, 0);
6322 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
6323
6325 ok(!ret, "RichEdit20A should NOT be unicode\n");
6326
6331
6332 if (em_settextex_supported)
6333 {
6338 }
6339
6345
6346 if (em_settextex_supported)
6347 {
6353 }
6355}
6356
6357static void test_WM_CHAR(void)
6358{
6359 HWND hwnd;
6360 int ret;
6361 const char * char_list = "abc\rabc\r";
6362 const char * expected_content_single = "abcabc";
6363 const char * expected_content_multi = "abc\r\nabc\r\n";
6364 char buffer[64] = {0};
6365 const char * p;
6366
6367 /* single-line control must IGNORE carriage returns */
6368 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
6369 0, 0, 200, 60, 0, 0, 0, 0);
6370 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
6371 disable_beep( hwnd );
6372
6373 p = char_list;
6374 while (*p != '\0') {
6376 ret = SendMessageA(hwnd, WM_CHAR, *p, 1);
6377 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *p, ret);
6378 SendMessageA(hwnd, WM_KEYUP, *p, 1);
6379 p++;
6380 }
6381
6383 ret = strcmp(buffer, expected_content_single);
6384 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n");
6385
6387
6388 /* multi-line control inserts CR normally */
6389 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP|ES_MULTILINE,
6390 0, 0, 200, 60, 0, 0, 0, 0);
6391 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
6392
6393 p = char_list;
6394 while (*p != '\0') {
6396 ret = SendMessageA(hwnd, WM_CHAR, *p, 1);
6397 ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *p, ret);
6398 SendMessageA(hwnd, WM_KEYUP, *p, 1);
6399 p++;
6400 }
6401
6403 ret = strcmp(buffer, expected_content_multi);
6404 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n");
6405
6407}
6408
6410{
6411 HWND hwnd;
6412 GETTEXTLENGTHEX gtl;
6413 int ret;
6414 const char * base_string = "base string";
6415 const char * test_string = "a\nb\n\n\r\n";
6416 const char * test_string_after = "a";
6417 const char * test_string_2 = "a\rtest\rstring";
6418 char buffer[64] = {0};
6419
6420 /* single line */
6421 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
6422 0, 0, 200, 60, 0, 0, 0, 0);
6423 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
6424
6426 gtl.codepage = CP_ACP;
6428 ok(ret == 0, "ret %d\n",ret);
6429
6431 gtl.codepage = CP_ACP;
6433 ok(ret == 0, "ret %d\n",ret);
6434
6435 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)base_string);
6436
6438 gtl.codepage = CP_ACP;
6440 ok(ret == strlen(base_string), "ret %d\n",ret);
6441
6443 gtl.codepage = CP_ACP;
6445 ok(ret == strlen(base_string), "ret %d\n",ret);
6446
6448
6450 gtl.codepage = CP_ACP;
6452 ok(ret == 1, "ret %d\n",ret);
6453
6455 gtl.codepage = CP_ACP;
6457 ok(ret == 1, "ret %d\n",ret);
6458
6460 ret = strcmp(buffer, test_string_after);
6461 ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n");
6462
6464
6465 /* multi line */
6466 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP | ES_MULTILINE,
6467 0, 0, 200, 60, 0, 0, 0, 0);
6468 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
6469
6471 gtl.codepage = CP_ACP;
6473 ok(ret == 0, "ret %d\n",ret);
6474
6476 gtl.codepage = CP_ACP;
6478 ok(ret == 0, "ret %d\n",ret);
6479
6480 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)base_string);
6481
6483 gtl.codepage = CP_ACP;
6485 ok(ret == strlen(base_string), "ret %d\n",ret);
6486
6488 gtl.codepage = CP_ACP;
6490 ok(ret == strlen(base_string), "ret %d\n",ret);
6491
6492 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)test_string_2);
6493
6495 gtl.codepage = CP_ACP;
6497 ok(ret == strlen(test_string_2) + 2, "ret %d\n",ret);
6498
6500 gtl.codepage = CP_ACP;
6502 ok(ret == strlen(test_string_2), "ret %d\n",ret);
6503
6505
6507 gtl.codepage = CP_ACP;
6509 ok(ret == 10, "ret %d\n",ret);
6510
6512 gtl.codepage = CP_ACP;
6514 ok(ret == 6, "ret %d\n",ret);
6515
6516 /* Unicode/NUMCHARS/NUMBYTES */
6517 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)test_string_2);
6518
6519 gtl.flags = GTL_DEFAULT;
6520 gtl.codepage = 1200;
6522 ok(ret == lstrlenA(test_string_2),
6523 "GTL_DEFAULT gave %i, expected %i\n", ret, lstrlenA(test_string_2));
6524
6525 gtl.flags = GTL_NUMCHARS;
6526 gtl.codepage = 1200;
6528 ok(ret == lstrlenA(test_string_2),
6529 "GTL_NUMCHARS gave %i, expected %i\n", ret, lstrlenA(test_string_2));
6530
6531 gtl.flags = GTL_NUMBYTES;
6532 gtl.codepage = 1200;
6534 ok(ret == lstrlenA(test_string_2)*2,
6535 "GTL_NUMBYTES gave %i, expected %i\n", ret, lstrlenA(test_string_2)*2);
6536
6537 gtl.flags = GTL_PRECISE;
6538 gtl.codepage = 1200;
6540 ok(ret == lstrlenA(test_string_2)*2,
6541 "GTL_PRECISE gave %i, expected %i\n", ret, lstrlenA(test_string_2)*2);
6542
6544 gtl.codepage = 1200;
6546 ok(ret == lstrlenA(test_string_2),
6547 "GTL_NUMCHAR | GTL_PRECISE gave %i, expected %i\n", ret, lstrlenA(test_string_2));
6548
6550 gtl.codepage = 1200;
6552 ok(ret == E_INVALIDARG,
6553 "GTL_NUMCHARS | GTL_NUMBYTES gave %i, expected %i\n", ret, E_INVALIDARG);
6554
6556}
6557
6558
6559/* globals that parent and child access when checking event masks & notifications */
6562static int watchForEventMask = 0;
6563
6564/* parent proc that queries the edit's event mask when it gets a WM_COMMAND */
6566{
6567 if(message == WM_COMMAND && (watchForEventMask & (wParam >> 16)))
6568 {
6570 }
6572}
6573
6574/* test event masks in combination with WM_COMMAND */
6575static void test_eventMask(void)
6576{
6577 HWND parent;
6578 int ret, style;
6579 WNDCLASSA cls;
6580 const char text[] = "foo bar\n";
6581 int eventMask;
6582
6583 /* register class to capture WM_COMMAND */
6584 cls.style = 0;
6586 cls.cbClsExtra = 0;
6587 cls.cbWndExtra = 0;
6588 cls.hInstance = GetModuleHandleA(0);
6589 cls.hIcon = 0;
6592 cls.lpszMenuName = NULL;
6593 cls.lpszClassName = "EventMaskParentClass";
6594 if(!RegisterClassA(&cls)) assert(0);
6595
6597 0, 0, 200, 60, NULL, NULL, NULL, NULL);
6598 ok (parent != 0, "Failed to create parent window\n");
6599
6601 ok(eventMaskEditHwnd != 0, "Failed to create edit window\n");
6602
6603 eventMask = ENM_CHANGE | ENM_UPDATE;
6605 ok(ret == ENM_NONE, "wrong event mask\n");
6607 ok(ret == eventMask, "failed to set event mask\n");
6608
6609 /* check what happens when we ask for EN_CHANGE and send WM_SETTEXT */
6610 queriedEventMask = 0; /* initialize to something other than we expect */
6613 ok(ret == TRUE, "failed to set text\n");
6614 /* richedit should mask off ENM_CHANGE when it sends an EN_CHANGE
6615 notification in response to WM_SETTEXT */
6616 ok(queriedEventMask == (eventMask & ~ENM_CHANGE),
6617 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask);
6618
6619 /* check to see if EN_CHANGE is sent when redraw is turned off */
6621 ok(IsWindowVisible(eventMaskEditHwnd), "Window should be visible.\n");
6623 /* redraw is disabled by making the window invisible. */
6624 ok(!IsWindowVisible(eventMaskEditHwnd), "Window shouldn't be visible.\n");
6625 queriedEventMask = 0; /* initialize to something other than we expect */
6627 ok(queriedEventMask == (eventMask & ~ENM_CHANGE),
6628 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask);
6630 ok(IsWindowVisible(eventMaskEditHwnd), "Window should be visible.\n");
6631
6632 /* check to see if EN_UPDATE is sent when the editor isn't visible */
6636 ok(!IsWindowVisible(eventMaskEditHwnd), "Window shouldn't be visible.\n");
6638 queriedEventMask = 0; /* initialize to something other than we expect */
6640 ok(queriedEventMask == 0,
6641 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask);
6643 ok(IsWindowVisible(eventMaskEditHwnd), "Window should be visible.\n");
6644 queriedEventMask = 0; /* initialize to something other than we expect */
6646 ok(queriedEventMask == eventMask,
6647 "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask);
6648
6649
6651}
6652
6653static int received_WM_NOTIFY = 0;
6654static int modify_at_WM_NOTIFY = 0;
6657
6659{
6660 if(message == WM_NOTIFY)
6661 {
6664 if (filter_on_WM_NOTIFY) return TRUE;
6665 }
6667}
6668
6669static void test_WM_NOTIFY(void)
6670{
6671 HWND parent;
6672 WNDCLASSA cls;
6673 CHARFORMAT2A cf2;
6674 int sel_start, sel_end;
6675
6676 /* register class to capture WM_NOTIFY */
6677 cls.style = 0;
6679 cls.cbClsExtra = 0;
6680 cls.cbWndExtra = 0;
6681 cls.hInstance = GetModuleHandleA(0);
6682 cls.hIcon = 0;
6685 cls.lpszMenuName = NULL;
6686 cls.lpszClassName = "WM_NOTIFY_ParentClass";
6687 if(!RegisterClassA(&cls)) assert(0);
6688
6690 0, 0, 200, 60, NULL, NULL, NULL, NULL);
6691 ok (parent != 0, "Failed to create parent window\n");
6692
6694 ok(hwndRichedit_WM_NOTIFY != 0, "Failed to create edit window\n");
6695
6697
6698 /* Notifications for selection change should only be sent when selection
6699 actually changes. EM_SETCHARFORMAT is one message that calls
6700 ME_CommitUndo, which should check whether message should be sent */
6702 cf2.cbSize = sizeof(CHARFORMAT2A);
6704 cf2.dwMask = CFM_ITALIC | cf2.dwMask;
6705 cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
6707 ok(received_WM_NOTIFY == 0, "Unexpected WM_NOTIFY was sent!\n");
6708
6709 /* WM_SETTEXT should NOT cause a WM_NOTIFY to be sent when selection is
6710 already at 0. */
6714 ok(received_WM_NOTIFY == 0, "Unexpected WM_NOTIFY was sent!\n");
6715 ok(modify_at_WM_NOTIFY == 0, "WM_NOTIFY callback saw text flagged as modified!\n");
6716
6720 ok(received_WM_NOTIFY == 1, "Expected WM_NOTIFY was NOT sent!\n");
6721
6725 ok(received_WM_NOTIFY == 1, "Expected WM_NOTIFY was NOT sent!\n");
6726 ok(modify_at_WM_NOTIFY == 0, "WM_NOTIFY callback saw text flagged as modified!\n");
6727
6728 /* Test for WM_NOTIFY messages with redraw disabled. */
6733 ok(received_WM_NOTIFY == 1, "Expected WM_NOTIFY was NOT sent!\n");
6735
6736 /* Test filtering key events. */
6739 SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
6742 SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
6743 ok(sel_start == 1 && sel_end == 1,
6744 "selections is incorrectly at (%d,%d)\n", sel_start, sel_end);
6748 SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
6749 ok(sel_start == 1 && sel_end == 1,
6750 "selections is incorrectly at (%d,%d)\n", sel_start, sel_end);
6751
6752 /* test with owner set to NULL */
6755 SendMessageA(hwndRichedit_WM_NOTIFY, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
6756 ok(sel_start == 1 && sel_end == 1,
6757 "selections is incorrectly at (%d,%d)\n", sel_start, sel_end);
6758
6761}
6762
6764#define CURSOR_CLIENT_X 5
6765#define CURSOR_CLIENT_Y 5
6766#define WP_PARENT 1
6767#define WP_CHILD 2
6768
6770{
6771 if(message == WM_NOTIFY && ((NMHDR*)lParam)->code == EN_LINK)
6772 {
6773 enlink = *(ENLINK*)lParam;
6774 }
6776}
6777
6778static void link_notify_test(const char *desc, int i, HWND hwnd, HWND parent,
6779 UINT msg, WPARAM wParam, LPARAM lParam, BOOL notifies)
6780{
6781 ENLINK junk_enlink;
6782
6783 switch (msg)
6784 {
6785 case WM_LBUTTONDBLCLK:
6786 case WM_LBUTTONDOWN:
6787 case WM_LBUTTONUP:
6788 case WM_MOUSEHOVER:
6789 case WM_MOUSEMOVE:
6790 case WM_MOUSEWHEEL:
6791 case WM_RBUTTONDBLCLK:
6792 case WM_RBUTTONDOWN:
6793 case WM_RBUTTONUP:
6795 break;
6796 case WM_SETCURSOR:
6797 if (wParam == WP_PARENT)
6798 wParam = (WPARAM)parent;
6799 else if (wParam == WP_CHILD)
6800 wParam = (WPARAM)hwnd;
6801 break;
6802 }
6803
6804 memset(&junk_enlink, 0x23, sizeof(junk_enlink));
6805 enlink = junk_enlink;
6806
6808
6809 if (notifies)
6810 {
6812 "%s test %i: Expected hwnd %p got %p\n", desc, i, hwnd, enlink.nmhdr.hwndFrom);
6813 ok(enlink.nmhdr.idFrom == 0,
6814 "%s test %i: Expected idFrom 0 got 0x%lx\n", desc, i, enlink.nmhdr.idFrom);
6815 ok(enlink.msg == msg,
6816 "%s test %i: Expected msg 0x%x got 0x%x\n", desc, i, msg, enlink.msg);
6817 if (msg == WM_SETCURSOR)
6818 {
6819 ok(enlink.wParam == 0,
6820 "%s test %i: Expected wParam 0 got 0x%lx\n", desc, i, enlink.wParam);
6821 }
6822 else
6823 {
6825 "%s test %i: Expected wParam 0x%lx got 0x%lx\n", desc, i, wParam, enlink.wParam);
6826 }
6828 "%s test %i: Expected lParam 0x%lx got 0x%lx\n",
6830 ok(enlink.chrg.cpMin == 0 && enlink.chrg.cpMax == 31,
6831 "%s test %i: Expected link range [0,31) got [%i,%i)\n", desc, i, enlink.chrg.cpMin, enlink.chrg.cpMax);
6832 }
6833 else
6834 {
6835 ok(memcmp(&enlink, &junk_enlink, sizeof(enlink)) == 0,
6836 "%s test %i: Expected enlink to remain unmodified\n", desc, i);
6837 }
6838}
6839
6840static void test_EN_LINK(void)
6841{
6842 HWND hwnd, parent;
6843 WNDCLASSA cls;
6844 CHARFORMAT2A cf2;
6845 POINT orig_cursor_pos;
6846 POINT cursor_screen_pos = {CURSOR_CLIENT_X, CURSOR_CLIENT_Y};
6847 int i;
6848
6849 static const struct
6850 {
6851 UINT msg;
6852 WPARAM wParam;
6853 LPARAM lParam;
6854 BOOL notifies;
6855 }
6856 link_notify_tests[] =
6857 {
6858 /* hold down the left button and try some messages */
6859 { WM_LBUTTONDOWN, 0, 0, TRUE }, /* 0 */
6860 { EM_LINESCROLL, 0, 1, FALSE },
6861 { EM_SCROLL, SB_BOTTOM, 0, FALSE },
6862 { WM_LBUTTONDBLCLK, 0, 0, TRUE },
6863 { WM_MOUSEHOVER, 0, 0, FALSE },
6864 { WM_MOUSEMOVE, 0, 0, FALSE },
6865 { WM_MOUSEWHEEL, 0, 0, FALSE },
6866 { WM_RBUTTONDBLCLK, 0, 0, TRUE },
6867 { WM_RBUTTONDOWN, 0, 0, TRUE },
6868 { WM_RBUTTONUP, 0, 0, TRUE },
6869 { WM_SETCURSOR, 0, 0, FALSE },
6870 { WM_SETCURSOR, WP_PARENT, 0, FALSE },
6871 { WM_SETCURSOR, WP_CHILD, 0, TRUE },
6872 { WM_SETCURSOR, WP_CHILD, 1, TRUE },
6873 { WM_VSCROLL, SB_BOTTOM, 0, FALSE },
6874 { WM_LBUTTONUP, 0, 0, TRUE },
6875 /* hold down the right button and try some messages */
6876 { WM_RBUTTONDOWN, 0, 0, TRUE }, /* 16 */
6877 { EM_LINESCROLL, 0, 1, FALSE },
6878 { EM_SCROLL, SB_BOTTOM, 0, FALSE },
6879 { WM_LBUTTONDBLCLK, 0, 0, TRUE },
6880 { WM_LBUTTONDOWN, 0, 0, TRUE },
6881 { WM_LBUTTONUP, 0, 0, TRUE },
6882 { WM_MOUSEHOVER, 0, 0, FALSE },
6883 { WM_MOUSEMOVE, 0, 0, TRUE },
6884 { WM_MOUSEWHEEL, 0, 0, FALSE },
6885 { WM_RBUTTONDBLCLK, 0, 0, TRUE },
6886 { WM_SETCURSOR, 0, 0, FALSE },
6887 { WM_SETCURSOR, WP_PARENT, 0, FALSE },
6888 { WM_SETCURSOR, WP_CHILD, 0, TRUE },
6889 { WM_SETCURSOR, WP_CHILD, 1, TRUE },
6890 { WM_VSCROLL, SB_BOTTOM, 0, FALSE },
6891 { WM_RBUTTONUP, 0, 0, TRUE },
6892 /* try the messages with both buttons released */
6893 { EM_LINESCROLL, 0, 1, FALSE }, /* 32 */
6894 { EM_SCROLL, SB_BOTTOM, 0, FALSE },
6895 { WM_LBUTTONDBLCLK, 0, 0, TRUE },
6896 { WM_LBUTTONDOWN, 0, 0, TRUE },
6897 { WM_LBUTTONUP, 0, 0, TRUE },
6898 { WM_MOUSEHOVER, 0, 0, FALSE },
6899 { WM_MOUSEMOVE, 0, 0, TRUE },
6900 { WM_MOUSEWHEEL, 0, 0, FALSE },
6901 { WM_RBUTTONDBLCLK, 0, 0, TRUE },
6902 { WM_RBUTTONDOWN, 0, 0, TRUE },
6903 { WM_RBUTTONUP, 0, 0, TRUE },
6904 { WM_SETCURSOR, 0, 0, FALSE },
6905 { WM_SETCURSOR, WP_CHILD, 0, TRUE },
6906 { WM_SETCURSOR, WP_CHILD, 1, TRUE },
6907 { WM_SETCURSOR, WP_PARENT, 0, FALSE },
6908 { WM_VSCROLL, SB_BOTTOM, 0, FALSE }
6909 };
6910
6911 /* register class to capture WM_NOTIFY */
6912 cls.style = 0;
6914 cls.cbClsExtra = 0;
6915 cls.cbWndExtra = 0;
6916 cls.hInstance = GetModuleHandleA(0);
6917 cls.hIcon = 0;
6920 cls.lpszMenuName = NULL;
6921 cls.lpszClassName = "EN_LINK_ParentClass";
6922 if(!RegisterClassA(&cls)) assert(0);
6923
6925 0, 0, 200, 60, NULL, NULL, NULL, NULL);
6926 ok(parent != 0, "Failed to create parent window\n");
6927
6929 ok(hwnd != 0, "Failed to create edit window\n");
6930
6932
6933 cf2.cbSize = sizeof(CHARFORMAT2A);
6934 cf2.dwMask = CFM_LINK;
6935 cf2.dwEffects = CFE_LINK;
6937 /* mixing letters and numbers causes runs to be split */
6938 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"link text with at least 2 runs");
6939
6940 GetCursorPos(&orig_cursor_pos);
6941 SetCursorPos(0, 0);
6942
6943 for (i = 0; i < ARRAY_SIZE(link_notify_tests); i++)
6944 {
6945 link_notify_test("cursor position simulated", i, hwnd, parent,
6946 link_notify_tests[i].msg, link_notify_tests[i].wParam, link_notify_tests[i].lParam,
6947 link_notify_tests[i].msg == WM_SETCURSOR ? FALSE : link_notify_tests[i].notifies);
6948 }
6949
6950 ClientToScreen(hwnd, &cursor_screen_pos);
6951 SetCursorPos(cursor_screen_pos.x, cursor_screen_pos.y);
6952
6953 for (i = 0; i < ARRAY_SIZE(link_notify_tests); i++)
6954 {
6955 link_notify_test("cursor position set", i, hwnd, parent,
6956 link_notify_tests[i].msg, link_notify_tests[i].wParam, link_notify_tests[i].lParam,
6957 link_notify_tests[i].notifies);
6958 }
6959
6960 SetCursorPos(orig_cursor_pos.x, orig_cursor_pos.y);
6963}
6964
6965static void test_undo_coalescing(void)
6966{
6967 HWND hwnd;
6968 int result;
6969 char buffer[64] = {0};
6970
6971 /* multi-line control inserts CR normally */
6972 hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP|ES_MULTILINE,
6973 0, 0, 200, 60, 0, 0, 0, 0);
6974 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
6975 disable_beep( hwnd );
6976
6978 ok (result == FALSE, "Can undo after window creation.\n");
6979 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
6980 ok (result == FALSE, "Undo operation successful with nothing to undo.\n");
6982 ok (result == FALSE, "Can redo after window creation.\n");
6983 result = SendMessageA(hwnd, EM_REDO, 0, 0);
6984 ok (result == FALSE, "Redo operation successful with nothing undone.\n");
6985
6986 /* Test the effect of arrows keys during typing on undo transactions*/
6987 simulate_typing_characters(hwnd, "one two three");
6990 simulate_typing_characters(hwnd, " four five six");
6991
6993 ok (result == FALSE, "Can redo before anything is undone.\n");
6995 ok (result == TRUE, "Cannot undo typed characters.\n");
6996 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
6997 ok (result == TRUE, "EM_UNDO Failed to undo typed characters.\n");
6999 ok (result == TRUE, "Cannot redo after undo.\n");
7001 result = strcmp(buffer, "one two three");
7002 ok (result == 0, "expected '%s' but got '%s'\n", "one two three", buffer);
7003
7005 ok (result == TRUE, "Cannot undo typed characters.\n");
7006 result = SendMessageA(hwnd, WM_UNDO, 0, 0);
7007 ok (result == TRUE, "Failed to undo typed characters.\n");
7009 result = strcmp(buffer, "");
7010 ok (result == 0, "expected '%s' but got '%s'\n", "", buffer);
7011
7012 /* Test the effect of focus changes during typing on undo transactions*/
7013 simulate_typing_characters(hwnd, "one two three");
7015 ok (result == FALSE, "Redo buffer should have been cleared by typing.\n");
7018 simulate_typing_characters(hwnd, " four five six");
7019 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
7020 ok (result == TRUE, "Failed to undo typed characters.\n");
7022 result = strcmp(buffer, "one two three");
7023 ok (result == 0, "expected '%s' but got '%s'\n", "one two three", buffer);
7024
7025 /* Test the effect of the back key during typing on undo transactions */
7028 ok (result == TRUE, "Failed to clear the text.\n");
7029 simulate_typing_characters(hwnd, "one two threa");
7031 ok (result == FALSE, "Redo buffer should have been cleared by typing.\n");
7034 simulate_typing_characters(hwnd, "e four five six");
7035 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
7036 ok (result == TRUE, "Failed to undo typed characters.\n");
7038 result = strcmp(buffer, "");
7039 ok (result == 0, "expected '%s' but got '%s'\n", "", buffer);
7040
7041 /* Test the effect of the delete key during typing on undo transactions */
7043 result = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"abcd");
7044 ok(result == TRUE, "Failed to set the text.\n");
7045 SendMessageA(hwnd, EM_SETSEL, 1, 1);
7050 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
7051 ok (result == TRUE, "Failed to undo typed characters.\n");
7053 result = strcmp(buffer, "acd");
7054 ok (result == 0, "expected '%s' but got '%s'\n", "acd", buffer);
7055 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
7056 ok (result == TRUE, "Failed to undo typed characters.\n");
7058 result = strcmp(buffer, "abcd");
7059 ok (result == 0, "expected '%s' but got '%s'\n", "abcd", buffer);
7060
7061 /* Test the effect of EM_STOPGROUPTYPING on undo transactions*/
7064 ok (result == TRUE, "Failed to clear the text.\n");
7065 simulate_typing_characters(hwnd, "one two three");
7067 ok (result == 0, "expected %d but got %d\n", 0, result);
7068 simulate_typing_characters(hwnd, " four five six");
7069 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
7070 ok (result == TRUE, "Failed to undo typed characters.\n");
7072 result = strcmp(buffer, "one two three");
7073 ok (result == 0, "expected '%s' but got '%s'\n", "one two three", buffer);
7074 result = SendMessageA(hwnd, EM_UNDO, 0, 0);
7075 ok (result == TRUE, "Failed to undo typed characters.\n");
7077 result = strcmp(buffer, "");
7078 ok (result == 0, "expected '%s' but got '%s'\n", "", buffer);
7079
7081}
7082
7084{
7085 int length;
7086
7087 /* MSDN lied, length is actually the number of bytes. */
7088 length = bytes / sizeof(WCHAR);
7089 switch(code)
7090 {
7091 case WB_ISDELIMITER:
7092 return text[pos] == 'X';
7093 case WB_LEFT:
7094 case WB_MOVEWORDLEFT:
7096 return pos-1;
7098 case WB_LEFTBREAK:
7099 pos--;
7101 pos--;
7102 return pos;
7103 case WB_RIGHT:
7104 case WB_MOVEWORDRIGHT:
7106 return pos+1;
7108 case WB_RIGHTBREAK:
7109 pos++;
7111 pos++;
7112 return pos;
7113 default:
7114 ok(FALSE, "Unexpected code %d\n", code);
7115 break;
7116 }
7117 return 0;
7118}
7119
7120static void test_word_movement(void)
7121{
7122 HWND hwnd;
7123 int result;
7124 int sel_start, sel_end;
7125 const WCHAR textW[] = {'o','n','e',' ','t','w','o','X','t','h','r','e','e',0};
7126
7127 /* multi-line control inserts CR normally */
7129
7130 result = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"one two three");
7131 ok (result == TRUE, "Failed to clear the text.\n");
7132 SendMessageA(hwnd, EM_SETSEL, 0, 0);
7133 /* |one two three */
7134
7136 /* one |two three */
7137 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7138 ok(sel_start == sel_end, "Selection should be empty\n");
7139 ok(sel_start == 4, "Cursor is at %d instead of %d\n", sel_start, 4);
7140
7142 /* one two |three */
7143 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7144 ok(sel_start == sel_end, "Selection should be empty\n");
7145 ok(sel_start == 9, "Cursor is at %d instead of %d\n", sel_start, 9);
7146
7148 /* one |two three */
7149 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7150 ok(sel_start == sel_end, "Selection should be empty\n");
7151 ok(sel_start == 4, "Cursor is at %d instead of %d\n", sel_start, 4);
7152
7154 /* |one two three */
7155 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7156 ok(sel_start == sel_end, "Selection should be empty\n");
7157 ok(sel_start == 0, "Cursor is at %d instead of %d\n", sel_start, 0);
7158
7159 SendMessageA(hwnd, EM_SETSEL, 8, 8);
7160 /* one two | three */
7162 /* one two |three */
7163 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7164 ok(sel_start == sel_end, "Selection should be empty\n");
7165 ok(sel_start == 9, "Cursor is at %d instead of %d\n", sel_start, 9);
7166
7167 SendMessageA(hwnd, EM_SETSEL, 11, 11);
7168 /* one two th|ree */
7170 /* one two |three */
7171 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7172 ok(sel_start == sel_end, "Selection should be empty\n");
7173 ok(sel_start == 9, "Cursor is at %d instead of %d\n", sel_start, 9);
7174
7175 /* Test with a custom word break procedure that uses X as the delimiter. */
7176 result = SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"one twoXthree");
7177 ok (result == TRUE, "Failed to clear the text.\n");
7179 /* |one twoXthree */
7181 /* one twoX|three */
7182 SendMessageA(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7183 ok(sel_start == sel_end, "Selection should be empty\n");
7184 ok(sel_start == 8, "Cursor is at %d instead of %d\n", sel_start, 8);
7185
7187
7188 /* Make sure the behaviour is the same with a unicode richedit window,
7189 * and using unicode functions. */
7190
7193 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7194
7195 /* Test with a custom word break procedure that uses X as the delimiter. */
7197 ok (result == TRUE, "Failed to clear the text.\n");
7199 /* |one twoXthree */
7201 /* one twoX|three */
7202 SendMessageW(hwnd, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
7203 ok(sel_start == sel_end, "Selection should be empty\n");
7204 ok(sel_start == 8, "Cursor is at %d instead of %d\n", sel_start, 8);
7205
7207}
7208
7209static void test_EM_CHARFROMPOS(void)
7210{
7211 HWND hwnd;
7212 int result;
7213 RECT rcClient;
7214 POINTL point;
7215 point.x = 0;
7216 point.y = 40;
7217
7218 /* multi-line control inserts CR normally */
7221 (LPARAM)"one two three four five six seven\reight");
7222 ok(result == 1, "Expected 1, got %d\n", result);
7223 GetClientRect(hwnd, &rcClient);
7224
7226 ok(result == 34, "expected character index of 34 but got %d\n", result);
7227
7228 /* Test with points outside the bounds of the richedit control. */
7229 point.x = -1;
7230 point.y = 40;
7232 todo_wine ok(result == 34, "expected character index of 34 but got %d\n", result);
7233
7234 point.x = 1000;
7235 point.y = 0;
7237 todo_wine ok(result == 33, "expected character index of 33 but got %d\n", result);
7238
7239 point.x = 1000;
7240 point.y = 36;
7242 todo_wine ok(result == 39, "expected character index of 39 but got %d\n", result);
7243
7244 point.x = 1000;
7245 point.y = -1;
7247 todo_wine ok(result == 0, "expected character index of 0 but got %d\n", result);
7248
7249 point.x = 1000;
7250 point.y = rcClient.bottom + 1;
7252 todo_wine ok(result == 34, "expected character index of 34 but got %d\n", result);
7253
7254 point.x = 1000;
7255 point.y = rcClient.bottom;
7257 todo_wine ok(result == 39, "expected character index of 39 but got %d\n", result);
7258
7260}
7261
7262static void test_word_wrap(void)
7263{
7264 HWND hwnd;
7265 POINTL point = {0, 60}; /* This point must be below the first line */
7266 const char *text = "Must be long enough to test line wrapping";
7268 int res, pos, lines;
7269
7270 /* Test the effect of WS_HSCROLL and ES_AUTOHSCROLL styles on wrapping
7271 * when specified on window creation and set later. */
7272 hwnd = CreateWindowA(RICHEDIT_CLASS20A, NULL, dwCommonStyle,
7273 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
7274 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
7276 ok(res, "WM_SETTEXT failed.\n");
7278 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
7280 ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines);
7281
7284 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
7286
7288 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
7289 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
7290
7292 ok(res, "WM_SETTEXT failed.\n");
7294 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
7296 ok(lines == 1, "Line wasn't expected to wrap (lines=%d).\n", lines);
7297
7298 SetWindowLongW(hwnd, GWL_STYLE, dwCommonStyle);
7300 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
7302
7304 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
7305 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
7307 ok(res, "WM_SETTEXT failed.\n");
7309 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
7310
7311 SetWindowLongW(hwnd, GWL_STYLE, dwCommonStyle);
7313 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
7315
7317 dwCommonStyle|WS_HSCROLL|ES_AUTOHSCROLL,
7318 0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
7319 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
7321 ok(res, "WM_SETTEXT failed.\n");
7323 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
7324
7325 SetWindowLongW(hwnd, GWL_STYLE, dwCommonStyle);
7327 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
7328
7329 /* Test the effect of EM_SETTARGETDEVICE on word wrap. */
7331 ok(res, "EM_SETTARGETDEVICE failed (returned %d).\n", res);
7333 ok(!pos, "pos=%d indicating word wrap when none is expected.\n", pos);
7334
7336 ok(res, "EM_SETTARGETDEVICE failed (returned %d).\n", res);
7338 ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
7340
7341 /* Test to see if wrapping happens with redraw disabled. */
7342 hwnd = CreateWindowA(RICHEDIT_CLASS20A, NULL, dwCommonStyle,
7343 0, 0, 400, 80, NULL, NULL, hmoduleRichEdit, NULL);
7344 ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
7347 ok(res, "EM_REPLACESEL failed.\n");
7349 ok(lines == 1, "Line wasn't expected to wrap (lines=%d).\n", lines);
7350 MoveWindow(hwnd, 0, 0, 200, 80, FALSE);
7352 ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines);
7353
7356}
7357
7358static void test_autoscroll(void)
7359{
7361 int lines, ret, redraw;
7362 POINT pt;
7363
7364 for (redraw = 0; redraw <= 1; redraw++) {
7365 trace("testing with WM_SETREDRAW=%d\n", redraw);
7367 SendMessageA(hwnd, EM_REPLACESEL, 0, (LPARAM)"1\n2\n3\n4\n5\n6\n7\n8");
7369 ok(lines == 8, "%d lines instead of 8\n", lines);
7371 ok(ret == 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret);
7372 ok(pt.y != 0, "Didn't scroll down after replacing text.\n");
7374 ok(ret & WS_VSCROLL, "Scrollbar was not shown yet (style=%x).\n", (UINT)ret);
7375
7378 ok(lines == 1, "%d lines instead of 1\n", lines);
7380 ok(ret == 1, "EM_GETSCROLLPOS returned %d instead of 1\n", ret);
7381 ok(pt.y == 0, "y scroll position is %d after clearing text.\n", pt.y);
7383 ok(!(ret & WS_VSCROLL), "Scrollbar is still shown (style=%x).\n", (UINT)ret);
7384 }
7385
7388
7389 /* The WS_VSCROLL and WS_HSCROLL styles implicitly set
7390 * auto vertical/horizontal scrolling options. */
7393 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7394 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7396 ok(ret & ECO_AUTOVSCROLL, "ECO_AUTOVSCROLL isn't set.\n");
7397 ok(ret & ECO_AUTOHSCROLL, "ECO_AUTOHSCROLL isn't set.\n");
7399 ok(!(ret & ES_AUTOVSCROLL), "ES_AUTOVSCROLL is set.\n");
7400 ok(!(ret & ES_AUTOHSCROLL), "ES_AUTOHSCROLL is set.\n");
7402
7405 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7406 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7408 ok(!(ret & ECO_AUTOVSCROLL), "ECO_AUTOVSCROLL is set.\n");
7409 ok(!(ret & ECO_AUTOHSCROLL), "ECO_AUTOHSCROLL is set.\n");
7411 ok(!(ret & ES_AUTOVSCROLL), "ES_AUTOVSCROLL is set.\n");
7412 ok(!(ret & ES_AUTOHSCROLL), "ES_AUTOHSCROLL is set.\n");
7414}
7415
7416
7417static void test_format_rect(void)
7418{
7419 HWND hwnd;
7420 RECT rc, expected, clientRect;
7421 int n;
7422 DWORD options;
7423
7426 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7427 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7428
7429 GetClientRect(hwnd, &clientRect);
7430
7431 expected = clientRect;
7432 InflateRect(&expected, -1, 0);
7434 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7436
7437 for (n = -3; n <= 3; n++)
7438 {
7439 rc = clientRect;
7440 InflateRect(&rc, -n, -n);
7442
7443 expected = rc;
7444 expected.top = max(0, rc.top);
7445 expected.left = max(0, rc.left);
7446 expected.bottom = min(clientRect.bottom, rc.bottom);
7447 expected.right = min(clientRect.right, rc.right);
7449 ok(EqualRect(&rc, &expected), "[n=%d] rect %s != %s\n", n, wine_dbgstr_rect(&rc),
7451 }
7452
7453 rc = clientRect;
7455 expected = clientRect;
7457 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7459
7460 /* Adding the selectionbar adds the selectionbar width to the left side. */
7463 ok(options & ECO_SELECTIONBAR, "EM_SETOPTIONS failed to add selectionbar.\n");
7464 expected.left += 8; /* selection bar width */
7466 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7468
7469 rc = clientRect;
7471 expected = clientRect;
7473 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7475
7476 /* Removing the selectionbar subtracts the selectionbar width from the left side,
7477 * even if the left side is already 0. */
7480 ok(!(options & ECO_SELECTIONBAR), "EM_SETOPTIONS failed to remove selectionbar.\n");
7481 expected.left -= 8; /* selection bar width */
7483 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7485
7486 /* reset back to client rect and now try adding selection bar */
7488 expected = clientRect;
7489 InflateRect(&expected, -1, 0);
7491 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7495 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7498
7499 /* Set the absolute value of the formatting rectangle. */
7500 rc = clientRect;
7502 expected = clientRect;
7504 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7506
7507 /* MSDN documents the EM_SETRECT message as using the rectangle provided in
7508 * LPARAM as being a relative offset when the WPARAM value is 1, but these
7509 * tests show that this isn't true. */
7510 rc.top = 15;
7511 rc.left = 15;
7512 rc.bottom = clientRect.bottom - 15;
7513 rc.right = clientRect.right - 15;
7514 expected = rc;
7517 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7519
7520 /* For some reason it does not limit the values to the client rect with
7521 * a WPARAM value of 1. */
7522 rc.top = -15;
7523 rc.left = -15;
7524 rc.bottom = clientRect.bottom + 15;
7525 rc.right = clientRect.right + 15;
7526 expected = rc;
7529 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7531
7532 /* Reset to default rect and check how the format rect adjusts to window
7533 * resize and how it copes with very small windows */
7535
7536 MoveWindow(hwnd, 0, 0, 100, 30, FALSE);
7537 GetClientRect(hwnd, &clientRect);
7538
7539 expected = clientRect;
7540 InflateRect(&expected, -1, 0);
7542 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7544
7545 MoveWindow(hwnd, 0, 0, 0, 30, FALSE);
7546 GetClientRect(hwnd, &clientRect);
7547
7548 expected = clientRect;
7549 InflateRect(&expected, -1, 0);
7551 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7553
7554 MoveWindow(hwnd, 0, 0, 100, 0, FALSE);
7555 GetClientRect(hwnd, &clientRect);
7556
7557 expected = clientRect;
7558 InflateRect(&expected, -1, 0);
7560 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7562
7564
7565 /* The extended window style affects the formatting rectangle. */
7568 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7569 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7570
7571 GetClientRect(hwnd, &clientRect);
7572
7573 expected = clientRect;
7574 expected.top += 1;
7575 InflateRect(&expected, -1, 0);
7577 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7579
7580 rc = clientRect;
7581 InflateRect(&rc, -5, -5);
7582 expected = rc;
7583 expected.top -= 1;
7584 InflateRect(&expected, 1, 0);
7587 ok(EqualRect(&rc, &expected), "rect %s != %s\n", wine_dbgstr_rect(&rc),
7589
7591}
7592
7593static void test_WM_GETDLGCODE(void)
7594{
7595 HWND hwnd;
7596 UINT res, expected;
7597 MSG msg;
7598
7600
7603 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7604 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7605 msg.hwnd = hwnd;
7608 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7609 res, expected);
7611
7612 msg.message = WM_KEYDOWN;
7613 msg.wParam = VK_RETURN;
7614 msg.lParam = (MapVirtualKeyA(VK_RETURN, MAPVK_VK_TO_VSC) << 16) | 0x0001;
7615 msg.pt.x = 0;
7616 msg.pt.y = 0;
7617 msg.time = GetTickCount();
7618
7621 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7622 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7623 msg.hwnd = hwnd;
7626 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7627 res, expected);
7629
7632 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7633 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7634 msg.hwnd = hwnd;
7637 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7638 res, expected);
7640
7643 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7644 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7645 msg.hwnd = hwnd;
7648 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7649 res, expected);
7651
7653 WS_POPUP,
7654 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7655 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7656 msg.hwnd = hwnd;
7659 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7660 res, expected);
7662
7663 msg.wParam = VK_TAB;
7664 msg.lParam = (MapVirtualKeyA(VK_TAB, MAPVK_VK_TO_VSC) << 16) | 0x0001;
7665
7668 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7669 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7670 msg.hwnd = hwnd;
7673 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7674 res, expected);
7676
7678 WS_POPUP,
7679 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7680 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7681 msg.hwnd = hwnd;
7684 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7685 res, expected);
7687
7689
7692 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7693 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7694 msg.hwnd = hwnd;
7697 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7698 res, expected);
7700
7702 WS_POPUP,
7703 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7704 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7705 msg.hwnd = hwnd;
7708 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7709 res, expected);
7711
7713
7714 msg.wParam = 'a';
7715 msg.lParam = (MapVirtualKeyA('a', MAPVK_VK_TO_VSC) << 16) | 0x0001;
7716
7719 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7720 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7721 msg.hwnd = hwnd;
7724 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7725 res, expected);
7727
7729 WS_POPUP,
7730 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7731 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7732 msg.hwnd = hwnd;
7735 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7736 res, expected);
7738
7739 msg.message = WM_CHAR;
7740
7743 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7744 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7745 msg.hwnd = hwnd;
7748 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7749 res, expected);
7751
7753 WS_POPUP,
7754 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7755 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7756 msg.hwnd = hwnd;
7759 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7760 res, expected);
7762
7765 0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
7766 ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
7769 ok(res == expected, "WM_GETDLGCODE returned %x but expected %x\n",
7770 res, expected);
7772}
7773
7774static void test_zoom(void)
7775{
7776 HWND hwnd;
7777 UINT ret;
7778 RECT rc;
7779 POINT pt;
7780 int numerator, denominator;
7781
7783 GetClientRect(hwnd, &rc);
7784 pt.x = (rc.right - rc.left) / 2;
7785 pt.y = (rc.bottom - rc.top) / 2;
7787
7788 /* Test initial zoom value */
7789 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7790 ok(numerator == 0, "Numerator should be initialized to 0 (got %d).\n", numerator);
7791 ok(denominator == 0, "Denominator should be initialized to 0 (got %d).\n", denominator);
7792 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7793
7794 /* test scroll wheel */
7797 MAKELPARAM(pt.x, pt.y));
7798 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret);
7800
7801 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7802 ok(numerator == 110, "incorrect numerator is %d\n", numerator);
7803 ok(denominator == 100, "incorrect denominator is %d\n", denominator);
7804 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7805
7806 /* Test how much the mouse wheel can zoom in and out. */
7807 ret = SendMessageA(hwnd, EM_SETZOOM, 490, 100);
7808 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret);
7809
7812 MAKELPARAM(pt.x, pt.y));
7813 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret);
7815
7816 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7817 ok(numerator == 500, "incorrect numerator is %d\n", numerator);
7818 ok(denominator == 100, "incorrect denominator is %d\n", denominator);
7819 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7820
7821 ret = SendMessageA(hwnd, EM_SETZOOM, 491, 100);
7822 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret);
7823
7826 MAKELPARAM(pt.x, pt.y));
7827 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret);
7829
7830 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7831 ok(numerator == 491, "incorrect numerator is %d\n", numerator);
7832 ok(denominator == 100, "incorrect denominator is %d\n", denominator);
7833 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7834
7835 ret = SendMessageA(hwnd, EM_SETZOOM, 20, 100);
7836 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret);
7837
7840 MAKELPARAM(pt.x, pt.y));
7841 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret);
7843
7844 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7845 ok(numerator == 10, "incorrect numerator is %d\n", numerator);
7846 ok(denominator == 100, "incorrect denominator is %d\n", denominator);
7847 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7848
7849 ret = SendMessageA(hwnd, EM_SETZOOM, 19, 100);
7850 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret);
7851
7854 MAKELPARAM(pt.x, pt.y));
7855 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret);
7857
7858 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7859 ok(numerator == 19, "incorrect numerator is %d\n", numerator);
7860 ok(denominator == 100, "incorrect denominator is %d\n", denominator);
7861 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7862
7863 /* Test how WM_SCROLLWHEEL treats our custom denominator. */
7864 ret = SendMessageA(hwnd, EM_SETZOOM, 50, 13);
7865 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret);
7866
7869 MAKELPARAM(pt.x, pt.y));
7870 ok(!ret, "WM_MOUSEWHEEL failed (%d).\n", ret);
7872
7873 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7874 ok(numerator == 394, "incorrect numerator is %d\n", numerator);
7875 ok(denominator == 100, "incorrect denominator is %d\n", denominator);
7876 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7877
7878 /* Test bounds checking on EM_SETZOOM */
7879 ret = SendMessageA(hwnd, EM_SETZOOM, 2, 127);
7880 ok(ret == TRUE, "EM_SETZOOM rejected valid values (%d).\n", ret);
7881
7882 ret = SendMessageA(hwnd, EM_SETZOOM, 127, 2);
7883 ok(ret == TRUE, "EM_SETZOOM rejected valid values (%d).\n", ret);
7884
7885 ret = SendMessageA(hwnd, EM_SETZOOM, 2, 128);
7886 ok(ret == FALSE, "EM_SETZOOM accepted invalid values (%d).\n", ret);
7887
7888 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7889 ok(numerator == 127, "incorrect numerator is %d\n", numerator);
7890 ok(denominator == 2, "incorrect denominator is %d\n", denominator);
7891 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7892
7893 ret = SendMessageA(hwnd, EM_SETZOOM, 128, 2);
7894 ok(ret == FALSE, "EM_SETZOOM accepted invalid values (%d).\n", ret);
7895
7896 /* See if negative numbers are accepted. */
7897 ret = SendMessageA(hwnd, EM_SETZOOM, -100, -100);
7898 ok(ret == FALSE, "EM_SETZOOM accepted invalid values (%d).\n", ret);
7899
7900 /* See if negative numbers are accepted. */
7901 ret = SendMessageA(hwnd, EM_SETZOOM, 0, 100);
7902 ok(ret == FALSE, "EM_SETZOOM failed (%d).\n", ret);
7903
7904 ret = SendMessageA(hwnd, EM_GETZOOM, (WPARAM)&numerator, (LPARAM)&denominator);
7905 ok(numerator == 127, "incorrect numerator is %d\n", numerator);
7906 ok(denominator == 2, "incorrect denominator is %d\n", denominator);
7907 ok(ret == TRUE, "EM_GETZOOM failed (%d).\n", ret);
7908
7909 /* Reset the zoom value */
7910 ret = SendMessageA(hwnd, EM_SETZOOM, 0, 0);
7911 ok(ret == TRUE, "EM_SETZOOM failed (%d).\n", ret);
7912
7914}
7915
7917{
7919};
7920
7922
7923#define test_dm_messages(wmclose, wmgetdefid, wmnextdlgctl) \
7924 ok(dm_messages.wm_close == wmclose, "expected %d WM_CLOSE message, " \
7925 "got %d\n", wmclose, dm_messages.wm_close); \
7926 ok(dm_messages.wm_getdefid == wmgetdefid, "expected %d WM_GETDIFID message, " \
7927 "got %d\n", wmgetdefid, dm_messages.wm_getdefid);\
7928 ok(dm_messages.wm_nextdlgctl == wmnextdlgctl, "expected %d WM_NEXTDLGCTL message, " \
7929 "got %d\n", wmnextdlgctl, dm_messages.wm_nextdlgctl)
7930
7932{
7933 switch (iMsg)
7934 {
7935 case DM_GETDEFID:
7936 dm_messages.wm_getdefid++;
7938 case WM_NEXTDLGCTL:
7939 dm_messages.wm_nextdlgctl++;
7940 break;
7941 case WM_CLOSE:
7942 dm_messages.wm_close++;
7943 break;
7944 }
7945
7946 return DefWindowProcA(hwnd, iMsg, wParam, lParam);
7947}
7948
7949static void test_dialogmode(void)
7950{
7951 HWND hwRichEdit, hwParent, hwButton;
7952 MSG msg= {0};
7953 int lcount, r;
7954 WNDCLASSA cls;
7955
7956 cls.style = 0;
7958 cls.cbClsExtra = 0;
7959 cls.cbWndExtra = 0;
7960 cls.hInstance = GetModuleHandleA(0);
7961 cls.hIcon = 0;
7964 cls.lpszMenuName = NULL;
7965 cls.lpszClassName = "DialogModeParentClass";
7966 if(!RegisterClassA(&cls)) assert(0);
7967
7968 hwParent = CreateWindowA("DialogModeParentClass", NULL, WS_OVERLAPPEDWINDOW,
7969 CW_USEDEFAULT, 0, 200, 120, NULL, NULL, GetModuleHandleA(0), NULL);
7970
7971 /* Test richedit(ES_MULTILINE) */
7972
7973 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE, hwParent);
7974
7975 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
7976 ok(0 == r, "expected 0, got %d\n", r);
7977 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
7978 ok(2 == lcount, "expected 2, got %d\n", lcount);
7979
7980 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, 0);
7981 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r);
7982
7983 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
7984 ok(0 == r, "expected 0, got %d\n", r);
7985 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
7986 ok(3 == lcount, "expected 3, got %d\n", lcount);
7987
7988 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
7989 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r);
7990 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
7991 ok(0 == r, "expected 0, got %d\n", r);
7992 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
7993 ok(3 == lcount, "expected 3, got %d\n", lcount);
7994
7995 DestroyWindow(hwRichEdit);
7996
7997 /* Test standalone richedit(ES_MULTILINE) */
7998
8000
8001 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8002 ok(0 == r, "expected 0, got %d\n", r);
8003 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8004 ok(2 == lcount, "expected 2, got %d\n", lcount);
8005
8006 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
8007 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r);
8008
8009 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8010 ok(0 == r, "expected 0, got %d\n", r);
8011 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8012 ok(2 == lcount, "expected 2, got %d\n", lcount);
8013
8014 DestroyWindow(hwRichEdit);
8015
8016 /* Check a destination for messages */
8017
8018 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE, hwParent);
8019
8020 SetWindowLongA(hwRichEdit, GWL_STYLE, GetWindowLongA(hwRichEdit, GWL_STYLE)& ~WS_POPUP);
8021 SetParent( hwRichEdit, NULL);
8022
8023 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
8024 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r);
8025
8026 memset(&dm_messages, 0, sizeof(dm_messages));
8027 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8028 ok(0 == r, "expected 0, got %d\n", r);
8029 test_dm_messages(0, 1, 0);
8030
8031 memset(&dm_messages, 0, sizeof(dm_messages));
8032 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
8033 ok(0 == r, "expected 0, got %d\n", r);
8034 test_dm_messages(0, 0, 1);
8035
8036 DestroyWindow(hwRichEdit);
8037
8038 /* Check messages from richedit(ES_MULTILINE) */
8039
8040 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE, hwParent);
8041
8042 memset(&dm_messages, 0, sizeof(dm_messages));
8043 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8044 ok(0 == r, "expected 0, got %d\n", r);
8045 test_dm_messages(0, 0, 0);
8046
8047 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8048 ok(2 == lcount, "expected 2, got %d\n", lcount);
8049
8050 memset(&dm_messages, 0, sizeof(dm_messages));
8051 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
8052 ok(0 == r, "expected 0, got %d\n", r);
8053 test_dm_messages(0, 0, 0);
8054
8055 memset(&dm_messages, 0, sizeof(dm_messages));
8056 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
8057 ok(0 == r, "expected 0, got %d\n", r);
8058 test_dm_messages(0, 0, 0);
8059
8060 memset(&dm_messages, 0, sizeof(dm_messages));
8061 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
8062 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r);
8063 test_dm_messages(0, 0, 0);
8064
8065 memset(&dm_messages, 0, sizeof(dm_messages));
8066 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8067 ok(0 == r, "expected 0, got %d\n", r);
8068 test_dm_messages(0, 1, 0);
8069
8070 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8071 ok(2 == lcount, "expected 2, got %d\n", lcount);
8072
8073 memset(&dm_messages, 0, sizeof(dm_messages));
8074 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
8075 ok(0 == r, "expected 0, got %d\n", r);
8076 test_dm_messages(0, 0, 0);
8077
8078 memset(&dm_messages, 0, sizeof(dm_messages));
8079 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
8080 ok(0 == r, "expected 0, got %d\n", r);
8081 test_dm_messages(0, 0, 1);
8082
8083 hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON,
8084 100, 100, 50, 20, hwParent, (HMENU)ID_RICHEDITTESTDBUTTON, GetModuleHandleA(0), NULL);
8085 ok(hwButton!=NULL, "CreateWindow failed with error code %d\n", GetLastError());
8086
8087 memset(&dm_messages, 0, sizeof(dm_messages));
8088 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8089 ok(0 == r, "expected 0, got %d\n", r);
8090 test_dm_messages(0, 1, 1);
8091
8092 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8093 ok(2 == lcount, "expected 2, got %d\n", lcount);
8094
8095 DestroyWindow(hwButton);
8096 DestroyWindow(hwRichEdit);
8097
8098 /* Check messages from richedit(ES_MULTILINE|ES_WANTRETURN) */
8099
8100 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_MULTILINE|ES_WANTRETURN, hwParent);
8101
8102 memset(&dm_messages, 0, sizeof(dm_messages));
8103 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8104 ok(0 == r, "expected 0, got %d\n", r);
8105 test_dm_messages(0, 0, 0);
8106
8107 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8108 ok(2 == lcount, "expected 2, got %d\n", lcount);
8109
8110 memset(&dm_messages, 0, sizeof(dm_messages));
8111 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
8112 ok(0 == r, "expected 0, got %d\n", r);
8113 test_dm_messages(0, 0, 0);
8114
8115 memset(&dm_messages, 0, sizeof(dm_messages));
8116 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
8117 ok(0 == r, "expected 0, got %d\n", r);
8118 test_dm_messages(0, 0, 0);
8119
8120 memset(&dm_messages, 0, sizeof(dm_messages));
8121 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
8122 ok(0x8f == r, "expected 0x8f, got 0x%x\n", r);
8123 test_dm_messages(0, 0, 0);
8124
8125 memset(&dm_messages, 0, sizeof(dm_messages));
8126 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8127 ok(0 == r, "expected 0, got %d\n", r);
8128 test_dm_messages(0, 0, 0);
8129
8130 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8131 ok(3 == lcount, "expected 3, got %d\n", lcount);
8132
8133 memset(&dm_messages, 0, sizeof(dm_messages));
8134 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
8135 ok(0 == r, "expected 0, got %d\n", r);
8136 test_dm_messages(0, 0, 0);
8137
8138 memset(&dm_messages, 0, sizeof(dm_messages));
8139 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
8140 ok(0 == r, "expected 0, got %d\n", r);
8141 test_dm_messages(0, 0, 1);
8142
8143 hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON,
8144 100, 100, 50, 20, hwParent, (HMENU)ID_RICHEDITTESTDBUTTON, GetModuleHandleA(0), NULL);
8145 ok(hwButton!=NULL, "CreateWindow failed with error code %d\n", GetLastError());
8146
8147 memset(&dm_messages, 0, sizeof(dm_messages));
8148 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8149 ok(0 == r, "expected 0, got %d\n", r);
8150 test_dm_messages(0, 0, 0);
8151
8152 lcount = SendMessageA(hwRichEdit, EM_GETLINECOUNT, 0, 0);
8153 ok(4 == lcount, "expected 4, got %d\n", lcount);
8154
8155 DestroyWindow(hwButton);
8156 DestroyWindow(hwRichEdit);
8157
8158 /* Check messages from richedit(0) */
8159
8160 hwRichEdit = new_window(RICHEDIT_CLASS20A, 0, hwParent);
8161
8162 memset(&dm_messages, 0, sizeof(dm_messages));
8163 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8164 ok(0 == r, "expected 0, got %d\n", r);
8165 test_dm_messages(0, 0, 0);
8166
8167 memset(&dm_messages, 0, sizeof(dm_messages));
8168 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
8169 ok(0 == r, "expected 0, got %d\n", r);
8170 test_dm_messages(0, 0, 0);
8171
8172 memset(&dm_messages, 0, sizeof(dm_messages));
8173 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
8174 ok(0 == r, "expected 0, got %d\n", r);
8175 test_dm_messages(0, 0, 0);
8176
8177 memset(&dm_messages, 0, sizeof(dm_messages));
8178 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
8179 ok(0x8b == r, "expected 0x8b, got 0x%x\n", r);
8180 test_dm_messages(0, 0, 0);
8181
8182 memset(&dm_messages, 0, sizeof(dm_messages));
8183 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8184 ok(0 == r, "expected 0, got %d\n", r);
8185 test_dm_messages(0, 1, 0);
8186
8187 memset(&dm_messages, 0, sizeof(dm_messages));
8188 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_ESCAPE, 0x10001);
8189 ok(0 == r, "expected 0, got %d\n", r);
8190 test_dm_messages(0, 0, 0);
8191
8192 memset(&dm_messages, 0, sizeof(dm_messages));
8193 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_TAB, 0xf0001);
8194 ok(0 == r, "expected 0, got %d\n", r);
8195 test_dm_messages(0, 0, 1);
8196
8197 hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON,
8198 100, 100, 50, 20, hwParent, (HMENU)ID_RICHEDITTESTDBUTTON, GetModuleHandleA(0), NULL);
8199 ok(hwButton!=NULL, "CreateWindow failed with error code %d\n", GetLastError());
8200
8201 memset(&dm_messages, 0, sizeof(dm_messages));
8202 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8203 ok(0 == r, "expected 0, got %d\n", r);
8204 test_dm_messages(0, 1, 1);
8205
8206 DestroyWindow(hwRichEdit);
8207
8208 /* Check messages from richedit(ES_WANTRETURN) */
8209
8210 hwRichEdit = new_window(RICHEDIT_CLASS20A, ES_WANTRETURN, hwParent);
8211
8212 memset(&dm_messages, 0, sizeof(dm_messages));
8213 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8214 ok(0 == r, "expected 0, got %d\n", r);
8215 test_dm_messages(0, 0, 0);
8216
8217 memset(&dm_messages, 0, sizeof(dm_messages));
8218 r = SendMessageA(hwRichEdit, WM_GETDLGCODE, 0, (LPARAM)&msg);
8219 ok(0x8b == r, "expected 0x8b, got 0x%x\n", r);
8220 test_dm_messages(0, 0, 0);
8221
8222 memset(&dm_messages, 0, sizeof(dm_messages));
8223 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8224 ok(0 == r, "expected 0, got %d\n", r);
8225 test_dm_messages(0, 0, 0);
8226
8227 hwButton = CreateWindowA("BUTTON", "OK", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON,
8228 100, 100, 50, 20, hwParent, (HMENU)ID_RICHEDITTESTDBUTTON, GetModuleHandleA(0), NULL);
8229 ok(hwButton!=NULL, "CreateWindow failed with error code %d\n", GetLastError());
8230
8231 memset(&dm_messages, 0, sizeof(dm_messages));
8232 r = SendMessageA(hwRichEdit, WM_KEYDOWN, VK_RETURN, 0x1c0001);
8233 ok(0 == r, "expected 0, got %d\n", r);
8234 test_dm_messages(0, 0, 0);
8235
8236 DestroyWindow(hwRichEdit);
8237 DestroyWindow(hwParent);
8238}
8239
8241{
8242 static const struct {
8243 WCHAR c;
8244 BOOL isdelimiter; /* expected result of WB_ISDELIMITER */
8245 } delimiter_tests[] = {
8246 {0x0a, FALSE}, /* newline */
8247 {0x0b, FALSE}, /* vertical tab */
8248 {0x0c, FALSE}, /* form feed */
8249 {0x0d, FALSE}, /* carriage return */
8250 {0x20, TRUE}, /* space */
8251 {0x61, FALSE}, /* capital letter a */
8252 {0xa0, FALSE}, /* no-break space */
8253 {0x2000, FALSE}, /* en quad */
8254 {0x3000, FALSE}, /* Ideographic space */
8255 {0x1100, FALSE}, /* Hangul Choseong Kiyeok (G sound) Ordinary Letter*/
8256 {0x11ff, FALSE}, /* Hangul Jongseoung Kiyeok-Hieuh (Hard N sound) Ordinary Letter*/
8257 {0x115f, FALSE}, /* Hangul Choseong Filler (no sound, used with two letter Hangul words) Ordinary Letter */
8258 {0xac00, FALSE}, /* Hangul character GA*/
8259 {0xd7af, FALSE}, /* End of Hangul character chart */
8260 {0xf020, TRUE}, /* MS private for CP_SYMBOL round trip?, see kb897872 */
8261 {0xff20, FALSE}, /* fullwidth commercial @ */
8262 {WCH_EMBEDDING, FALSE}, /* object replacement character*/
8263 };
8264 int i;
8265 HWND hwndRichEdit = new_richeditW(NULL);
8266 ok(IsWindowUnicode(hwndRichEdit), "window should be unicode\n");
8267 for (i = 0; i < ARRAY_SIZE(delimiter_tests); i++)
8268 {
8269 WCHAR wbuf[2];
8270 int result;
8271
8272 wbuf[0] = delimiter_tests[i].c;
8273 wbuf[1] = 0;
8274 SendMessageW(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)wbuf);
8276 todo_wine_if (wbuf[0] == 0x20 || wbuf[0] == 0xf020)
8277 ok(result == delimiter_tests[i].isdelimiter,
8278 "wanted ISDELIMITER_W(0x%x) %d, got %d\n",
8279 delimiter_tests[i].c, delimiter_tests[i].isdelimiter, result);
8280 }
8281 DestroyWindow(hwndRichEdit);
8282}
8283
8285{
8286 static const struct {
8287 WCHAR c;
8288 BOOL isdelimiter; /* expected result of WB_ISDELIMITER */
8289 } delimiter_tests[] = {
8290 {0x0a, FALSE}, /* newline */
8291 {0x0b, FALSE}, /* vertical tab */
8292 {0x0c, FALSE}, /* form feed */
8293 {0x0d, FALSE}, /* carriage return */
8294 {0x20, TRUE}, /* space */
8295 {0x61, FALSE}, /* capital letter a */
8296 };
8297 int i;
8298 HWND hwndRichEdit = new_richedit(NULL);
8299
8300 ok(!IsWindowUnicode(hwndRichEdit), "window should not be unicode\n");
8301 for (i = 0; i < ARRAY_SIZE(delimiter_tests); i++)
8302 {
8303 int result;
8304 char buf[2];
8305 buf[0] = delimiter_tests[i].c;
8306 buf[1] = 0;
8307 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)buf);
8309 todo_wine_if (buf[0] == 0x20)
8310 ok(result == delimiter_tests[i].isdelimiter,
8311 "wanted ISDELIMITER_A(0x%x) %d, got %d\n",
8312 delimiter_tests[i].c, delimiter_tests[i].isdelimiter, result);
8313 }
8314 DestroyWindow(hwndRichEdit);
8315}
8316
8317static void format_test_result(char *target, const char *src)
8318{
8319 int i;
8320 for (i = 0; i < strlen(src); i++)
8321 sprintf(target + 2*i, "%02x", src[i] & 0xFF);
8322 target[2*i] = 0;
8323}
8324
8325/*
8326 * This test attempts to show the effect of enter on a richedit
8327 * control v1.0 inserts CRLF whereas for higher versions it only
8328 * inserts CR. If shows that EM_GETTEXTEX with GT_USECRLF == WM_GETTEXT
8329 * and also shows that GT_USECRLF has no effect in richedit 1.0, but
8330 * does for higher. The same test is cloned in riched32 and riched20.
8331 * Also shows the difference between WM_CHAR/WM_KEYDOWN in v1.0 and higher versions
8332 */
8333static void test_enter(void)
8334{
8335 static const struct {
8336 const char *initialtext;
8337 const int cursor;
8338 const char *expectedwmtext;
8339 const char *expectedemtext;
8340 const char *expectedemtextcrlf;
8341 } testenteritems[] = {
8342 { "aaabbb\r\n", 3, "aaa\r\nbbb\r\n", "aaa\rbbb\r", "aaa\r\nbbb\r\n"},
8343 { "aaabbb\r\n", 6, "aaabbb\r\n\r\n", "aaabbb\r\r", "aaabbb\r\n\r\n"},
8344 { "aa\rabbb\r\n", 7, "aa\r\nabbb\r\n\r\n", "aa\rabbb\r\r", "aa\r\nabbb\r\n\r\n"},
8345 { "aa\rabbb\r\n", 3, "aa\r\n\r\nabbb\r\n", "aa\r\rabbb\r", "aa\r\n\r\nabbb\r\n"},
8346 { "aa\rabbb\r\n", 2, "aa\r\n\r\nabbb\r\n", "aa\r\rabbb\r", "aa\r\n\r\nabbb\r\n"}
8347 };
8348
8349 char expectedbuf[1024];
8350 char resultbuf[1024];
8351 HWND hwndRichEdit = new_richedit(NULL);
8352 UINT i;
8353 char buf[1024] = {0};
8354 GETTEXTEX getText = {sizeof(buf)};
8356 const char *expected;
8357
8358 for (i = 0; i < ARRAY_SIZE(testenteritems); i++)
8359 {
8360 /* Set the text to the initial text */
8361 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)testenteritems[i].initialtext);
8362 ok (result == 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i, result);
8363
8364 /* Send Enter */
8365 SendMessageA(hwndRichEdit, EM_SETSEL, testenteritems[i].cursor, testenteritems[i].cursor);
8366 simulate_typing_characters(hwndRichEdit, "\r");
8367
8368 /* 1. Retrieve with WM_GETTEXT */
8369 buf[0] = 0x00;
8370 result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf);
8371 expected = testenteritems[i].expectedwmtext;
8372
8373 format_test_result(resultbuf, buf);
8374 format_test_result(expectedbuf, expected);
8375
8377 ok (result == 0,
8378 "[%d] WM_GETTEXT unexpected '%s' expected '%s'\n",
8379 i, resultbuf, expectedbuf);
8380
8381 /* 2. Retrieve with EM_GETTEXTEX, GT_DEFAULT */
8382 getText.flags = GT_DEFAULT;
8383 getText.codepage = CP_ACP;
8384 buf[0] = 0x00;
8385 result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
8386 expected = testenteritems[i].expectedemtext;
8387
8388 format_test_result(resultbuf, buf);
8389 format_test_result(expectedbuf, expected);
8390
8392 ok (result == 0,
8393 "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n",
8394 i, resultbuf, expectedbuf);
8395
8396 /* 3. Retrieve with EM_GETTEXTEX, GT_USECRLF */
8397 getText.flags = GT_USECRLF;
8398 getText.codepage = CP_ACP;
8399 buf[0] = 0x00;
8400 result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
8401 expected = testenteritems[i].expectedemtextcrlf;
8402
8403 format_test_result(resultbuf, buf);
8404 format_test_result(expectedbuf, expected);
8405
8407 ok (result == 0,
8408 "[%d] EM_GETTEXTEX, GT_USECRLF unexpected '%s', expected '%s'\n",
8409 i, resultbuf, expectedbuf);
8410 }
8411
8412 /* Show that WM_CHAR is handled differently from WM_KEYDOWN */
8413 getText.flags = GT_DEFAULT;
8414 getText.codepage = CP_ACP;
8415
8416 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
8417 ok (result == 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i, result);
8418 SendMessageW(hwndRichEdit, WM_CHAR, 'T', 0);
8419 SendMessageW(hwndRichEdit, WM_KEYDOWN, VK_RETURN, 0);
8420
8421 result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
8422 ok(result == 2, "Got %d\n", (int)result);
8423 format_test_result(resultbuf, buf);
8424 format_test_result(expectedbuf, "T\r");
8425 result = strcmp(resultbuf, expectedbuf);
8426 ok (result == 0, "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n", i, resultbuf, expectedbuf);
8427
8428 result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
8429 ok (result == 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i, result);
8430 SendMessageW(hwndRichEdit, WM_CHAR, 'T', 0);
8431 SendMessageW(hwndRichEdit, WM_CHAR, '\r', 0);
8432
8433 result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
8434 ok(result == 1, "Got %d\n", (int)result);
8435 format_test_result(resultbuf, buf);
8436 format_test_result(expectedbuf, "T");
8437 result = strcmp(resultbuf, expectedbuf);
8438 ok (result == 0, "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n", i, resultbuf, expectedbuf);
8439
8440 DestroyWindow(hwndRichEdit);
8441}
8442
8443static void test_WM_CREATE(void)
8444{
8445 static const WCHAR titleW[] = {'l','i','n','e','1','\n','l','i','n','e','2',0};
8446 static const char title[] = "line1\nline2";
8447
8448 HWND rich_edit;
8449 LRESULT res;
8450 char buf[64];
8451 int len;
8452
8454 0, 0, 200, 80, NULL, NULL, NULL, NULL);
8455 ok(rich_edit != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS20A, (int) GetLastError());
8456
8457 len = GetWindowTextA(rich_edit, buf, sizeof(buf));
8458 ok(len == 5, "GetWindowText returned %d\n", len);
8459 ok(!strcmp(buf, "line1"), "buf = %s\n", buf);
8460
8461 res = SendMessageA(rich_edit, EM_GETSEL, 0, 0);
8462 ok(res == 0, "SendMessage(EM_GETSEL) returned %lx\n", res);
8463
8464 DestroyWindow(rich_edit);
8465
8467 0, 0, 200, 80, NULL, NULL, NULL, NULL);
8468 ok(rich_edit != NULL, "class: %s, error: %d\n", wine_dbgstr_w(RICHEDIT_CLASS20W), (int) GetLastError());
8469
8470 len = GetWindowTextA(rich_edit, buf, sizeof(buf));
8471 ok(len == 12, "GetWindowText returned %d\n", len);
8472 ok(!strcmp(buf, "line1\r\nline2"), "buf = %s\n", buf);
8473
8474 res = SendMessageA(rich_edit, EM_GETSEL, 0, 0);
8475 ok(res == 0, "SendMessage(EM_GETSEL) returned %lx\n", res);
8476
8477 DestroyWindow(rich_edit);
8478}
8479
8480/*******************************************************************
8481 * Test that after deleting all of the text, the first paragraph
8482 * format reverts to the default.
8483 */
8485{
8486 HWND richedit = new_richeditW( NULL );
8488 WORD def_align, new_align;
8489
8490 memset( &fmt, 0, sizeof(fmt) );
8491 fmt.cbSize = sizeof(PARAFORMAT2);
8492 fmt.dwMask = -1;
8493 SendMessageA( richedit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt );
8494 def_align = fmt.wAlignment;
8495 new_align = (def_align == PFA_LEFT) ? PFA_RIGHT : PFA_LEFT;
8496
8497 simulate_typing_characters( richedit, "123" );
8498
8499 SendMessageA( richedit, EM_SETSEL, 0, -1 );
8500 fmt.dwMask = PFM_ALIGNMENT;
8501 fmt.wAlignment = new_align;
8502 SendMessageA( richedit, EM_SETPARAFORMAT, 0, (LPARAM)&fmt );
8503
8504 SendMessageA( richedit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt );
8505 ok( fmt.wAlignment == new_align, "got %d expect %d\n", fmt.wAlignment, new_align );
8506
8507 SendMessageA( richedit, EM_SETSEL, 0, -1 );
8508 SendMessageA( richedit, WM_CUT, 0, 0 );
8509
8510 SendMessageA( richedit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt );
8511 ok( fmt.wAlignment == def_align, "got %d expect %d\n", fmt.wAlignment, def_align );
8512
8513 DestroyWindow( richedit );
8514}
8515
8516static void test_EM_SETREADONLY(void)
8517{
8518 HWND richedit = new_richeditW(NULL);
8519 DWORD dwStyle;
8520 LRESULT res;
8521
8522 res = SendMessageA(richedit, EM_SETREADONLY, TRUE, 0);
8523 ok(res == 1, "EM_SETREADONLY\n");
8524 dwStyle = GetWindowLongA(richedit, GWL_STYLE);
8525 ok(dwStyle & ES_READONLY, "got wrong value: 0x%x\n", dwStyle);
8526
8527 res = SendMessageA(richedit, EM_SETREADONLY, FALSE, 0);
8528 ok(res == 1, "EM_SETREADONLY\n");
8529 dwStyle = GetWindowLongA(richedit, GWL_STYLE);
8530 ok(!(dwStyle & ES_READONLY), "got wrong value: 0x%x\n", dwStyle);
8531
8532 DestroyWindow(richedit);
8533}
8534
8536{
8537 return value / 20;
8538}
8539
8540#define TEST_EM_SETFONTSIZE(hwnd,size,expected_size,expected_res,expected_undo) \
8541 _test_font_size(__LINE__,hwnd,size,expected_size,expected_res,expected_undo)
8542static void _test_font_size(unsigned line, HWND hwnd, LONG size, LONG expected_size,
8543 LRESULT expected_res, BOOL expected_undo)
8544{
8546 LRESULT res;
8547 BOOL isundo;
8548
8549 cf.cbSize = sizeof(cf);
8550 cf.dwMask = CFM_SIZE;
8551
8554 isundo = SendMessageA(hwnd, EM_CANUNDO, 0, 0);
8555 ok_(__FILE__,line)(res == expected_res, "EM_SETFONTSIZE unexpected return value: %lx.\n", res);
8556 ok_(__FILE__,line)(twips2points(cf.yHeight) == expected_size, "got wrong font size: %d, expected: %d\n",
8557 twips2points(cf.yHeight), expected_size);
8558 ok_(__FILE__,line)(isundo == expected_undo, "get wrong undo mark: %d, expected: %d.\n",
8559 isundo, expected_undo);
8560}
8561
8562static void test_EM_SETFONTSIZE(void)
8563{
8564 HWND richedit = new_richedit(NULL);
8565 CHAR text[] = "wine";
8566 CHARFORMAT2A tmp_cf;
8567 LONG default_size;
8568
8569 tmp_cf.cbSize = sizeof(tmp_cf);
8570 tmp_cf.dwMask = CFM_SIZE;
8571 tmp_cf.yHeight = 9 * 20.0;
8572 SendMessageA(richedit, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM)&tmp_cf);
8573
8574 SendMessageA(richedit, WM_SETTEXT, 0, (LPARAM)text);
8575
8576 SendMessageA(richedit, EM_SETMODIFY, FALSE, 0);
8577 /* without selection */
8578 TEST_EM_SETFONTSIZE(richedit, 1, 10, TRUE, FALSE); /* 9 + 1 -> 10 */
8579 SendMessageA(richedit, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM)&tmp_cf);
8580 default_size = twips2points(tmp_cf.yHeight);
8581 ok(default_size == 9, "Default font size should not be changed.\n");
8582 ok(SendMessageA(richedit, EM_SETMODIFY, 0, 0) == FALSE, "Modify flag should not be changed.\n");
8583
8584 SendMessageA(richedit, EM_SETSEL, 0, 2);
8585
8586 TEST_EM_SETFONTSIZE(richedit, 0, 9, TRUE, TRUE); /* 9 + 0 -> 9 */
8587
8588 SendMessageA(richedit, EM_SETMODIFY, FALSE, 0);
8589 TEST_EM_SETFONTSIZE(richedit, 3, 12, TRUE, TRUE); /* 9 + 3 -> 12 */
8590 ok(SendMessageA(richedit, EM_SETMODIFY, 0, 0) == FALSE, "Modify flag should not be changed.\n");
8591
8592 TEST_EM_SETFONTSIZE(richedit, 1, 14, TRUE, TRUE); /* 12 + 1 + 1 -> 14 */
8593 TEST_EM_SETFONTSIZE(richedit, -1, 12, TRUE, TRUE); /* 14 - 1 - 1 -> 12 */
8594 TEST_EM_SETFONTSIZE(richedit, 4, 16, TRUE, TRUE); /* 12 + 4 -> 16 */
8595 TEST_EM_SETFONTSIZE(richedit, 3, 20, TRUE, TRUE); /* 16 + 3 + 1 -> 20 */
8596 TEST_EM_SETFONTSIZE(richedit, 0, 20, TRUE, TRUE); /* 20 + 0 -> 20 */
8597 TEST_EM_SETFONTSIZE(richedit, 8, 28, TRUE, TRUE); /* 20 + 8 -> 28 */
8598 TEST_EM_SETFONTSIZE(richedit, 0, 28, TRUE, TRUE); /* 28 + 0 -> 28 */
8599 TEST_EM_SETFONTSIZE(richedit, 1, 36, TRUE, TRUE); /* 28 + 1 -> 36 */
8600 TEST_EM_SETFONTSIZE(richedit, 0, 36, TRUE, TRUE); /* 36 + 0 -> 36 */
8601 TEST_EM_SETFONTSIZE(richedit, 1, 48, TRUE, TRUE); /* 36 + 1 -> 48 */
8602 TEST_EM_SETFONTSIZE(richedit, 0, 48, TRUE, TRUE); /* 48 + 0 -> 48 */
8603 TEST_EM_SETFONTSIZE(richedit, 1, 72, TRUE, TRUE); /* 48 + 1 -> 72 */
8604 TEST_EM_SETFONTSIZE(richedit, 0, 72, TRUE, TRUE); /* 72 + 0 -> 72 */
8605 TEST_EM_SETFONTSIZE(richedit, 1, 80, TRUE, TRUE); /* 72 + 1 -> 80 */
8606 TEST_EM_SETFONTSIZE(richedit, 0, 80, TRUE, TRUE); /* 80 + 0 -> 80 */
8607 TEST_EM_SETFONTSIZE(richedit, 1, 90, TRUE, TRUE); /* 80 + 1 -> 90 */
8608 TEST_EM_SETFONTSIZE(richedit, 0, 90, TRUE, TRUE); /* 90 + 0 -> 90 */
8609 TEST_EM_SETFONTSIZE(richedit, 1, 100, TRUE, TRUE); /* 90 + 1 -> 100 */
8610 TEST_EM_SETFONTSIZE(richedit, 25, 130, TRUE, TRUE); /* 100 + 25 -> 130 */
8611 TEST_EM_SETFONTSIZE(richedit, -1, 120, TRUE, TRUE); /* 130 - 1 -> 120 */
8612 TEST_EM_SETFONTSIZE(richedit, -35, 80, TRUE, TRUE); /* 120 - 35 -> 80 */
8613 TEST_EM_SETFONTSIZE(richedit, -7, 72, TRUE, TRUE); /* 80 - 7 -> 72 */
8614 TEST_EM_SETFONTSIZE(richedit, -42, 28, TRUE, TRUE); /* 72 - 42 -> 28 */
8615 TEST_EM_SETFONTSIZE(richedit, -16, 12, TRUE, TRUE); /* 28 - 16 -> 12 */
8616 TEST_EM_SETFONTSIZE(richedit, -3, 9, TRUE, TRUE); /* 12 - 3 -> 9 */
8617 TEST_EM_SETFONTSIZE(richedit, -8, 1, TRUE, TRUE); /* 9 - 8 -> 1 */
8618 TEST_EM_SETFONTSIZE(richedit, -111, 1, TRUE, TRUE); /* 1 - 111 -> 1 */
8619 TEST_EM_SETFONTSIZE(richedit, 10086, 1638, TRUE, TRUE); /* 1 + 10086 -> 1638 */
8620
8621 /* return FALSE when richedit is TM_PLAINTEXT mode */
8622 SendMessageA(richedit, WM_SETTEXT, 0, (LPARAM)"");
8624 TEST_EM_SETFONTSIZE(richedit, 0, 9, FALSE, FALSE);
8625
8626 DestroyWindow(richedit);
8627}
8628
8629static void test_alignment_style(void)
8630{
8631 HWND richedit = NULL;
8632 PARAFORMAT2 pf;
8633 DWORD align_style[] = {ES_LEFT, ES_CENTER, ES_RIGHT, ES_RIGHT | ES_CENTER,
8638 const char * streamtext =
8639 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n"
8640 "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n"
8641 "}\r\n";
8642 EDITSTREAM es;
8643 int i;
8644
8645 for (i = 0; i < ARRAY_SIZE(align_style); i++)
8646 {
8647 DWORD dwStyle, new_align;
8648
8649 richedit = new_windowW(RICHEDIT_CLASS20W, align_style[i], NULL);
8650 memset(&pf, 0, sizeof(pf));
8651 pf.cbSize = sizeof(PARAFORMAT2);
8652 pf.dwMask = -1;
8653
8654 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
8655 ok(pf.wAlignment == align_mask[i], "(i = %d) got %d expected %d\n",
8656 i, pf.wAlignment, align_mask[i]);
8657 dwStyle = GetWindowLongW(richedit, GWL_STYLE);
8658 ok((i ? (dwStyle & align_style[i]) : (!(dwStyle & 0x0000000f))) ,
8659 "(i = %d) didn't set right align style: 0x%x\n", i, dwStyle);
8660
8661
8662 /* Based on test_reset_default_para_fmt() */
8663 new_align = (align_mask[i] == PFA_LEFT) ? PFA_RIGHT : PFA_LEFT;
8664 simulate_typing_characters(richedit, "123");
8665
8666 SendMessageW(richedit, EM_SETSEL, 0, -1);
8667 pf.dwMask = PFM_ALIGNMENT;
8668 pf.wAlignment = new_align;
8669 SendMessageW(richedit, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
8670
8671 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
8672 ok(pf.wAlignment == new_align, "got %d expect %d\n", pf.wAlignment, new_align);
8673
8674 SendMessageW(richedit, EM_SETSEL, 0, -1);
8675 SendMessageW(richedit, WM_CUT, 0, 0);
8676
8677 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
8678 ok(pf.wAlignment == align_mask[i], "got %d expect %d\n", pf.wAlignment, align_mask[i]);
8679
8680 /* Test out of bounds tab count */
8681 pf.dwMask = PFM_TABSTOPS;
8682 pf.cTabCount = -25000;
8683 SendMessageW(richedit, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
8684 ok(pf.cTabCount == -25000, "Got %d\n", pf.cTabCount);
8685 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
8686 ok(pf.cTabCount == 0, "Got %d\n", pf.cTabCount);
8687 pf.dwMask = PFM_TABSTOPS;
8688 pf.cTabCount = 25000;
8689 SendMessageW(richedit, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
8690 ok(pf.cTabCount == 25000, "Got %d\n", pf.cTabCount);
8691 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
8692 ok(pf.cTabCount == 32, "Got %d\n", pf.cTabCount);
8693 pf.dwMask = PFM_TABSTOPS;
8694 pf.cTabCount = 32;
8695 SendMessageW(richedit, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
8696 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
8697 ok(pf.cTabCount == 32, "Got %d\n", pf.cTabCount);
8698 pf.dwMask = PFM_TABSTOPS;
8699 pf.cTabCount = 33;
8700 SendMessageW(richedit, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
8701 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
8702 ok(pf.cTabCount == 32, "Got %d\n", pf.cTabCount);
8703 pf.dwMask = PFM_TABSTOPS;
8704 pf.cTabCount = 1;
8705 SendMessageW(richedit, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
8706 SendMessageW(richedit, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
8707 ok(pf.cTabCount == 1, "Got %d\n", pf.cTabCount);
8708
8709 DestroyWindow(richedit);
8710 }
8711
8712 /* test with EM_STREAMIN */
8714 simulate_typing_characters(richedit, "abc");
8715 es.dwCookie = (DWORD_PTR)&streamtext;
8716 es.dwError = 0;
8717 es.pfnCallback = test_EM_STREAMIN_esCallback;
8718 SendMessageW(richedit, EM_STREAMIN, SF_RTF, (LPARAM)&es);
8719 SendMessageW(richedit, EM_SETSEL, 0, -1);
8720 memset(&pf, 0, sizeof(pf));
8721 pf.cbSize = sizeof(PARAFORMAT2);
8722 pf.dwMask = -1;
8724 ok(pf.wAlignment == PFA_LEFT, "got %d expected PFA_LEFT\n", pf.wAlignment);
8725 DestroyWindow(richedit);
8726}
8727
8728static void test_WM_GETTEXTLENGTH(void)
8729{
8730 HWND hwndRichEdit = new_richedit(NULL);
8731 static const char text1[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee";
8732 static const char text2[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee\r\n";
8733 static const char text3[] = "abcdef\x8e\xf0";
8734 int result;
8735
8736 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
8737 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
8738 ok(result == lstrlenA(text1), "WM_GETTEXTLENGTH returned %d, expected %d\n",
8739 result, lstrlenA(text1));
8740
8741 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
8742 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
8743 ok(result == lstrlenA(text2), "WM_GETTEXTLENGTH returned %d, expected %d\n",
8744 result, lstrlenA(text2));
8745
8746 /* Test with multibyte character */
8747 if (!is_lang_japanese)
8748 skip("Skip multibyte character tests on non-Japanese platform\n");
8749 else
8750 {
8751 SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text3);
8752 result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
8753 todo_wine ok(result == 8, "WM_GETTEXTLENGTH returned %d, expected 8\n", result);
8754 }
8755
8756 DestroyWindow(hwndRichEdit);
8757}
8758
8759static void test_rtf(void)
8760{
8761 const char *specials = "{\\rtf1\\emspace\\enspace\\bullet\\lquote"
8762 "\\rquote\\ldblquote\\rdblquote\\ltrmark\\rtlmark\\zwj\\zwnj}";
8763 const WCHAR expect_specials[] = {' ',' ',0x2022,0x2018,0x2019,0x201c,
8764 0x201d,0x200e,0x200f,0x200d,0x200c};
8765 const char *pard = "{\\rtf1 ABC\\rtlpar\\par DEF\\par HIJ\\pard\\par}";
8766 const char *highlight = "{\\rtf1{\\colortbl;\\red0\\green0\\blue0;\\red128\\green128\\blue128;\\red192\\green192\\blue192;}\\cf2\\highlight3 foo\\par}";
8767
8768 HWND edit = new_richeditW( NULL );
8769 EDITSTREAM es;
8770 WCHAR buf[80];
8774
8775 /* Test rtf specials */
8776 es.dwCookie = (DWORD_PTR)&specials;
8777 es.dwError = 0;
8778 es.pfnCallback = test_EM_STREAMIN_esCallback;
8780 ok( result == 11, "got %ld\n", result );
8781
8783 ok( result == ARRAY_SIZE(expect_specials), "got %ld\n", result );
8784 ok( !memcmp( buf, expect_specials, sizeof(expect_specials) ), "got %s\n", wine_dbgstr_w(buf) );
8785
8786 /* Show that \rtlpar propagates to the second paragraph and is
8787 reset by \pard in the third. */
8788 es.dwCookie = (DWORD_PTR)&pard;
8790 ok( result == 11, "got %ld\n", result );
8791
8792 fmt.cbSize = sizeof(fmt);
8793 SendMessageW( edit, EM_SETSEL, 1, 1 );
8794 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt );
8795 ok( fmt.dwMask & PFM_RTLPARA, "rtl para mask not set\n" );
8796 ok( fmt.wEffects & PFE_RTLPARA, "rtl para not set\n" );
8797 SendMessageW( edit, EM_SETSEL, 5, 5 );
8798 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt );
8799 ok( fmt.dwMask & PFM_RTLPARA, "rtl para mask not set\n" );
8800 ok( fmt.wEffects & PFE_RTLPARA, "rtl para not set\n" );
8801 SendMessageW( edit, EM_SETSEL, 9, 9 );
8802 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt );
8803 ok( fmt.dwMask & PFM_RTLPARA, "rtl para mask not set\n" );
8804 ok( !(fmt.wEffects & PFE_RTLPARA), "rtl para set\n" );
8805
8806 /* Test \highlight */
8807 es.dwCookie = (DWORD_PTR)&highlight;
8809 ok( result == 3, "got %ld\n", result );
8810 SendMessageW( edit, EM_SETSEL, 1, 1 );
8811 memset( &cf, 0, sizeof(cf) );
8812 cf.cbSize = sizeof(cf);
8814 ok( (cf.dwEffects & (CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR)) == 0, "got %08x\n", cf.dwEffects );
8815 ok( cf.crTextColor == RGB(128,128,128), "got %08x\n", cf.crTextColor );
8816 ok( cf.crBackColor == RGB(192,192,192), "got %08x\n", cf.crBackColor );
8817
8818 DestroyWindow( edit );
8819}
8820
8821static void test_background(void)
8822{
8823 HWND hwndRichEdit = new_richedit(NULL);
8824
8825 /* set the background color to black */
8826 ValidateRect(hwndRichEdit, NULL);
8827 SendMessageA(hwndRichEdit, EM_SETBKGNDCOLOR, FALSE, RGB(0, 0, 0));
8828 ok(GetUpdateRect(hwndRichEdit, NULL, FALSE), "Update rectangle is empty!\n");
8829
8830 DestroyWindow(hwndRichEdit);
8831}
8832
8833static void test_eop_char_fmt(void)
8834{
8835 HWND edit = new_richedit( NULL );
8836 const char *rtf = "{\\rtf1{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 Arial;}{\\f1\\fnil\\fcharset2 Symbol;}}"
8837 "{\\fs10{\\pard\\fs16\\fi200\\li360\\f0 First\\par"
8838 "\\f0\\fs25 Second\\par"
8839 "{\\f0\\fs26 Third}\\par"
8840 "{\\f0\\fs22 Fourth}\\par}}}";
8841 EDITSTREAM es;
8843 int i, num, expect_height;
8844
8845 es.dwCookie = (DWORD_PTR)&rtf;
8846 es.dwError = 0;
8847 es.pfnCallback = test_EM_STREAMIN_esCallback;
8848 num = SendMessageA( edit, EM_STREAMIN, SF_RTF, (LPARAM)&es );
8849 ok( num == 25, "got %d\n", num );
8850
8851 for (i = 0; i <= num; i++)
8852 {
8853 SendMessageW( edit, EM_SETSEL, i, i + 1 );
8854 cf.cbSize = sizeof(cf);
8855 cf.dwMask = CFM_SIZE;
8857 ok( cf.dwMask & CFM_SIZE, "%d: got %08x\n", i, cf.dwMask );
8858 if (i < 6) expect_height = 160;
8859 else if (i < 13) expect_height = 250;
8860 else if (i < 18) expect_height = 260;
8861 else if (i == 18 || i == 25) expect_height = 250;
8862 else expect_height = 220;
8863 ok( cf.yHeight == expect_height, "%d: got %d\n", i, cf.yHeight );
8864 }
8865
8866 DestroyWindow( edit );
8867}
8868
8869static void test_para_numbering(void)
8870{
8871 HWND edit = new_richeditW( NULL );
8872 const char *numbers = "{\\rtf1{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 Arial;}{\\f1\\fnil\\fcharset2 Symbol;}}"
8873 "\\pard{\\pntext\\f0 3.\\tab}{\\*\\pn\\pnlvlbody\\pnfs32\\pnf0\\pnindent1000\\pnstart2\\pndec{\\pntxta.}}"
8874 "\\fs20\\fi200\\li360\\f0 First\\par"
8875 "{\\pntext\\f0 4.\\tab}\\f0 Second\\par"
8876 "{\\pntext\\f0 6.\\tab}\\f0 Third\\par}";
8877 const WCHAR expect_numbers_txt[] = {'F','i','r','s','t','\r','S','e','c','o','n','d','\r','T','h','i','r','d',0};
8878 EDITSTREAM es;
8879 WCHAR buf[80];
8881 PARAFORMAT2 fmt, fmt2;
8884
8885 get_text.cb = sizeof(buf);
8886 get_text.flags = GT_RAWTEXT;
8887 get_text.codepage = 1200;
8888 get_text.lpDefaultChar = NULL;
8889 get_text.lpUsedDefChar = NULL;
8890
8891 es.dwCookie = (DWORD_PTR)&numbers;
8892 es.dwError = 0;
8893 es.pfnCallback = test_EM_STREAMIN_esCallback;
8895 ok( result == lstrlenW( expect_numbers_txt ), "got %ld\n", result );
8896
8898 ok( result == lstrlenW( expect_numbers_txt ), "got %ld\n", result );
8899 ok( !lstrcmpW( buf, expect_numbers_txt ), "got %s\n", wine_dbgstr_w(buf) );
8900
8901 SendMessageW( edit, EM_SETSEL, 1, 1 );
8902 memset( &fmt, 0, sizeof(fmt) );
8903 fmt.cbSize = sizeof(fmt);
8904 fmt.dwMask = PFM_ALL2;
8905 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt );
8906 ok( fmt.wNumbering == PFN_ARABIC, "got %d\n", fmt.wNumbering );
8907 ok( fmt.wNumberingStart == 2, "got %d\n", fmt.wNumberingStart );
8908 ok( fmt.wNumberingStyle == PFNS_PERIOD, "got %04x\n", fmt.wNumberingStyle );
8909 ok( fmt.wNumberingTab == 1000, "got %d\n", fmt.wNumberingTab );
8910 ok( fmt.dxStartIndent == 560, "got %d\n", fmt.dxStartIndent );
8911 ok( fmt.dxOffset == -200, "got %d\n", fmt.dxOffset );
8912
8913 /* Second para should have identical fmt */
8914 SendMessageW( edit, EM_SETSEL, 10, 10 );
8915 memset( &fmt2, 0, sizeof(fmt2) );
8916 fmt2.cbSize = sizeof(fmt2);
8917 fmt2.dwMask = PFM_ALL2;
8918 SendMessageW( edit, EM_GETPARAFORMAT, 0, (LPARAM)&fmt2 );
8919 ok( !memcmp( &fmt, &fmt2, sizeof(fmt) ), "format mismatch\n" );
8920
8921 /* Check the eop heights - this determines the label height */
8922 SendMessageW( edit, EM_SETSEL, 12, 13 );
8923 cf.cbSize = sizeof(cf);
8924 cf.dwMask = CFM_SIZE;
8926 ok( cf.yHeight == 200, "got %d\n", cf.yHeight );
8927
8928 SendMessageW( edit, EM_SETSEL, 18, 19 );
8929 cf.cbSize = sizeof(cf);
8930 cf.dwMask = CFM_SIZE;
8932 ok( cf.yHeight == 200, "got %d\n", cf.yHeight );
8933
8934 DestroyWindow( edit );
8935}
8936
8937static void fill_reobject_struct(REOBJECT *reobj, LONG cp, LPOLEOBJECT poleobj,
8938 LPSTORAGE pstg, LPOLECLIENTSITE polesite, LONG sizel_cx,
8939 LONG sizel_cy, DWORD aspect, DWORD flags, DWORD user)
8940{
8941 reobj->cbStruct = sizeof(*reobj);
8942 reobj->clsid = CLSID_NULL;
8943 reobj->cp = cp;
8944 reobj->poleobj = poleobj;
8945 reobj->pstg = pstg;
8946 reobj->polesite = polesite;
8947 reobj->sizel.cx = sizel_cx;
8948 reobj->sizel.cy = sizel_cy;
8949 reobj->dvaspect = aspect;
8950 reobj->dwFlags = flags;
8951 reobj->dwUser = user;
8952}
8953
8954static void test_EM_SELECTIONTYPE(void)
8955{
8957 IRichEditOle *reole = NULL;
8958 static const char text1[] = "abcdefg\n";
8959 int result;
8960 REOBJECT reo1, reo2;
8961 IOleClientSite *clientsite;
8962 HRESULT hr;
8963
8964 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)text1);
8966
8967 SendMessageA(hwnd, EM_SETSEL, 1, 1);
8969 ok(result == SEL_EMPTY, "got wrong selection type: %x.\n", result);
8970
8971 SendMessageA(hwnd, EM_SETSEL, 1, 2);
8973 ok(result == SEL_TEXT, "got wrong selection type: %x.\n", result);
8974
8975 SendMessageA(hwnd, EM_SETSEL, 2, 5);
8977 ok(result == (SEL_TEXT | SEL_MULTICHAR), "got wrong selection type: %x.\n", result);
8978
8979 SendMessageA(hwnd, EM_SETSEL, 0, 1);
8980 hr = IRichEditOle_GetClientSite(reole, &clientsite);
8981 ok(hr == S_OK, "IRichEditOle_GetClientSite failed: 0x%08x\n", hr);
8982 fill_reobject_struct(&reo1, REO_CP_SELECTION, NULL, NULL, clientsite, 10, 10,
8983 DVASPECT_CONTENT, 0, 1);
8984 hr = IRichEditOle_InsertObject(reole, &reo1);
8985 ok(hr == S_OK, "IRichEditOle_InsertObject failed: 0x%08x\n", hr);
8986 IOleClientSite_Release(clientsite);
8987
8988 SendMessageA(hwnd, EM_SETSEL, 0, 1);
8990 ok(result == SEL_OBJECT, "got wrong selection type: %x.\n", result);
8991
8992 SendMessageA(hwnd, EM_SETSEL, 0, 2);
8994 ok(result == (SEL_TEXT | SEL_OBJECT), "got wrong selection type: %x.\n", result);
8995
8996 SendMessageA(hwnd, EM_SETSEL, 0, 3);
8998 ok(result == (SEL_TEXT | SEL_MULTICHAR | SEL_OBJECT), "got wrong selection type: %x.\n", result);
8999
9000 SendMessageA(hwnd, EM_SETSEL, 2, 3);
9001 hr = IRichEditOle_GetClientSite(reole, &clientsite);
9002 ok(hr == S_OK, "IRichEditOle_GetClientSite failed: 0x%08x\n", hr);
9003 fill_reobject_struct(&reo2, REO_CP_SELECTION, NULL, NULL, clientsite, 10, 10,
9004 DVASPECT_CONTENT, 0, 2);
9005 hr = IRichEditOle_InsertObject(reole, &reo2);
9006 ok(hr == S_OK, "IRichEditOle_InsertObject failed: 0x%08x\n", hr);
9007 IOleClientSite_Release(clientsite);
9008
9009 SendMessageA(hwnd, EM_SETSEL, 0, 2);
9011 ok(result == (SEL_OBJECT | SEL_TEXT), "got wrong selection type: %x.\n", result);
9012
9013 SendMessageA(hwnd, EM_SETSEL, 0, 3);
9015 ok(result == (SEL_OBJECT | SEL_MULTIOBJECT | SEL_TEXT), "got wrong selection type: %x.\n", result);
9016
9017 SendMessageA(hwnd, EM_SETSEL, 0, 4);
9019 ok(result == (SEL_TEXT| SEL_MULTICHAR | SEL_OBJECT | SEL_MULTIOBJECT), "got wrong selection type: %x.\n", result);
9020
9021 IRichEditOle_Release(reole);
9023}
9024
9025static void test_window_classes(void)
9026{
9027 static const struct
9028 {
9029 const char *class;
9030 BOOL success;
9031 } test[] =
9032 {
9033 { "RichEdit", FALSE },
9034 { "RichEdit20A", TRUE },
9035 { "RichEdit20W", TRUE },
9036 { "RichEdit50A", FALSE },
9037 { "RichEdit50W", FALSE }
9038 };
9039 int i;
9040 HWND hwnd;
9041
9042 for (i = 0; i < sizeof(test)/sizeof(test[0]); i++)
9043 {
9044 SetLastError(0xdeadbeef);
9045 hwnd = CreateWindowExA(0, test[i].class, NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL);
9046todo_wine_if(!strcmp(test[i].class, "RichEdit50A") || !strcmp(test[i].class, "RichEdit50W"))
9047 ok(!hwnd == !test[i].success, "CreateWindow(%s) should %s\n",
9048 test[i].class, test[i].success ? "succeed" : "fail");
9049 if (!hwnd)
9052 else
9054 }
9055}
9056
9057START_TEST( editor )
9058{
9059 BOOL ret;
9060 /* Must explicitly LoadLibrary(). The test has no references to functions in
9061 * RICHED20.DLL, so the linker doesn't actually link to it. */
9062 hmoduleRichEdit = LoadLibraryA("riched20.dll");
9063 ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError());
9065
9067 test_WM_CHAR();
9094 test_WM_PASTE();
9107 test_EN_LINK();
9118 test_zoom();
9122 test_enter();
9128 test_rtf();
9133
9134 /* Set the environment variable WINETEST_RICHED20 to keep windows
9135 * responsive and open for 30 seconds. This is useful for debugging.
9136 */
9137 if (getenv( "WINETEST_RICHED20" )) {
9138 keep_responsive(30);
9139 }
9140
9143 ok(ret, "error: %d\n", (int) GetLastError());
9144}
#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 START_TEST(x)
Definition: atltest.h:75
#define ok_(x1, x2)
Definition: atltest.h:61
static const char * wine_dbgstr_rect(const RECT *prc)
Definition: atltest.h:160
#define msg(x)
Definition: auth_time.c:54
void user(int argc, const char *argv[])
Definition: cmds.c:1350
#define ARRAY_SIZE(A)
Definition: main.h:20
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
#define FR_WHOLEWORD
Definition: commdlg.h:145
#define FR_MATCHCASE
Definition: commdlg.h:136
#define FR_DOWN
Definition: commdlg.h:127
static TAGID TAGID find
Definition: db.cpp:155
#define E_INVALIDARG
Definition: ddrawi.h:101
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define GetProcessHeap()
Definition: compat.h:736
#define CP_ACP
Definition: compat.h:109
#define SetLastError(x)
Definition: compat.h:752
#define 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 WideCharToMultiByte
Definition: compat.h:111
#define MultiByteToWideChar
Definition: compat.h:110
#define lstrlenW
Definition: compat.h:750
HMODULE WINAPI DECLSPEC_HOTPATCH GetModuleHandleA(LPCSTR lpModuleName)
Definition: loader.c:812
HINSTANCE WINAPI DECLSPEC_HOTPATCH LoadLibraryA(LPCSTR lpLibFileName)
Definition: loader.c:111
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:455
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
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:42
POINTL point
Definition: edittest.c:50
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
unsigned short WORD
Definition: ntddk_ex.h:93
GLuint start
Definition: gl.h:1545
const GLdouble * v
Definition: gl.h:2040
GLuint GLuint GLsizei count
Definition: gl.h:1545
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 n
Definition: glext.h:7729
GLuint res
Definition: glext.h:9613
GLenum src
Definition: glext.h:6340
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
GLenum GLint * range
Definition: glext.h:7539
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLbitfield flags
Definition: glext.h:7161
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
const GLint * first
Definition: glext.h:5794
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
GLenum target
Definition: glext.h:7315
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble * u
Definition: glfuncs.h:240
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
static const WCHAR titleW[]
Definition: htmlelem.c:1067
#define es
Definition: i386-dis.c:440
const char cursor[]
Definition: icontest.c:13
_Check_return_ char *__cdecl getenv(_In_z_ const char *_VarName)
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define c
Definition: ke_i.h:80
#define wine_dbgstr_w
Definition: kernel32.h:34
int WINAPI lstrlenA(LPCSTR lpString)
Definition: lstring.c:145
POINT cp
Definition: magnifier.c:59
__u16 time
Definition: mkdosfs.c:8
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
char string[160]
Definition: util.h:11
static PVOID ptr
Definition: dispmode.c:27
#define sprintf(buf, format,...)
Definition: sprintf.c:55
HDC hdc
Definition: main.c:9
static const char textA[]
Definition: registrar.c:40
static HDC
Definition: imagelist.c:88
static BOOL rtl
Definition: propsheet.c:36
static const WCHAR textW[]
Definition: itemdlg.c:1559
static const WCHAR url[]
Definition: encode.c:1432
static const WCHAR desc[]
Definition: protectdata.c:36
BOOL expected
Definition: store.c:2063
static DWORD *static HFONT(WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *)
static HMODULE MODULEINFO DWORD cb
Definition: module.c:33
#define todo_wine_if(is_todo)
Definition: custom.c:86
#define todo_wine
Definition: custom.c:89
static char * dest
Definition: rtl.c:135
static unsigned int recursionLevel
Definition: editor.c:2894
static struct dialog_mode_messages dm_messages
Definition: editor.c:7921
static void test_EM_SELECTIONTYPE(void)
Definition: editor.c:8954
static void test_EM_FORMATRANGE(void)
Definition: editor.c:5614
static CHAR string2[MAX_PATH]
Definition: editor.c:44
static DWORD CALLBACK test_EM_STREAMIN_esCallback_UTF8Split(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
Definition: editor.c:5774
#define expect_empty(hwnd, wm_get_text)
static LRESULT WINAPI WM_NOTIFY_ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
Definition: editor.c:6658
static void test_SETPARAFORMAT(void)
Definition: editor.c:1535
static void simulate_typing_characters(HWND hwnd, const char *szChars)
Definition: editor.c:133
static LRESULT WINAPI EN_LINK_ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
Definition: editor.c:6769
static LRESULT CALLBACK dialog_mode_wnd_proc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
Definition: editor.c:7931
static void test_WM_PASTE(void)
Definition: editor.c:5449
static DWORD CALLBACK test_EM_STREAMIN_null_bytes(DWORD_PTR cookie, BYTE *buf, LONG size, LONG *written)
Definition: editor.c:5797
static void test_EM_EXSETSEL(void)
Definition: editor.c:4968
static void test_EM_GETSELTEXT(void)
Definition: editor.c:1830
static void check_CFE_LINK_rcvd(HWND hwnd, BOOL is_url, const char *url)
Definition: editor.c:1951
static void test_WM_GETTEXT(void)
Definition: editor.c:1679
#define CURSOR_CLIENT_Y
Definition: editor.c:6765
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:8937
static void test_EM_StreamIn_Undo(void)
Definition: editor.c:6120
#define test_dm_messages(wmclose, wmgetdefid, wmnextdlgctl)
Definition: editor.c:7923
static void test_EM_SETOPTIONS(void)
Definition: editor.c:1869
static UINT message
Definition: editor.c:2897
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:6565
static void test_EM_FINDWORDBREAK_W(void)
Definition: editor.c:8240
static void test_WM_SETFONT(void)
Definition: editor.c:4665
static void check_EM_SETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id)
Definition: editor.c:5007
#define WP_PARENT
Definition: editor.c:6766
LONG streamout_written
Definition: editor.c:3696
static HMODULE hmoduleRichEdit
Definition: editor.c:53
#define ID_RICHEDITTESTDBUTTON
Definition: editor.c:42
static void test_undo_coalescing(void)
Definition: editor.c:6965
#define TEST_SETTEXTW(a, b)
static void test_EM_GETTEXTLENGTHEX(void)
Definition: editor.c:6409
static void format_test_result(char *target, const char *src)
Definition: editor.c:8317
static HWND new_richedit(HWND parent)
Definition: editor.c:101
static void test_EM_STREAMOUT_FONTTBL(void)
Definition: editor.c:3943
static void test_EM_GETLINE(void)
Definition: editor.c:419
#define DISABLE_WS_VSCROLL(hwnd)
static void test_WM_GETTEXTLENGTH(void)
Definition: editor.c:8728
#define expect_textW(hwnd, wm_get_text, txt)
static void test_EM_SCROLL(void)
Definition: editor.c:2760
static HWND new_windowW(LPCWSTR lpClassName, DWORD dwStyle, HWND parent)
Definition: editor.c:91
static unsigned int WM_SIZE_recursionLevel
Definition: editor.c:2895
static DWORD CALLBACK test_EM_STREAMIN_esCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
Definition: editor.c:5756
static int nCallbackCount
Definition: editor.c:5730
static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *find, int num_tests, BOOL unicode)
Definition: editor.c:350
static void move_cursor(HWND hwnd, LONG charindex)
Definition: editor.c:555
static WCHAR * atowstr(const char *str)
Definition: editor.c:258
static void test_EM_GETLIMITTEXT(void)
Definition: editor.c:4650
static const struct exsetsel_s exsetsel_tests[]
Definition: editor.c:4921
#define expect_textA(hwnd, wm_get_text, txt)
static void test_EN_LINK(void)
Definition: editor.c:6840
static void test_unicode_conversions(void)
Definition: editor.c:6199
static void test_EM_STREAMIN(void)
Definition: editor.c:5846
static void check_EM_EXSETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id)
Definition: editor.c:4950
static BOOL check_CFE_LINK_selection(HWND hwnd, int sel_start, int sel_end)
Definition: editor.c:1942
static BOOL is_em_settextex_supported(HWND hwnd)
Definition: editor.c:6193
static void test_EM_STREAMOUT(void)
Definition: editor.c:3841
static BOOL hold_key(int vk)
Definition: editor.c:146
static void test_EM_AUTOURLDETECT(void)
Definition: editor.c:1970
static void test_EM_REPLACESEL(int redraw)
Definition: editor.c:5065
static LRESULT send_ctrl_key(HWND hwnd, UINT key)
Definition: editor.c:5440
static int received_WM_NOTIFY
Definition: editor.c:6653
#define ok_w3(format, szString1, szString2, szString3)
Definition: editor.c:46
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:3812
static void test_WM_CREATE(void)
Definition: editor.c:8443
static void test_WM_SETTEXT(void)
Definition: editor.c:3713
static void test_EM_SETCHARFORMAT(void)
Definition: editor.c:779
static int queriedEventMask
Definition: editor.c:6561
static void test_background(void)
Definition: editor.c:8821
static BOOL is_lang_japanese
Definition: editor.c:54
static void test_dialogmode(void)
Definition: editor.c:7949
static BOOL filter_on_WM_NOTIFY
Definition: editor.c:6655
static struct find_s find_tests2[]
Definition: editor.c:195
static void test_EM_SETTEXTMODE(void)
Definition: editor.c:1393
static void test_format_rect(void)
Definition: editor.c:7417
static HWND hwndRichedit_WM_NOTIFY
Definition: editor.c:6656
static LRESULT WINAPI RicheditStupidOverrideProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
Definition: editor.c:2899
static void test_eventMask(void)
Definition: editor.c:6575
static void test_EM_LINELENGTH(void)
Definition: editor.c:491
static struct find_s find_tests[]
Definition: editor.c:186
static void test_scrollbar_visibility(void)
Definition: editor.c:2926
static CHAR string1[MAX_PATH]
Definition: editor.c:44
static void keep_responsive(time_t delay_time)
Definition: editor.c:115
static void test_EM_CHARFROMPOS(void)
Definition: editor.c:7209
#define CURSOR_CLIENT_X
Definition: editor.c:6764
static HWND eventMaskEditHwnd
Definition: editor.c:6560
static BOOL release_key(int vk)
Definition: editor.c:160
static void test_EM_SETFONTSIZE(void)
Definition: editor.c:8562
static DWORD CALLBACK test_EM_GETMODIFY_esCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
Definition: editor.c:4727
static void test_EM_SETSEL(void)
Definition: editor.c:5022
static void line_scroll(HWND hwnd, int amount)
Definition: editor.c:563
static int modify_at_WM_NOTIFY
Definition: editor.c:6654
static void test_rtf(void)
Definition: editor.c:8759
#define MAX_BUF_LEN
static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id, BOOL unicode)
Definition: editor.c:268
static void test_WM_GETDLGCODE(void)
Definition: editor.c:7593
static void test_EM_SCROLLCARET(void)
Definition: editor.c:568
static ENLINK enlink
Definition: editor.c:6763
static int get_scroll_pos_y(HWND hwnd)
Definition: editor.c:547
static void test_EM_SETUNDOLIMIT(void)
Definition: editor.c:3606
static CHAR string3[MAX_PATH]
Definition: editor.c:44
static void test_EM_STREAMOUT_empty_para(void)
Definition: editor.c:3996
#define WP_CHILD
Definition: editor.c:6767
static void test_EM_LIMITTEXT(void)
Definition: editor.c:4479
static void test_autoscroll(void)
Definition: editor.c:7358
static void check_EM_FINDTEXTEX(HWND hwnd, const char *name, struct find_s *f, int id, BOOL unicode)
Definition: editor.c:304
static void test_word_wrap(void)
Definition: editor.c:7262
static void test_enter(void)
Definition: editor.c:8333
#define TEST_SETTEXT(a, b)
static void test_EM_FINDWORDBREAK_A(void)
Definition: editor.c:8284
static LONG CALLBACK customWordBreakProc(WCHAR *text, int pos, int bytes, int code)
Definition: editor.c:7083
static void test_reset_default_para_fmt(void)
Definition: editor.c:8484
static void test_window_classes(void)
Definition: editor.c:9025
static DWORD CALLBACK test_WM_SETTEXT_esCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
Definition: editor.c:3698
static LONG twips2points(LONG value)
Definition: editor.c:8535
#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:3828
#define set_textA(hwnd, wm_set_text, txt)
static void test_EM_POSFROMCHAR(void)
Definition: editor.c:626
static DWORD CALLBACK EditStreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
Definition: editor.c:5732
static void test_zoom(void)
Definition: editor.c:7774
static int watchForEventMask
Definition: editor.c:6562
static HWND new_static_wnd(HWND parent)
Definition: editor.c:1966
static DWORD CALLBACK test_EM_STREAMIN_esCallback2(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
Definition: editor.c:5827
static HWND new_window(LPCSTR lpClassName, DWORD dwStyle, HWND parent)
Definition: editor.c:81
static void test_ES_PASSWORD(void)
Definition: editor.c:3670
static const struct getline_s gl[]
static void test_EM_EXLIMITTEXT(void)
Definition: editor.c:4519
static void _test_font_size(unsigned line, HWND hwnd, LONG size, LONG expected_size, LRESULT expected_res, BOOL expected_undo)
Definition: editor.c:8542
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:6778
static BOOL bailedOutOfRecursion
Definition: editor.c:2896
static void test_WM_CHAR(void)
Definition: editor.c:6357
static void test_eop_char_fmt(void)
Definition: editor.c:8833
static void test_word_movement(void)
Definition: editor.c:7120
#define TEST_EM_SETFONTSIZE(hwnd, size, expected_size, expected_res, expected_undo)
Definition: editor.c:8540
static const char haystack[]
Definition: editor.c:174
static void test_para_numbering(void)
Definition: editor.c:8869
#define set_textW(hwnd, wm_set_text, txt)
static void test_EM_GETTEXTRANGE(void)
Definition: editor.c:1746
static void test_alignment_style(void)
Definition: editor.c:8629
static void test_EM_SETTEXTEX(void)
Definition: editor.c:4016
static void disable_beep(HWND hwnd)
Definition: editor.c:63
static void test_WM_NOTIFY(void)
Definition: editor.c:6669
static void test_EM_SETREADONLY(void)
Definition: editor.c:8516
static void test_TM_PLAINTEXT(void)
Definition: editor.c:1569
static void test_EM_GETMODIFY(void)
Definition: editor.c:4747
static IID * pIID_ITextServices
Definition: txtsrv.c:42
static void test_EM_FINDTEXT(void)
Definition: editor.c:779
static const CLSID *static CLSID *static const GUID VARIANT VARIANT *static IServiceProvider DWORD *static HMENU
Definition: ordinal.c:63
WORD vk
Definition: input.c:77
#define min(a, b)
Definition: monoChain.cc:55
unsigned int UINT
Definition: ndis.h:50
#define LOCALE_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
void redraw(int x, int y, int cx, int cy)
Definition: qtewin.cpp:1248
#define WB_MOVEWORDRIGHT
Definition: richedit.h:1002
#define TM_RICHTEXT
Definition: richedit.h:1029
#define GT_DEFAULT
Definition: richedit.h:1036
#define SEL_EMPTY
Definition: richedit.h:822
#define ENM_CHANGE
Definition: richedit.h:468
#define EM_CANREDO
Definition: richedit.h:118
#define EM_SCROLLCARET
Definition: richedit.h:81
#define SEL_OBJECT
Definition: richedit.h:824
#define CFU_UNDERLINEDOUBLE
Definition: richedit.h:430
#define PFA_RIGHT
Definition: richedit.h:922
#define CFM_EFFECTS
Definition: richedit.h:364
#define SFF_SELECTION
Definition: richedit.h:979
#define PFA_CENTER
Definition: richedit.h:923
#define PFE_RTLPARA
Definition: richedit.h:932
#define EM_GETEVENTMASK
Definition: richedit.h:92
#define EM_REDO
Definition: richedit.h:117
#define EM_GETSELTEXT
Definition: richedit.h:95
#define PFN_ARABIC
Definition: richedit.h:906
#define ST_DEFAULT
Definition: richedit.h:1070
struct _charformat CHARFORMATA
#define EM_AUTOURLDETECT
Definition: richedit.h:125
#define CFE_STRIKEOUT
Definition: richedit.h:409
#define SCF_WORD
Definition: richedit.h:236
#define CFE_BOLD
Definition: richedit.h:406
#define EM_FORMATRANGE
Definition: richedit.h:90
#define PFA_LEFT
Definition: richedit.h:921
#define CFE_AUTOCOLOR
Definition: richedit.h:414
#define EM_SETZOOM
Definition: richedit.h:170
#define ENM_LINK
Definition: richedit.h:485
#define EM_STREAMIN
Definition: richedit.h:106
#define ST_SELECTION
Definition: richedit.h:1072
#define EM_SETEVENTMASK
Definition: richedit.h:102
#define EM_SETOPTIONS
Definition: richedit.h:110
#define GTL_DEFAULT
Definition: richedit.h:1054
#define WB_RIGHTBREAK
Definition: richedit.h:1006
static const WCHAR RICHEDIT_CLASS20W[]
Definition: richedit.h:50
#define CFM_WEIGHT
Definition: richedit.h:354
#define ST_KEEPUNDO
Definition: richedit.h:1071
#define SF_RTF
Definition: richedit.h:721
#define CFE_ITALIC
Definition: richedit.h:407
#define SEL_MULTICHAR
Definition: richedit.h:825
#define SCF_SELECTION
Definition: richedit.h:235
#define EM_SETBKGNDCOLOR
Definition: richedit.h:100
#define EM_SETTEXTEX
Definition: richedit.h:131
#define EM_POSFROMCHAR
Definition: richedit.h:77
#define SCF_DEFAULT
Definition: richedit.h:234
#define EM_GETCHARFORMAT
Definition: richedit.h:91
#define CFE_SUPERSCRIPT
Definition: richedit.h:413
#define GTL_NUMCHARS
Definition: richedit.h:1058
struct _charformatw CHARFORMATW
#define ENM_UPDATE
Definition: richedit.h:469
#define SEL_TEXT
Definition: richedit.h:823
#define CFM_SPACING
Definition: richedit.h:353
#define EM_SETCHARFORMAT
Definition: richedit.h:101
#define PFM_ALL2
Definition: richedit.h:892
#define EM_SETFONTSIZE
Definition: richedit.h:168
#define ENM_SELCHANGE
Definition: richedit.h:478
#define EM_GETPARAFORMAT
Definition: richedit.h:94
#define ENM_KEYEVENTS
Definition: richedit.h:475
#define EM_GETOPTIONS
Definition: richedit.h:111
#define RICHEDIT_CLASS20A
Definition: richedit.h:43
#define CFE_UNDERLINE
Definition: richedit.h:408
#define ECO_AUTOHSCROLL
Definition: richedit.h:458
#define EM_CHARFROMPOS
Definition: richedit.h:78
#define CFE_SUBSCRIPT
Definition: richedit.h:412
#define ES_DISABLENOSCROLL
Definition: richedit.h:224
#define CFM_ITALIC
Definition: richedit.h:333
#define EM_GETTEXTRANGE
Definition: richedit.h:108
#define CFU_UNDERLINE
Definition: richedit.h:428
struct _paraformat2 PARAFORMAT2
#define CFE_PROTECTED
Definition: richedit.h:410
#define CFE_LINK
Definition: richedit.h:411
#define CFM_LINK
Definition: richedit.h:337
#define EM_SETTEXTMODE
Definition: richedit.h:123
#define CFM_SIZE
Definition: richedit.h:362
#define EM_FINDTEXTW
Definition: richedit.h:147
#define GT_RAWTEXT
Definition: richedit.h:1039
#define EM_GETZOOM
Definition: richedit.h:169
#define EM_EXSETSEL
Definition: richedit.h:88
#define EM_GETSCROLLPOS
Definition: richedit.h:165
#define GTL_PRECISE
Definition: richedit.h:1056
#define CFM_ALL2
Definition: richedit.h:393
struct _charformat2a CHARFORMAT2A
#define CFM_EFFECTS2
Definition: richedit.h:372
#define EM_EXLIMITTEXT
Definition: richedit.h:86
#define PFM_ALIGNMENT
Definition: richedit.h:841
#define WCH_EMBEDDING
Definition: richedit.h:1024
#define SF_TEXT
Definition: richedit.h:720
#define CFE_AUTOBACKCOLOR
Definition: richedit.h:425
#define EM_SELECTIONTYPE
Definition: richedit.h:99
#define EM_FINDTEXT
Definition: richedit.h:89
#define 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 SF_UNICODE
Definition: richedit.h:724
#define EM_SETTARGETDEVICE
Definition: richedit.h:105
#define SEL_MULTIOBJECT
Definition: richedit.h:826
#define CFM_BOLD
Definition: richedit.h:332
#define EM_GETLIMITTEXT
Definition: richedit.h:74
#define CFM_UNDERLINETYPE
Definition: richedit.h:355
#define EN_LINK
Definition: richedit.h:202
#define ES_SELECTIONBAR
Definition: richedit.h:230
#define GT_USECRLF
Definition: richedit.h:1037
#define CFU_UNDERLINENONE
Definition: richedit.h:427
#define ES_VERTICAL
Definition: richedit.h:229
#define CFM_FACE
Definition: richedit.h:360
#define EM_GETOLEINTERFACE
Definition: richedit.h:93
#define ECO_AUTOVSCROLL
Definition: richedit.h:457
#define WM_NOTIFY
Definition: richedit.h:61
#define PFM_RTLPARA
Definition: richedit.h:856
#define EM_GETTEXTEX
Definition: richedit.h:128
#define GTL_NUMBYTES
Definition: richedit.h:1059
#define EM_SETPARAFORMAT
Definition: richedit.h:104
#define WB_MOVEWORDLEFT
Definition: richedit.h:1000
#define CFM_UNDERLINE
Definition: richedit.h:334
#define EM_EXGETSEL
Definition: richedit.h:85
#define WB_LEFTBREAK
Definition: richedit.h:1004
#define EM_FINDTEXTEX
Definition: richedit.h:112
#define PFNS_PERIOD
Definition: richedit.h:915
#define EM_SETUNDOLIMIT
Definition: richedit.h:116
#define GTL_USECRLF
Definition: richedit.h:1055
#define EM_FINDWORDBREAK
Definition: richedit.h:109
#define ECO_SELECTIONBAR
Definition: richedit.h:463
#define ECOOP_AND
Definition: richedit.h:452
#define CFM_SUPERSCRIPT
Definition: richedit.h:349
#define EM_STREAMOUT
Definition: richedit.h:107
#define test
Definition: rosglue.h:37
const WCHAR * str
#define LANG_ENGLISH
Definition: nls.h:52
#define CP_UTF8
Definition: nls.h:20
#define LANG_JAPANESE
Definition: nls.h:76
#define PRIMARYLANGID(l)
Definition: nls.h:16
#define ros_skip_flaky
Definition: test.h: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
CHAR lfFaceName[LF_FACESIZE]
Definition: dimm.idl:55
char * buffer
Definition: editor.c:5823
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:3173
HICON hIcon
Definition: winuser.h:3171
HINSTANCE hInstance
Definition: winuser.h:3170
HCURSOR hCursor
Definition: winuser.h:3172
int cbWndExtra
Definition: winuser.h:3169
UINT style
Definition: winuser.h:3166
LPCSTR lpszMenuName
Definition: winuser.h:3174
LPCSTR lpszClassName
Definition: winuser.h:3175
WNDPROC lpfnWndProc
Definition: winuser.h:3167
int cbClsExtra
Definition: winuser.h:3168
DWORD dwMask
Definition: richedit.h:283
BYTE bRevAuthor
Definition: richedit.h:300
LONG yHeight
Definition: richedit.h:285
BYTE bUnderlineType
Definition: richedit.h:298
char szFaceName[LF_FACESIZE]
Definition: richedit.h:290
SHORT sSpacing
Definition: richedit.h:292
LONG yOffset
Definition: richedit.h:286
SHORT sStyle
Definition: richedit.h:296
WORD wKerning
Definition: richedit.h:297
DWORD dwEffects
Definition: richedit.h:284
BYTE bAnimation
Definition: richedit.h:299
WORD wWeight
Definition: richedit.h:291
DWORD dwMask
Definition: richedit.h:306
WORD wWeight
Definition: richedit.h:314
SHORT sSpacing
Definition: richedit.h:315
UINT cbSize
Definition: richedit.h:255
DWORD dwEffects
Definition: richedit.h:257
DWORD dwMask
Definition: richedit.h:256
UINT cbSize
Definition: richedit.h:268
DWORD dwMask
Definition: richedit.h:269
DWORD dwEffects
Definition: richedit.h:270
LONG cpMax
Definition: richedit.h:501
LONG cpMin
Definition: richedit.h:500
CHARRANGE chrg
Definition: richedit.h:581
LPCSTR lpstrText
Definition: richedit.h:582
CHARRANGE chrg
Definition: richedit.h:586
LPCWSTR lpstrText
Definition: richedit.h:587
LPCSTR lpstrText
Definition: richedit.h:594
CHARRANGE chrg
Definition: richedit.h:593
CHARRANGE chrgText
Definition: richedit.h:595
CHARRANGE chrg
Definition: richedit.h:599
CHARRANGE chrgText
Definition: richedit.h:601
LPCWSTR lpstrText
Definition: richedit.h:600
HDC hdcTarget
Definition: richedit.h:608
CHARRANGE chrg
Definition: richedit.h:611
RECT rcPage
Definition: richedit.h:610
DWORD cb
Definition: richedit.h:706
DWORD flags
Definition: richedit.h:707
LPCSTR lpDefaultChar
Definition: richedit.h:709
LPBOOL lpUsedDefChar
Definition: richedit.h:710
UINT codepage
Definition: richedit.h:708
WORD wAlignment
Definition: richedit.h:673
DWORD dwMask
Definition: richedit.h:667
UINT cbSize
Definition: richedit.h:666
DWORD dwUser
Definition: richole.idl:67
CLSID clsid
Definition: richole.idl:60
DWORD dwFlags
Definition: richole.idl:66
LPSTORAGE pstg
Definition: richole.idl:62
LPOLEOBJECT poleobj
Definition: richole.idl:61
DWORD dvaspect
Definition: richole.idl:65
LPOLECLIENTSITE polesite
Definition: richole.idl:63
DWORD cbStruct
Definition: richole.idl:58
LONG cp
Definition: richole.idl:59
SIZEL sizel
Definition: richole.idl:64
UINT codepage
Definition: richedit.h:1066
DWORD flags
Definition: richedit.h:1065
CHARRANGE chrg
Definition: richedit.h:508
LPSTR lpstrText
Definition: richedit.h:509
Definition: ftp_var.h:139
Definition: inflate.c:139
Definition: cookie.c:34
Definition: query.h:86
LRESULT expected_retval
Definition: editor.c:4915
LONG max
Definition: editor.c:4914
BOOL todo
Definition: editor.c:4918
int expected_getsel_end
Definition: editor.c:4917
LONG min
Definition: editor.c:4913
int expected_getsel_start
Definition: editor.c:4916
Definition: editor.c:177
int flags
Definition: editor.c:181
int start
Definition: editor.c:178
int end
Definition: editor.c:179
int expected_loc
Definition: editor.c:182
const char * needle
Definition: editor.c:180
Definition: dsound.c:943
size_t buffer_len
Definition: editor.c:405
int line
Definition: editor.c:404
const char * text
Definition: editor.c:406
Definition: copy.c:22
Definition: parser.c:49
Definition: tftpd.h:60
Definition: name.c:39
DWORD lsUsb[4]
Definition: wingdi.h:2611
UINT_PTR idFrom
Definition: winuser.h:3161
HWND hwndFrom
Definition: winuser.h:3160
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:1312
#define success(from, fromstr, to, tostr)
#define ZeroMemory
Definition: winbase.h:1737
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
LONG_PTR LPARAM
Definition: windef.h:208
LONG_PTR LRESULT
Definition: windef.h:209
UINT_PTR WPARAM
Definition: windef.h:207
#define WINAPI
Definition: msvc.h:6
#define E_UNEXPECTED
Definition: winerror.h:2456
#define ERROR_CANNOT_FIND_WND_CLASS
Definition: winerror.h:888
#define DEFAULT_PITCH
Definition: wingdi.h:443
#define FW_LIGHT
Definition: wingdi.h:372
HGDIOBJ WINAPI GetStockObject(_In_ int)
#define FW_DONTCARE
Definition: wingdi.h:368
int WINAPI GetDeviceCaps(_In_opt_ HDC, _In_ int)
int WINAPI GetObjectA(_In_ HANDLE h, _In_ int c, _Out_writes_bytes_opt_(c) LPVOID pv)
#define DEFAULT_QUALITY
Definition: wingdi.h:436
#define FF_DONTCARE
Definition: wingdi.h:448
#define LOGPIXELSY
Definition: wingdi.h:719
#define WHITE_BRUSH
Definition: wingdi.h:902
#define OUT_DEFAULT_PRECIS
Definition: wingdi.h:415
#define ANSI_CHARSET
Definition: wingdi.h:383
#define OUT_TT_PRECIS
Definition: wingdi.h:419
#define CLIP_DEFAULT_PRECIS
Definition: wingdi.h:426
#define LOGPIXELSX
Definition: wingdi.h:718
HFONT WINAPI CreateFontA(_In_ int, _In_ int, _In_ int, _In_ int, _In_ int, _In_ DWORD, _In_ DWORD, _In_ DWORD, _In_ DWORD, _In_ DWORD, _In_ DWORD, _In_ DWORD, _In_ DWORD, _In_opt_ LPCSTR)
BOOL WINAPI GetTextExtentPoint32A(_In_ HDC hdc, _In_reads_(c) LPCSTR lpString, _In_ int c, _Out_ LPSIZE psizl)
#define LOCALE_FONTSIGNATURE
Definition: winnls.h:127
#define EM_SETREADONLY
Definition: winuser.h:2018
int WINAPI ReleaseDC(_In_opt_ HWND, _In_ HDC)
LRESULT WINAPI DispatchMessageA(_In_ const MSG *)
#define MAKEWPARAM(l, h)
Definition: winuser.h:4012
#define SetWindowLongPtrA
Definition: winuser.h:5357
#define WM_GETTEXTLENGTH
Definition: winuser.h:1622
#define EM_GETRECT
Definition: winuser.h:1999
#define WM_CLOSE
Definition: winuser.h:1624
#define EM_LIMITTEXT
Definition: winuser.h:2003
#define VK_TAB
Definition: winuser.h:2202
UINT WINAPI MapVirtualKeyA(_In_ UINT, _In_ UINT)
#define SB_LINEUP
Definition: winuser.h:564
#define WM_HSCROLL
Definition: winuser.h:1746
BOOL WINAPI SetKeyboardState(_In_reads_(256) LPBYTE)
#define WM_PASTE
Definition: winuser.h:1866
BOOL WINAPI TranslateMessage(_In_ const MSG *)
#define MAKELPARAM(l, h)
Definition: winuser.h:4011
#define WM_KEYUP
Definition: winuser.h:1719
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:1998
LONG WINAPI GetWindowLongA(_In_ HWND, _In_ int)
LRESULT WINAPI DefWindowProcA(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define WM_VSCROLL
Definition: winuser.h:1747
#define CreateWindowA(a, b, c, d, e, f, g, h, i, j, k)
Definition: winuser.h:4318
LONG WINAPI SetWindowLongA(_In_ HWND, _In_ int, _In_ LONG)
#define SIF_RANGE
Definition: winuser.h:1238
#define DLGC_WANTCHARS
Definition: winuser.h:2621
#define DLGC_WANTTAB
Definition: winuser.h:2614
#define EM_GETSEL
Definition: winuser.h:2000
#define EM_SETPASSWORDCHAR
Definition: winuser.h:2017
#define EN_UPDATE
Definition: winuser.h:2031
#define EM_GETMODIFY
Definition: winuser.h:1997
#define WB_ISDELIMITER
Definition: winuser.h:549
HWND WINAPI SetParent(_In_ HWND, _In_opt_ HWND)
#define WM_SIZE
Definition: winuser.h:1614
#define SB_VERT
Definition: winuser.h:553
#define EM_EMPTYUNDOBUFFER
Definition: winuser.h:1988
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:1781
BOOL WINAPI ValidateRect(_In_opt_ HWND, _In_opt_ LPCRECT)
#define WM_COMMAND
Definition: winuser.h:1743
#define EM_REPLACESEL
Definition: winuser.h:2009
#define IDC_ARROW
Definition: winuser.h:687
#define VK_CONTROL
Definition: winuser.h:2206
BOOL WINAPI GetCursorPos(_Out_ LPPOINT)
Definition: cursoricon.c:2756
#define EM_SETRECT
Definition: winuser.h:2019
#define WM_RBUTTONUP
Definition: winuser.h:1783
#define DC_HASDEFID
Definition: winuser.h:2612
#define WM_RBUTTONDBLCLK
Definition: winuser.h:1784
LRESULT WINAPI SendMessageA(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define WM_SETFOCUS
Definition: winuser.h:1616
#define SIF_PAGE
Definition: winuser.h:1236
#define WM_MOUSEMOVE
Definition: winuser.h:1778
#define WM_GETTEXT
Definition: winuser.h:1621
_Check_return_ BOOL WINAPI GetKeyboardState(_Out_writes_(256) PBYTE lpKeyState)
#define WM_CUT
Definition: winuser.h:1864
#define SB_LINERIGHT
Definition: winuser.h:567
#define WM_LBUTTONDOWN
Definition: winuser.h:1779
BOOL WINAPI SetCursorPos(_In_ int, _In_ int)
Definition: cursoricon.c:2748
#define EM_LINESCROLL
Definition: winuser.h:2007
#define EM_GETFIRSTVISIBLELINE
Definition: winuser.h:1991
BOOL WINAPI ClientToScreen(_In_ HWND, _Inout_ LPPOINT)
#define WM_NEXTDLGCTL
Definition: winuser.h:1646
#define WM_UNDO
Definition: winuser.h:1868
#define WM_RBUTTONDOWN
Definition: winuser.h:1782
#define WM_SETTEXT
Definition: winuser.h:1620
#define EM_CANUNDO
Definition: winuser.h:1986
#define EM_LINELENGTH
Definition: winuser.h:2006
BOOL WINAPI IsWindowUnicode(_In_ HWND)
BOOL WINAPI GetClientRect(_In_ HWND, _Out_ LPRECT)
ATOM WINAPI RegisterClassA(_In_ CONST WNDCLASSA *)
#define VK_RETURN
Definition: winuser.h:2204
#define EM_GETLINE
Definition: winuser.h:1994
#define SB_LINELEFT
Definition: winuser.h:566
#define MK_CONTROL
Definition: winuser.h:2373
#define WB_LEFT
Definition: winuser.h:550
#define GWLP_HWNDPARENT
Definition: winuser.h:861
#define WM_SETFONT
Definition: winuser.h:1653
#define EM_UNDO
Definition: winuser.h:2024
#define DLGC_WANTARROWS
Definition: winuser.h:2613
#define EM_SCROLL
Definition: winuser.h:2010
#define PM_REMOVE
Definition: winuser.h:1199
#define SB_PAGEDOWN
Definition: winuser.h:569
#define EM_SETWORDBREAKPROC
Definition: winuser.h:2023
#define SIF_ALL
Definition: winuser.h:1235
#define VK_BACK
Definition: winuser.h:2201
HDC WINAPI GetDC(_In_opt_ HWND)
#define SB_LINEDOWN
Definition: winuser.h:565
#define EM_SETSEL
Definition: winuser.h:2021
#define CreateWindowW(a, b, c, d, e, f, g, h, i, j, k)
Definition: winuser.h:4319
BOOL WINAPI GetClassInfoA(_In_opt_ HINSTANCE, _In_ LPCSTR, _Out_ LPWNDCLASSA)
#define WM_LBUTTONUP
Definition: winuser.h:1780
#define WB_RIGHT
Definition: winuser.h:551
#define WM_CHAR
Definition: winuser.h:1720
#define CW_USEDEFAULT
Definition: winuser.h:225
#define VK_LEFT
Definition: winuser.h:2227
#define VK_RIGHT
Definition: winuser.h:2229
#define WM_COPY
Definition: winuser.h:1865
#define WM_SETCURSOR
Definition: winuser.h:1639
BOOL WINAPI PeekMessageA(_Out_ LPMSG, _In_opt_ HWND, _In_ UINT, _In_ UINT, _In_ UINT)
#define DLGC_WANTMESSAGE
Definition: winuser.h:2616
#define VK_DELETE
Definition: winuser.h:2236
#define MAPVK_VK_TO_VSC
Definition: winuser.h:2358
#define WS_EX_CLIENTEDGE
Definition: winuser.h:384
#define WM_CLEAR
Definition: winuser.h:1867
BOOL WINAPI ShowScrollBar(_In_ HWND, _In_ int, _In_ BOOL)
#define WM_KEYDOWN
Definition: winuser.h:1718
#define EM_GETLINECOUNT
Definition: winuser.h:1995
#define DM_GETDEFID
Definition: winuser.h:2101
BOOL WINAPI InflateRect(_Inout_ LPRECT, _In_ int, _In_ int)
#define GWL_STYLE
Definition: winuser.h:855
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:2217
#define DLGC_HASSETSEL
Definition: winuser.h:2617
BOOL WINAPI IsWindowVisible(_In_ HWND)
BOOL WINAPI DestroyWindow(_In_ HWND)
#define WM_KILLFOCUS
Definition: winuser.h:1617
BOOL WINAPI EqualRect(_In_ LPCRECT, _In_ LPCRECT)
#define SB_PAGEUP
Definition: winuser.h:568
BOOL WINAPI MoveWindow(_In_ HWND, _In_ int, _In_ int, _In_ int, _In_ int, _In_ BOOL)
#define WM_GETDLGCODE
Definition: winuser.h:1692
#define EM_SETMODIFY
Definition: winuser.h:2016
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
HCURSOR WINAPI LoadCursorA(_In_opt_ HINSTANCE, _In_ LPCSTR)
Definition: cursoricon.c:2176
#define EN_CHANGE
Definition: winuser.h:2025
#define WM_SETREDRAW
Definition: winuser.h:1619
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