qedit/tests: Add test framework and test for IMediaDet_put_Filename.
[wine] / dlls / riched20 / tests / editor.c
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 #include <stdarg.h>
24 #include <assert.h>
25 #include <windef.h>
26 #include <winbase.h>
27 #include <wingdi.h>
28 #include <winuser.h>
29 #include <winnls.h>
30 #include <ole2.h>
31 #include <richedit.h>
32 #include <time.h>
33 #include <wine/test.h>
34
35 static HMODULE hmoduleRichEdit;
36
37 static HWND new_window(LPCTSTR lpClassName, DWORD dwStyle, HWND parent) {
38   HWND hwnd;
39   hwnd = CreateWindow(lpClassName, NULL, dwStyle|WS_POPUP|WS_HSCROLL|WS_VSCROLL
40                       |WS_VISIBLE, 0, 0, 200, 60, parent, NULL,
41                       hmoduleRichEdit, NULL);
42   ok(hwnd != NULL, "class: %s, error: %d\n", lpClassName, (int) GetLastError());
43   return hwnd;
44 }
45
46 static HWND new_richedit(HWND parent) {
47   return new_window(RICHEDIT_CLASS, ES_MULTILINE, parent);
48 }
49
50 static const char haystack[] = "WINEWine wineWine wine WineWine";
51                              /* ^0        ^10       ^20       ^30 */
52
53 struct find_s {
54   int start;
55   int end;
56   const char *needle;
57   int flags;
58   int expected_loc;
59   int _todo_wine;
60 };
61
62
63 struct find_s find_tests[] = {
64   /* Find in empty text */
65   {0, -1, "foo", FR_DOWN, -1, 0},
66   {0, -1, "foo", 0, -1, 0},
67   {0, -1, "", FR_DOWN, -1, 0},
68   {20, 5, "foo", FR_DOWN, -1, 0},
69   {5, 20, "foo", FR_DOWN, -1, 0}
70 };
71
72 struct find_s find_tests2[] = {
73   /* No-result find */
74   {0, -1, "foo", FR_DOWN | FR_MATCHCASE, -1, 0},
75   {5, 20, "WINE", FR_DOWN | FR_MATCHCASE, -1, 0},
76
77   /* Subsequent finds */
78   {0, -1, "Wine", FR_DOWN | FR_MATCHCASE, 4, 0},
79   {5, 31, "Wine", FR_DOWN | FR_MATCHCASE, 13, 0},
80   {14, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23, 0},
81   {24, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0},
82
83   /* Find backwards */
84   {19, 20, "Wine", FR_MATCHCASE, 13, 0},
85   {10, 20, "Wine", FR_MATCHCASE, 4, 0},
86   {20, 10, "Wine", FR_MATCHCASE, 13, 0},
87
88   /* Case-insensitive */
89   {1, 31, "wInE", FR_DOWN, 4, 0},
90   {1, 31, "Wine", FR_DOWN, 4, 0},
91
92   /* High-to-low ranges */
93   {20, 5, "Wine", FR_DOWN, -1, 0},
94   {2, 1, "Wine", FR_DOWN, -1, 0},
95   {30, 29, "Wine", FR_DOWN, -1, 0},
96   {20, 5, "Wine", 0, 13, 0},
97
98   /* Find nothing */
99   {5, 10, "", FR_DOWN, -1, 0},
100   {10, 5, "", FR_DOWN, -1, 0},
101   {0, -1, "", FR_DOWN, -1, 0},
102   {10, 5, "", 0, -1, 0},
103
104   /* Whole-word search */
105   {0, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18, 0},
106   {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1, 0},
107   {13, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18, 0},
108   {0, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 0, 0},
109   {10, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 23, 0},
110   {11, -1, "winewine", FR_WHOLEWORD, 0, 0},
111   {31, -1, "winewine", FR_WHOLEWORD, 23, 0},
112   
113   /* Bad ranges */
114   {5, 200, "XXX", FR_DOWN, -1, 0},
115   {-20, 20, "Wine", FR_DOWN, -1, 0},
116   {-20, 20, "Wine", FR_DOWN, -1, 0},
117   {-15, -20, "Wine", FR_DOWN, -1, 0},
118   {1<<12, 1<<13, "Wine", FR_DOWN, -1, 0},
119
120   /* Check the case noted in bug 4479 where matches at end aren't recognized */
121   {23, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23, 0},
122   {27, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0},
123   {27, 32, "Wine", FR_DOWN | FR_MATCHCASE, 27, 0},
124   {13, 31, "WineWine", FR_DOWN | FR_MATCHCASE, 23, 0},
125   {13, 32, "WineWine", FR_DOWN | FR_MATCHCASE, 23, 0},
126
127   /* The backwards case of bug 4479; bounds look right
128    * Fails because backward find is wrong */
129   {19, 20, "WINE", FR_MATCHCASE, 0, 0},
130   {0, 20, "WINE", FR_MATCHCASE, -1, 0}
131 };
132
133 static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id) {
134   int findloc;
135   FINDTEXT ft;
136   memset(&ft, 0, sizeof(ft));
137   ft.chrg.cpMin = f->start;
138   ft.chrg.cpMax = f->end;
139   ft.lpstrText = f->needle;
140   findloc = SendMessage(hwnd, EM_FINDTEXT, f->flags, (LPARAM) &ft);
141   ok(findloc == f->expected_loc,
142      "EM_FINDTEXT(%s,%d) '%s' in range(%d,%d), flags %08x, got start at %d\n",
143      name, id, f->needle, f->start, f->end, f->flags, findloc);
144 }
145
146 static void check_EM_FINDTEXTEX(HWND hwnd, const char *name, struct find_s *f,
147     int id) {
148   int findloc;
149   FINDTEXTEX ft;
150   memset(&ft, 0, sizeof(ft));
151   ft.chrg.cpMin = f->start;
152   ft.chrg.cpMax = f->end;
153   ft.lpstrText = f->needle;
154   findloc = SendMessage(hwnd, EM_FINDTEXTEX, f->flags, (LPARAM) &ft);
155   ok(findloc == f->expected_loc,
156       "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
157       name, id, f->needle, f->start, f->end, f->flags, findloc);
158   ok(ft.chrgText.cpMin == f->expected_loc,
159       "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
160       name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMin);
161   ok(ft.chrgText.cpMax == ((f->expected_loc == -1) ? -1
162         : f->expected_loc + strlen(f->needle)),
163       "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d\n",
164       name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMax);
165 }
166
167 static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *find,
168     int num_tests)
169 {
170   int i;
171
172   for (i = 0; i < num_tests; i++) {
173     if (find[i]._todo_wine) {
174       todo_wine {
175         check_EM_FINDTEXT(hwnd, name, &find[i], i);
176         check_EM_FINDTEXTEX(hwnd, name, &find[i], i);
177       }
178     } else {
179         check_EM_FINDTEXT(hwnd, name, &find[i], i);
180         check_EM_FINDTEXTEX(hwnd, name, &find[i], i);
181     }
182   }
183 }
184
185 static void test_EM_FINDTEXT(void)
186 {
187   HWND hwndRichEdit = new_richedit(NULL);
188
189   /* Empty rich edit control */
190   run_tests_EM_FINDTEXT(hwndRichEdit, "1", find_tests,
191       sizeof(find_tests)/sizeof(struct find_s));
192
193   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) haystack);
194
195   /* Haystack text */
196   run_tests_EM_FINDTEXT(hwndRichEdit, "2", find_tests2,
197       sizeof(find_tests2)/sizeof(struct find_s));
198
199   DestroyWindow(hwndRichEdit);
200 }
201
202 static const struct getline_s {
203   int line;
204   size_t buffer_len;
205   const char *text;
206 } gl[] = {
207   {0, 10, "foo bar\r"},
208   {1, 10, "\r"},
209   {2, 10, "bar\r"},
210   {3, 10, "\r"},
211
212   /* Buffer smaller than line length */
213   {0, 2, "foo bar\r"},
214   {0, 1, "foo bar\r"},
215   {0, 0, "foo bar\r"}
216 };
217
218 static void test_EM_GETLINE(void)
219 {
220   int i;
221   HWND hwndRichEdit = new_richedit(NULL);
222   static const int nBuf = 1024;
223   char dest[1024], origdest[1024];
224   const char text[] = "foo bar\n"
225       "\n"
226       "bar\n";
227
228   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
229
230   memset(origdest, 0xBB, nBuf);
231   for (i = 0; i < sizeof(gl)/sizeof(struct getline_s); i++)
232   {
233     int nCopied;
234     int expected_nCopied = min(gl[i].buffer_len, strlen(gl[i].text));
235     int expected_bytes_written = min(gl[i].buffer_len, strlen(gl[i].text) + 1);
236     memset(dest, 0xBB, nBuf);
237     *(WORD *) dest = gl[i].buffer_len;
238
239     /* EM_GETLINE appends a "\r\0" to the end of the line
240      * nCopied counts up to and including the '\r' */
241     nCopied = SendMessage(hwndRichEdit, EM_GETLINE, gl[i].line, (LPARAM) dest);
242     ok(nCopied == expected_nCopied, "%d: %d!=%d\n", i, nCopied,
243        expected_nCopied);
244     /* two special cases since a parameter is passed via dest */
245     if (gl[i].buffer_len == 0)
246       ok(!dest[0] && !dest[1] && !strncmp(dest+2, origdest+2, nBuf-2),
247          "buffer_len=0\n");
248     else if (gl[i].buffer_len == 1)
249       ok(dest[0] == gl[i].text[0] && !dest[1] &&
250          !strncmp(dest+2, origdest+2, nBuf-2), "buffer_len=1\n");
251     else
252     {
253       ok(!strncmp(dest, gl[i].text, expected_bytes_written),
254          "%d: expected_bytes_written=%d\n", i, expected_bytes_written);
255       ok(!strncmp(dest + expected_bytes_written, origdest
256                   + expected_bytes_written, nBuf - expected_bytes_written),
257          "%d: expected_bytes_written=%d\n", i, expected_bytes_written);
258     }
259   }
260
261   DestroyWindow(hwndRichEdit);
262 }
263
264 static int get_scroll_pos_y(HWND hwnd)
265 {
266   POINT p = {-1, -1};
267   SendMessage(hwnd, EM_GETSCROLLPOS, 0, (LPARAM) &p);
268   ok(p.x != -1 && p.y != -1, "p.x:%d p.y:%d\n", p.x, p.y);
269   return p.y;
270 }
271
272 static void move_cursor(HWND hwnd, long charindex)
273 {
274   CHARRANGE cr;
275   cr.cpMax = charindex;
276   cr.cpMin = charindex;
277   SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &cr);
278 }
279
280 static void line_scroll(HWND hwnd, int amount)
281 {
282   SendMessage(hwnd, EM_LINESCROLL, 0, amount);
283 }
284
285 static void test_EM_SCROLLCARET(void)
286 {
287   int prevY, curY;
288   HWND hwndRichEdit = new_richedit(NULL);
289   const char text[] = "aa\n"
290       "this is a long line of text that should be longer than the "
291       "control's width\n"
292       "cc\n"
293       "dd\n"
294       "ee\n"
295       "ff\n"
296       "gg\n"
297       "hh\n";
298
299   /* Can't verify this */
300   SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
301
302   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
303
304   /* Caret above visible window */
305   line_scroll(hwndRichEdit, 3);
306   prevY = get_scroll_pos_y(hwndRichEdit);
307   SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
308   curY = get_scroll_pos_y(hwndRichEdit);
309   ok(prevY != curY, "%d == %d\n", prevY, curY);
310
311   /* Caret below visible window */
312   move_cursor(hwndRichEdit, sizeof(text) - 1);
313   line_scroll(hwndRichEdit, -3);
314   prevY = get_scroll_pos_y(hwndRichEdit);
315   SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
316   curY = get_scroll_pos_y(hwndRichEdit);
317   ok(prevY != curY, "%d == %d\n", prevY, curY);
318
319   /* Caret in visible window */
320   move_cursor(hwndRichEdit, sizeof(text) - 2);
321   prevY = get_scroll_pos_y(hwndRichEdit);
322   SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
323   curY = get_scroll_pos_y(hwndRichEdit);
324   ok(prevY == curY, "%d != %d\n", prevY, curY);
325
326   /* Caret still in visible window */
327   line_scroll(hwndRichEdit, -1);
328   prevY = get_scroll_pos_y(hwndRichEdit);
329   SendMessage(hwndRichEdit, EM_SCROLLCARET, 0, 0);
330   curY = get_scroll_pos_y(hwndRichEdit);
331   ok(prevY == curY, "%d != %d\n", prevY, curY);
332
333   DestroyWindow(hwndRichEdit);
334 }
335
336 static void test_EM_SETCHARFORMAT(void)
337 {
338   HWND hwndRichEdit = new_richedit(NULL);
339   CHARFORMAT2 cf2;
340   int rc = 0;
341
342   /* Invalid flags, CHARFORMAT2 structure blanked out */
343   memset(&cf2, 0, sizeof(cf2));
344   rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) 0xfffffff0,
345              (LPARAM) &cf2);
346   ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
347
348   /* A valid flag, CHARFORMAT2 structure blanked out */
349   memset(&cf2, 0, sizeof(cf2));
350   rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_DEFAULT,
351              (LPARAM) &cf2);
352   ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
353
354   /* A valid flag, CHARFORMAT2 structure blanked out */
355   memset(&cf2, 0, sizeof(cf2));
356   rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION,
357              (LPARAM) &cf2);
358   ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
359
360   /* A valid flag, CHARFORMAT2 structure blanked out */
361   memset(&cf2, 0, sizeof(cf2));
362   rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_WORD,
363              (LPARAM) &cf2);
364   ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
365
366   /* A valid flag, CHARFORMAT2 structure blanked out */
367   memset(&cf2, 0, sizeof(cf2));
368   rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL,
369              (LPARAM) &cf2);
370   ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
371
372   /* Invalid flags, CHARFORMAT2 structure minimally filled */
373   memset(&cf2, 0, sizeof(cf2));
374   cf2.cbSize = sizeof(CHARFORMAT2);
375   rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) 0xfffffff0,
376              (LPARAM) &cf2);
377   ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
378
379   /* A valid flag, CHARFORMAT2 structure minimally filled */
380   memset(&cf2, 0, sizeof(cf2));
381   cf2.cbSize = sizeof(CHARFORMAT2);
382   rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_DEFAULT,
383              (LPARAM) &cf2);
384   ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
385
386   /* A valid flag, CHARFORMAT2 structure minimally filled */
387   memset(&cf2, 0, sizeof(cf2));
388   cf2.cbSize = sizeof(CHARFORMAT2);
389   rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION,
390              (LPARAM) &cf2);
391   ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
392
393   /* A valid flag, CHARFORMAT2 structure minimally filled */
394   memset(&cf2, 0, sizeof(cf2));
395   cf2.cbSize = sizeof(CHARFORMAT2);
396   rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_WORD,
397              (LPARAM) &cf2);
398   ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
399
400   /* A valid flag, CHARFORMAT2 structure minimally filled */
401   memset(&cf2, 0, sizeof(cf2));
402   cf2.cbSize = sizeof(CHARFORMAT2);
403   rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL,
404              (LPARAM) &cf2);
405   ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
406
407   DestroyWindow(hwndRichEdit);
408 }
409
410 static void test_EM_SETTEXTMODE(void)
411 {
412   HWND hwndRichEdit = new_richedit(NULL);
413   CHARFORMAT2 cf2, cf2test;
414   CHARRANGE cr;
415   int rc = 0;
416
417   /*Test that EM_SETTEXTMODE fails if text exists within the control*/
418   /*Insert text into the control*/
419
420   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
421
422   /*Attempt to change the control to plain text mode*/
423   rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_PLAINTEXT, 0);
424   ok(rc != 0, "EM_SETTEXTMODE: changed text mode in control containing text - returned: %d\n", rc);
425
426   /*Test that EM_SETTEXTMODE does not allow rich edit text to be pasted.
427   If rich text is pasted, it should have the same formatting as the rest
428   of the text in the control*/
429
430   /*Italicize the text
431   *NOTE: If the default text was already italicized, the test will simply
432   reverse; in other words, it will copy a regular "wine" into a plain
433   text window that uses an italicized format*/
434   cf2.cbSize = sizeof(CHARFORMAT2);
435   SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
436              (LPARAM) &cf2);
437
438   cf2.dwMask = CFM_ITALIC | cf2.dwMask;
439   cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
440
441   /*EM_SETCHARFORMAT is not yet fully implemented for all WPARAMs in wine;
442   however, SCF_ALL has been implemented*/
443   rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
444   ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
445   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
446
447   /*Select the string "wine"*/
448   cr.cpMin = 0;
449   cr.cpMax = 4;
450   SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
451
452   /*Copy the italicized "wine" to the clipboard*/
453   SendMessage(hwndRichEdit, WM_COPY, 0, 0);
454
455   /*Reset the formatting to default*/
456   cf2.dwEffects = CFE_ITALIC^cf2.dwEffects;
457   rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
458   ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
459
460   /*Clear the text in the control*/
461   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
462
463   /*Switch to Plain Text Mode*/
464   rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_PLAINTEXT, 0);
465   ok(rc == 0, "EM_SETTEXTMODE: unable to switch to plain text mode with empty control:  returned: %d\n", rc);
466
467   /*Input "wine" again in normal format*/
468   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
469
470   /*Paste the italicized "wine" into the control*/
471   SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
472
473   /*Select a character from the first "wine" string*/
474   cr.cpMin = 2;
475   cr.cpMax = 3;
476   SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
477
478   /*Retrieve its formatting*/
479   SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
480               (LPARAM) &cf2);
481
482   /*Select a character from the second "wine" string*/
483   cr.cpMin = 5;
484   cr.cpMax = 6;
485   SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
486
487   /*Retrieve its formatting*/
488   cf2test.cbSize = sizeof(CHARFORMAT2);
489   SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
490                (LPARAM) &cf2test);
491
492   /*Compare the two formattings*/
493     ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
494       "two formats found in plain text mode - cf2.dwEffects: %x cf2test.dwEffects: %x\n",
495        cf2.dwEffects, cf2test.dwEffects);
496   /*Test TM_RICHTEXT by: switching back to Rich Text mode
497                          printing "wine" in the current format(normal)
498                          pasting "wine" from the clipboard(italicized)
499                          comparing the two formats(should differ)*/
500
501   /*Attempt to switch with text in control*/
502   rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
503   ok(rc != 0, "EM_SETTEXTMODE: changed from plain text to rich text with text in control - returned: %d\n", rc);
504
505   /*Clear control*/
506   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
507
508   /*Switch into Rich Text mode*/
509   rc = SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
510   ok(rc == 0, "EM_SETTEXTMODE: unable to change to rich text with empty control - returned: %d\n", rc);
511
512   /*Print "wine" in normal formatting into the control*/
513   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
514
515   /*Paste italicized "wine" into the control*/
516   SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
517
518   /*Select text from the first "wine" string*/
519   cr.cpMin = 1;
520   cr.cpMax = 3;
521   SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
522
523   /*Retrieve its formatting*/
524   SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
525                 (LPARAM) &cf2);
526
527   /*Select text from the second "wine" string*/
528   cr.cpMin = 6;
529   cr.cpMax = 7;
530   SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
531
532   /*Retrieve its formatting*/
533   SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION,
534                 (LPARAM) &cf2test);
535
536   /*Test that the two formattings are not the same*/
537   todo_wine ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects != cf2test.dwEffects),
538       "expected different formats - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
539       cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
540
541   DestroyWindow(hwndRichEdit);
542 }
543
544 static void test_TM_PLAINTEXT(void)
545 {
546   /*Tests plain text properties*/
547
548   HWND hwndRichEdit = new_richedit(NULL);
549   CHARFORMAT2 cf2, cf2test;
550   CHARRANGE cr;
551   int rc = 0;
552
553   /*Switch to plain text mode*/
554
555   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
556   SendMessage(hwndRichEdit, EM_SETTEXTMODE, TM_PLAINTEXT, 0);
557
558   /*Fill control with text*/
559
560   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "Is Wine an emulator? No it's not");
561
562   /*Select some text and bold it*/
563
564   cr.cpMin = 10;
565   cr.cpMax = 20;
566   SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
567   cf2.cbSize = sizeof(CHARFORMAT2);
568   SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
569               (LPARAM) &cf2);
570
571   cf2.dwMask = CFM_BOLD | cf2.dwMask;
572   cf2.dwEffects = CFE_BOLD ^ cf2.dwEffects;
573
574   rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
575   ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
576
577   rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_WORD | SCF_SELECTION, (LPARAM) &cf2);
578   ok(rc == 0, "EM_SETCHARFORMAT returned %d instead of 0\n", rc);
579
580   rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM)&cf2);
581   ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
582
583   /*Get the formatting of those characters*/
584
585   SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
586
587   /*Get the formatting of some other characters*/
588   cf2test.cbSize = sizeof(CHARFORMAT2);
589   cr.cpMin = 21;
590   cr.cpMax = 30;
591   SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
592   SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2test);
593
594   /*Test that they are the same as plain text allows only one formatting*/
595
596   ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
597      "two selections' formats differ - cf2.dwMask: %x, cf2test.dwMask %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
598      cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
599   
600   /*Fill the control with a "wine" string, which when inserted will be bold*/
601
602   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
603
604   /*Copy the bolded "wine" string*/
605
606   cr.cpMin = 0;
607   cr.cpMax = 4;
608   SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
609   SendMessage(hwndRichEdit, WM_COPY, 0, 0);
610
611   /*Swap back to rich text*/
612
613   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "");
614   SendMessage(hwndRichEdit, EM_SETTEXTMODE, (WPARAM) TM_RICHTEXT, 0);
615
616   /*Set the default formatting to bold italics*/
617
618   SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT, (LPARAM) &cf2);
619   cf2.dwMask |= CFM_ITALIC;
620   cf2.dwEffects ^= CFE_ITALIC;
621   rc = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
622   ok(rc == 1, "EM_SETCHARFORMAT returned %d instead of 1\n", rc);
623
624   /*Set the text in the control to "wine", which will be bold and italicized*/
625
626   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "wine");
627
628   /*Paste the plain text "wine" string, which should take the insert
629    formatting, which at the moment is bold italics*/
630
631   SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
632
633   /*Select the first "wine" string and retrieve its formatting*/
634
635   cr.cpMin = 1;
636   cr.cpMax = 3;
637   SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
638   SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2);
639
640   /*Select the second "wine" string and retrieve its formatting*/
641
642   cr.cpMin = 5;
643   cr.cpMax = 7;
644   SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
645   SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &cf2test);
646
647   /*Compare the two formattings. They should be the same.*/
648
649   ok((cf2.dwMask == cf2test.dwMask) && (cf2.dwEffects == cf2test.dwEffects),
650      "Copied text retained formatting - cf2.dwMask: %x, cf2test.dwMask: %x, cf2.dwEffects: %x, cf2test.dwEffects: %x\n",
651      cf2.dwMask, cf2test.dwMask, cf2.dwEffects, cf2test.dwEffects);
652   DestroyWindow(hwndRichEdit);
653 }
654
655 static void test_WM_GETTEXT(void)
656 {
657     HWND hwndRichEdit = new_richedit(NULL);
658     static const char text[] = "Hello. My name is RichEdit!";
659     static const char text2[] = "Hello. My name is RichEdit!\r";
660     static const char text2_after[] = "Hello. My name is RichEdit!\r\n";
661     char buffer[1024] = {0};
662     int result;
663
664     /* Baseline test with normal-sized buffer */
665     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
666     result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
667     ok(result == lstrlen(buffer),
668         "WM_GETTEXT returned %d, expected %d\n", result, lstrlen(buffer));
669     SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
670     result = strcmp(buffer,text);
671     ok(result == 0, 
672         "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
673
674     /* Test for returned value of WM_GETTEXTLENGTH */
675     result = SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
676     ok(result == lstrlen(text),
677         "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
678         result, lstrlen(text));
679
680     /* Test for behavior in overflow case */
681     memset(buffer, 0, 1024);
682     result = SendMessage(hwndRichEdit, WM_GETTEXT, strlen(text), (LPARAM)buffer);
683     ok(result == 0,
684         "WM_GETTEXT returned %d, expected 0\n", result);
685     result = strcmp(buffer,text);
686     ok(result == 0,
687         "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
688
689     /* Baseline test with normal-sized buffer and carriage return */
690     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text2);
691     result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
692     ok(result == lstrlen(buffer),
693         "WM_GETTEXT returned %d, expected %d\n", result, lstrlen(buffer));
694     result = strcmp(buffer,text2_after);
695     ok(result == 0,
696         "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
697
698     /* Test for returned value of WM_GETTEXTLENGTH */
699     result = SendMessage(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
700     ok(result == lstrlen(text2_after),
701         "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
702         result, lstrlen(text2_after));
703
704     /* Test for behavior of CRLF conversion in case of overflow */
705     memset(buffer, 0, 1024);
706     result = SendMessage(hwndRichEdit, WM_GETTEXT, strlen(text2), (LPARAM)buffer);
707     ok(result == 0,
708         "WM_GETTEXT returned %d, expected 0\n", result);
709     result = strcmp(buffer,text2);
710     ok(result == 0,
711         "WM_GETTEXT: settext and gettext differ. strcmp: %d\n", result);
712
713     DestroyWindow(hwndRichEdit);
714 }
715
716 /* FIXME: need to test unimplemented options and robustly test wparam */
717 static void test_EM_SETOPTIONS(void)
718 {
719     HWND hwndRichEdit = new_richedit(NULL);
720     static const char text[] = "Hello. My name is RichEdit!";
721     char buffer[1024] = {0};
722
723     /* NEGATIVE TESTING - NO OPTIONS SET */
724     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
725     SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, 0);
726
727     /* testing no readonly by sending 'a' to the control*/
728     SetFocus(hwndRichEdit);
729     SendMessage(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
730     SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
731     ok(buffer[0]=='a', 
732        "EM_SETOPTIONS: Text not changed! s1:%s s2:%s\n", text, buffer);
733     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
734
735     /* READONLY - sending 'a' to the control */
736     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
737     SendMessage(hwndRichEdit, EM_SETOPTIONS, ECOOP_SET, ECO_READONLY);
738     SetFocus(hwndRichEdit);
739     SendMessage(hwndRichEdit, WM_CHAR, 'a', 0x1E0001);
740     SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
741     ok(buffer[0]==text[0], 
742        "EM_SETOPTIONS: Text changed! s1:%s s2:%s\n", text, buffer); 
743
744     DestroyWindow(hwndRichEdit);
745 }
746
747 static void check_CFE_LINK_rcvd(HWND hwnd, int is_url, const char * url)
748 {
749   CHARFORMAT2W text_format;
750   int link_present = 0;
751   text_format.cbSize = sizeof(text_format);
752   SendMessage(hwnd, EM_SETSEL, 0, 1);
753   SendMessage(hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &text_format);
754   link_present = text_format.dwEffects & CFE_LINK;
755   if (is_url) 
756   { /* control text is url; should get CFE_LINK */
757         ok(0 != link_present, "URL Case: CFE_LINK not set for [%s].\n", url);
758   }
759   else 
760   {
761     ok(0 == link_present, "Non-URL Case: CFE_LINK set for [%s].\n", url);
762   }
763 }
764
765 static HWND new_static_wnd(HWND parent) {
766   return new_window("Static", 0, parent);
767 }
768
769 static void test_EM_AUTOURLDETECT(void)
770 {
771   struct urls_s {
772     const char *text;
773     int is_url;
774   } urls[12] = {
775     {"winehq.org", 0},
776     {"http://www.winehq.org", 1},
777     {"http//winehq.org", 0},
778     {"ww.winehq.org", 0},
779     {"www.winehq.org", 1},
780     {"ftp://192.168.1.1", 1},
781     {"ftp//192.168.1.1", 0},
782     {"mailto:your@email.com", 1},    
783     {"prospero:prosperoserver", 1},
784     {"telnet:test", 1},
785     {"news:newserver", 1},
786     {"wais:waisserver", 1}  
787   };
788
789   int i;
790   int urlRet=-1;
791   HWND hwndRichEdit, parent;
792
793   parent = new_static_wnd(NULL);
794   hwndRichEdit = new_richedit(parent);
795   /* Try and pass EM_AUTOURLDETECT some test wParam values */
796   urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
797   ok(urlRet==0, "Good wParam: urlRet is: %d\n", urlRet);
798   urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, 1, 0);
799   ok(urlRet==0, "Good wParam2: urlRet is: %d\n", urlRet);
800   /* Windows returns -2147024809 (0x80070057) on bad wParam values */
801   urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, 8, 0);
802   ok(urlRet==E_INVALIDARG, "Bad wParam: urlRet is: %d\n", urlRet);
803   urlRet=SendMessage(hwndRichEdit, EM_AUTOURLDETECT, (WPARAM)"h", (LPARAM)"h");
804   ok(urlRet==E_INVALIDARG, "Bad wParam2: urlRet is: %d\n", urlRet);
805   /* for each url, check the text to see if CFE_LINK effect is present */
806   for (i = 0; i < sizeof(urls)/sizeof(struct urls_s); i++) {
807     SendMessage(hwndRichEdit, EM_AUTOURLDETECT, FALSE, 0);
808     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) urls[i].text);
809     SendMessage(hwndRichEdit, WM_CHAR, 0, 0);
810     check_CFE_LINK_rcvd(hwndRichEdit, 0, urls[i].text);
811     SendMessage(hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0);
812     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) urls[i].text);
813     SendMessage(hwndRichEdit, WM_CHAR, 0, 0);
814     check_CFE_LINK_rcvd(hwndRichEdit, urls[i].is_url, urls[i].text);
815   }
816   DestroyWindow(hwndRichEdit);
817   DestroyWindow(parent);
818 }
819
820 static void test_EM_SCROLL(void)
821 {
822   int i, j;
823   int r; /* return value */
824   int expr; /* expected return value */
825   HWND hwndRichEdit = new_richedit(NULL);
826   int y_before, y_after; /* units of lines of text */
827
828   /* test a richedit box containing a single line of text */
829   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a");/* one line of text */
830   expr = 0x00010000;
831   for (i = 0; i < 4; i++) {
832     static const int cmd[4] = { SB_PAGEDOWN, SB_PAGEUP, SB_LINEDOWN, SB_LINEUP };
833
834     r = SendMessage(hwndRichEdit, EM_SCROLL, cmd[i], 0);
835     y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
836     ok(expr == r, "EM_SCROLL improper return value returned (i == %d). "
837        "Got 0x%08x, expected 0x%08x\n", i, r, expr);
838     ok(y_after == 0, "EM_SCROLL improper scroll. scrolled to line %d, not 1 "
839        "(i == %d)\n", y_after, i);
840   }
841
842   /*
843    * test a richedit box that will scroll. There are two general
844    * cases: the case without any long lines and the case with a long
845    * line.
846    */
847   for (i = 0; i < 2; i++) { /* iterate through different bodies of text */
848     if (i == 0)
849       SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "a\nb\nc\nd\ne");
850     else
851       SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)
852                   "a LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
853                   "LONG LINE LONG LINE LONG LINE LONG LINE LONG LINE "
854                   "LONG LINE \nb\nc\nd\ne");
855     for (j = 0; j < 12; j++) /* reset scrol position to top */
856       SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0);
857
858     /* get first visible line */
859     y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
860     r = SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0); /* page down */
861
862     /* get new current first visible line */
863     y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
864
865     ok(((r & 0xffffff00) == 0x00010000) &&
866        ((r & 0x000000ff) != 0x00000000),
867        "EM_SCROLL page down didn't scroll by a small positive number of "
868        "lines (r == 0x%08x)\n", r);
869     ok(y_after > y_before, "EM_SCROLL page down not functioning "
870        "(line %d scrolled to line %d\n", y_before, y_after);
871
872     y_before = y_after;
873     
874     r = SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEUP, 0); /* page up */
875     y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
876     ok(((r & 0xffffff00) == 0x0001ff00),
877        "EM_SCROLL page up didn't scroll by a small negative number of lines "
878        "(r == 0x%08x)\n", r);
879     ok(y_after < y_before, "EM_SCROLL page up not functioning (line "
880        "%d scrolled to line %d\n", y_before, y_after);
881     
882     y_before = y_after;
883
884     r = SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */
885
886     y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
887
888     ok(r == 0x00010001, "EM_SCROLL line down didn't scroll by one line "
889        "(r == 0x%08x)\n", r);
890     ok(y_after -1 == y_before, "EM_SCROLL line down didn't go down by "
891        "1 line (%d scrolled to %d)\n", y_before, y_after);
892
893     y_before = y_after;
894
895     r = SendMessage(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */
896
897     y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
898
899     ok(r == 0x0001ffff, "EM_SCROLL line up didn't scroll by one line "
900        "(r == 0x%08x)\n", r);
901     ok(y_after +1 == y_before, "EM_SCROLL line up didn't go up by 1 "
902        "line (%d scrolled to %d)\n", y_before, y_after);
903
904     y_before = y_after;
905
906     r = SendMessage(hwndRichEdit, EM_SCROLL,
907                     SB_LINEUP, 0); /* lineup beyond top */
908
909     y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
910
911     ok(r == 0x00010000,
912        "EM_SCROLL line up returned indicating movement (0x%08x)\n", r);
913     ok(y_before == y_after,
914        "EM_SCROLL line up beyond top worked (%d)\n", y_after);
915
916     y_before = y_after;
917
918     r = SendMessage(hwndRichEdit, EM_SCROLL,
919                     SB_PAGEUP, 0);/*page up beyond top */
920
921     y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
922
923     ok(r == 0x00010000,
924        "EM_SCROLL page up returned indicating movement (0x%08x)\n", r);
925     ok(y_before == y_after,
926        "EM_SCROLL page up beyond top worked (%d)\n", y_after);
927
928     for (j = 0; j < 12; j++) /* page down all the way to the bottom */
929       SendMessage(hwndRichEdit, EM_SCROLL, SB_PAGEDOWN, 0);
930     y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
931     r = SendMessage(hwndRichEdit, EM_SCROLL,
932                     SB_PAGEDOWN, 0); /* page down beyond bot */
933     y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
934
935     ok(r == 0x00010000,
936        "EM_SCROLL page down returned indicating movement (0x%08x)\n", r);
937     ok(y_before == y_after,
938        "EM_SCROLL page down beyond bottom worked (%d -> %d)\n",
939        y_before, y_after);
940
941     y_before = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
942     SendMessage(hwndRichEdit, EM_SCROLL,
943                 SB_LINEDOWN, 0); /* line down beyond bot */
944     y_after = SendMessage(hwndRichEdit, EM_GETFIRSTVISIBLELINE, 0, 0);
945     
946     ok(r == 0x00010000,
947        "EM_SCROLL line down returned indicating movement (0x%08x)\n", r);
948     ok(y_before == y_after,
949        "EM_SCROLL line down beyond bottom worked (%d -> %d)\n",
950        y_before, y_after);
951   }
952   DestroyWindow(hwndRichEdit);
953 }
954
955 static void test_EM_SETUNDOLIMIT(void)
956 {
957   /* cases we test for:
958    * default behaviour - limiting at 100 undo's 
959    * undo disabled - setting a limit of 0
960    * undo limited -  undo limit set to some to some number, like 2
961    * bad input - sending a negative number should default to 100 undo's */
962  
963   HWND hwndRichEdit = new_richedit(NULL);
964   CHARRANGE cr;
965   int i;
966   int result;
967   
968   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "x");
969   cr.cpMin = 0;
970   cr.cpMax = 1;
971   SendMessage(hwndRichEdit, WM_COPY, 0, 0);
972     /*Load "x" into the clipboard. Paste is an easy, undo'able operation.
973       also, multiple pastes don't combine like WM_CHAR would */
974   SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
975
976   /* first case - check the default */
977   SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0); 
978   for (i=0; i<101; i++) /* Put 101 undo's on the stack */
979     SendMessage(hwndRichEdit, WM_PASTE, 0, 0); 
980   for (i=0; i<100; i++) /* Undo 100 of them */
981     SendMessage(hwndRichEdit, WM_UNDO, 0, 0); 
982   ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
983      "EM_SETUNDOLIMIT allowed more than a hundred undo's by default.\n");
984
985   /* second case - cannot undo */
986   SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0); 
987   SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, 0, 0); 
988   SendMessage(hwndRichEdit,
989               WM_PASTE, 0, 0); /* Try to put something in the undo stack */
990   ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
991      "EM_SETUNDOLIMIT allowed undo with UNDOLIMIT set to 0\n");
992
993   /* third case - set it to an arbitrary number */
994   SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0, 0); 
995   SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, 2, 0); 
996   SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
997   SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
998   SendMessage(hwndRichEdit, WM_PASTE, 0, 0); 
999   /* If SETUNDOLIMIT is working, there should only be two undo's after this */
1000   ok(SendMessage(hwndRichEdit, EM_CANUNDO, 0,0),
1001      "EM_SETUNDOLIMIT didn't allow the first undo with UNDOLIMIT set to 2\n");
1002   SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
1003   ok(SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
1004      "EM_SETUNDOLIMIT didn't allow a second undo with UNDOLIMIT set to 2\n");
1005   SendMessage(hwndRichEdit, WM_UNDO, 0, 0); 
1006   ok(!SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0),
1007      "EM_SETUNDOLIMIT allowed a third undo with UNDOLIMIT set to 2\n");
1008   
1009   /* fourth case - setting negative numbers should default to 100 undos */
1010   SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0); 
1011   result = SendMessage(hwndRichEdit, EM_SETUNDOLIMIT, -1, 0);
1012   ok (result == 100, 
1013       "EM_SETUNDOLIMIT returned %d when set to -1, instead of 100\n",result);
1014       
1015   DestroyWindow(hwndRichEdit);
1016 }
1017
1018 static void test_ES_PASSWORD(void)
1019 {
1020   /* This isn't hugely testable, so we're just going to run it through its paces */
1021
1022   HWND hwndRichEdit = new_richedit(NULL);
1023   WCHAR result;
1024
1025   /* First, check the default of a regular control */
1026   result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
1027   ok (result == 0,
1028         "EM_GETPASSWORDCHAR returned %c by default, instead of NULL\n",result);
1029
1030   /* Now, set it to something normal */
1031   SendMessage(hwndRichEdit, EM_SETPASSWORDCHAR, 'x', 0);
1032   result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
1033   ok (result == 120,
1034         "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result);
1035
1036   /* Now, set it to something odd */
1037   SendMessage(hwndRichEdit, EM_SETPASSWORDCHAR, (WCHAR)1234, 0);
1038   result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0);
1039   ok (result == 1234,
1040         "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result);
1041   DestroyWindow(hwndRichEdit);
1042 }
1043
1044 static void test_WM_SETTEXT()
1045 {
1046   HWND hwndRichEdit = new_richedit(NULL);
1047   const char * TestItem1 = "TestSomeText";
1048   const char * TestItem2 = "TestSomeText\r";
1049   const char * TestItem2_after = "TestSomeText\r\n";
1050   const char * TestItem3 = "TestSomeText\rSomeMoreText\r";
1051   const char * TestItem3_after = "TestSomeText\r\nSomeMoreText\r\n";
1052   const char * TestItem4 = "TestSomeText\n\nTestSomeText";
1053   const char * TestItem4_after = "TestSomeText\r\n\r\nTestSomeText";
1054   const char * TestItem5 = "TestSomeText\r\r\nTestSomeText";
1055   const char * TestItem5_after = "TestSomeText TestSomeText";
1056   const char * TestItem6 = "TestSomeText\r\r\n\rTestSomeText";
1057   const char * TestItem6_after = "TestSomeText \r\nTestSomeText";
1058   const char * TestItem7 = "TestSomeText\r\n\r\r\n\rTestSomeText";
1059   const char * TestItem7_after = "TestSomeText\r\n \r\nTestSomeText";
1060   char buf[1024] = {0};
1061   LRESULT result;
1062
1063   /* This test attempts to show that WM_SETTEXT on a riched20 control causes
1064      any solitary \r to be converted to \r\n on return. Properly paired
1065      \r\n are not affected. It also shows that the special sequence \r\r\n
1066      gets converted to a single space.
1067    */
1068
1069 #define TEST_SETTEXT(a, b) \
1070   result = SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) a); \
1071   ok (result == 1, "WM_SETTEXT returned %ld instead of 1\n", result); \
1072   result = SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buf); \
1073   ok (result == lstrlen(buf), \
1074         "WM_GETTEXT returned %ld instead of expected %u\n", \
1075         result, lstrlen(buf)); \
1076   result = strcmp(b, buf); \
1077   ok(result == 0, \
1078         "WM_SETTEXT round trip: strcmp = %ld\n", result);
1079
1080   TEST_SETTEXT(TestItem1, TestItem1)
1081   TEST_SETTEXT(TestItem2, TestItem2_after)
1082   TEST_SETTEXT(TestItem3, TestItem3_after)
1083   TEST_SETTEXT(TestItem3_after, TestItem3_after)
1084   TEST_SETTEXT(TestItem4, TestItem4_after)
1085   TEST_SETTEXT(TestItem5, TestItem5_after)
1086   TEST_SETTEXT(TestItem6, TestItem6_after)
1087   TEST_SETTEXT(TestItem7, TestItem7_after)
1088
1089 #undef TEST_SETTEXT
1090   DestroyWindow(hwndRichEdit);
1091 }
1092
1093 static void test_EM_SETTEXTEX(void)
1094 {
1095   HWND hwndRichEdit = new_richedit(NULL);
1096   SETTEXTEX setText;
1097   GETTEXTEX getText;
1098   WCHAR TestItem1[] = {'T', 'e', 's', 't', 
1099                        'S', 'o', 'm', 'e', 
1100                        'T', 'e', 'x', 't', 0}; 
1101   WCHAR TestItem2[] = {'T', 'e', 's', 't',
1102                        'S', 'o', 'm', 'e',
1103                        'T', 'e', 'x', 't',
1104                       '\r', 0};
1105   const char * TestItem2_after = "TestSomeText\r\n";
1106   WCHAR TestItem3[] = {'T', 'e', 's', 't',
1107                        'S', 'o', 'm', 'e',
1108                        'T', 'e', 'x', 't',
1109                       '\r','\n','\r','\n', 0};
1110   WCHAR TestItem3alt[] = {'T', 'e', 's', 't',
1111                        'S', 'o', 'm', 'e',
1112                        'T', 'e', 'x', 't',
1113                        '\n','\n', 0};
1114   WCHAR TestItem3_after[] = {'T', 'e', 's', 't',
1115                        'S', 'o', 'm', 'e',
1116                        'T', 'e', 'x', 't',
1117                        '\r','\r', 0};
1118   WCHAR TestItem4[] = {'T', 'e', 's', 't',
1119                        'S', 'o', 'm', 'e',
1120                        'T', 'e', 'x', 't',
1121                       '\r','\r','\n','\r',
1122                       '\n', 0};
1123   WCHAR TestItem4_after[] = {'T', 'e', 's', 't',
1124                        'S', 'o', 'm', 'e',
1125                        'T', 'e', 'x', 't',
1126                        ' ','\r', 0};
1127 #define MAX_BUF_LEN 1024
1128   WCHAR buf[MAX_BUF_LEN];
1129   int result;
1130   CHARRANGE cr;
1131
1132   setText.codepage = 1200;  /* no constant for unicode */
1133   getText.codepage = 1200;  /* no constant for unicode */
1134   getText.cb = MAX_BUF_LEN;
1135   getText.flags = GT_DEFAULT;
1136   getText.lpDefaultChar = NULL;
1137   getText.lpUsedDefChar = NULL;
1138
1139   setText.flags = 0;
1140   SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
1141   SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1142   ok(lstrcmpW(buf, TestItem1) == 0,
1143       "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
1144
1145   /* Unlike WM_SETTEXT/WM_GETTEXT pair, EM_SETTEXTEX/EM_GETTEXTEX does not
1146      convert \r to \r\n on return
1147    */
1148   setText.codepage = 1200;  /* no constant for unicode */
1149   getText.codepage = 1200;  /* no constant for unicode */
1150   getText.cb = MAX_BUF_LEN;
1151   getText.flags = GT_DEFAULT;
1152   getText.lpDefaultChar = NULL;
1153   getText.lpUsedDefChar = NULL;
1154   setText.flags = 0;
1155   SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem2);
1156   SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1157   ok(lstrcmpW(buf, TestItem2) == 0,
1158       "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
1159
1160   /* However, WM_GETTEXT *does* see \r\n where EM_GETTEXTEX would see \r */
1161   SendMessage(hwndRichEdit, WM_GETTEXT, MAX_BUF_LEN, (LPARAM)buf);
1162   ok(strcmp((const char *)buf, TestItem2_after) == 0,
1163       "WM_GETTEXT did *not* see \\r converted to \\r\\n pairs.\n");
1164
1165   /* Baseline test for just-enough buffer space for string */
1166   getText.cb = (lstrlenW(TestItem2) + 1) * sizeof(WCHAR);
1167   getText.codepage = 1200;  /* no constant for unicode */
1168   getText.flags = GT_DEFAULT;
1169   getText.lpDefaultChar = NULL;
1170   getText.lpUsedDefChar = NULL;
1171   memset(buf, 0, MAX_BUF_LEN);
1172   SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1173   ok(lstrcmpW(buf, TestItem2) == 0,
1174       "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
1175
1176   /* When there is enough space for one character, but not both, of the CRLF
1177      pair at the end of the string, the CR is not copied at all. That is,
1178      the caller must not see CRLF pairs truncated to CR at the end of the
1179      string.
1180    */
1181   getText.cb = (lstrlenW(TestItem2) + 1) * sizeof(WCHAR);
1182   getText.codepage = 1200;  /* no constant for unicode */
1183   getText.flags = GT_USECRLF;   /* <-- asking for CR -> CRLF conversion */
1184   getText.lpDefaultChar = NULL;
1185   getText.lpUsedDefChar = NULL;
1186   memset(buf, 0, MAX_BUF_LEN);
1187   SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1188   ok(lstrcmpW(buf, TestItem1) == 0,
1189       "EM_GETTEXTEX results not what was set by EM_SETTEXTEX\n");
1190
1191
1192   /* \r\n pairs get changed into \r */
1193   setText.codepage = 1200;  /* no constant for unicode */
1194   getText.codepage = 1200;  /* no constant for unicode */
1195   getText.cb = MAX_BUF_LEN;
1196   getText.flags = GT_DEFAULT;
1197   getText.lpDefaultChar = NULL;
1198   getText.lpUsedDefChar = NULL;
1199   setText.flags = 0;
1200   SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem3);
1201   SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1202   ok(lstrcmpW(buf, TestItem3_after) == 0,
1203       "EM_SETTEXTEX did not convert properly\n");
1204
1205   /* \n also gets changed to \r */
1206   setText.codepage = 1200;  /* no constant for unicode */
1207   getText.codepage = 1200;  /* no constant for unicode */
1208   getText.cb = MAX_BUF_LEN;
1209   getText.flags = GT_DEFAULT;
1210   getText.lpDefaultChar = NULL;
1211   getText.lpUsedDefChar = NULL;
1212   setText.flags = 0;
1213   SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem3alt);
1214   SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1215   ok(lstrcmpW(buf, TestItem3_after) == 0,
1216       "EM_SETTEXTEX did not convert properly\n");
1217
1218   /* \r\r\n gets changed into single space */
1219   setText.codepage = 1200;  /* no constant for unicode */
1220   getText.codepage = 1200;  /* no constant for unicode */
1221   getText.cb = MAX_BUF_LEN;
1222   getText.flags = GT_DEFAULT;
1223   getText.lpDefaultChar = NULL;
1224   getText.lpUsedDefChar = NULL;
1225   setText.flags = 0;
1226   SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem4);
1227   SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1228   ok(lstrcmpW(buf, TestItem4_after) == 0,
1229       "EM_SETTEXTEX did not convert properly\n");
1230
1231   result = SendMessage(hwndRichEdit, EM_SETTEXTEX, 
1232                        (WPARAM)&setText, (LPARAM) NULL);
1233   SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1234   
1235   ok (result == 1, 
1236       "EM_SETTEXTEX returned %d, instead of 1\n",result);
1237   ok(lstrlenW(buf) == 0,
1238       "EM_SETTEXTEX with NULL lParam should clear rich edit.\n");
1239   
1240   /* put some text back */
1241   setText.flags = 0;
1242   SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
1243   /* select some text */
1244   cr.cpMax = 1;
1245   cr.cpMin = 3;
1246   SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1247   /* replace current selection */
1248   setText.flags = ST_SELECTION;
1249   result = SendMessage(hwndRichEdit, EM_SETTEXTEX, 
1250                        (WPARAM)&setText, (LPARAM) NULL);
1251   ok(result == 0,
1252       "EM_SETTEXTEX with NULL lParam to replace selection"
1253       " with no text should return 0. Got %i\n",
1254       result);
1255   
1256   /* put some text back */
1257   setText.flags = 0;
1258   SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM) TestItem1);
1259   /* select some text */
1260   cr.cpMax = 1;
1261   cr.cpMin = 3;
1262   SendMessage(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM) &cr);
1263   /* replace current selection */
1264   setText.flags = ST_SELECTION;
1265   result = SendMessage(hwndRichEdit, EM_SETTEXTEX,
1266                        (WPARAM)&setText, (LPARAM) TestItem1);
1267   /* get text */
1268   SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buf);
1269   ok(result == lstrlenW(TestItem1),
1270       "EM_SETTEXTEX with NULL lParam to replace selection"
1271       " with no text should return 0. Got %i\n",
1272       result);
1273   ok(lstrlenW(buf) == 22,
1274       "EM_SETTEXTEX to replace selection with more text failed: %i.\n",
1275       lstrlenW(buf) );
1276
1277   DestroyWindow(hwndRichEdit);
1278 }
1279
1280 static void test_EM_LIMITTEXT(void)
1281 {
1282   int ret;
1283
1284   HWND hwndRichEdit = new_richedit(NULL);
1285
1286   /* The main purpose of this test is to demonstrate that the nonsense in MSDN
1287    * about setting the length to -1 for multiline edit controls doesn't happen.
1288    */
1289
1290   /* Don't check default gettextlimit case. That's done in other tests */
1291
1292   /* Set textlimit to 100 */
1293   SendMessage (hwndRichEdit, EM_LIMITTEXT, 100, 0);
1294   ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1295   ok (ret == 100,
1296       "EM_LIMITTEXT: set to 100, returned: %d, expected: 100\n", ret);
1297
1298   /* Set textlimit to 0 */
1299   SendMessage (hwndRichEdit, EM_LIMITTEXT, 0, 0);
1300   ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1301   ok (ret == 65536,
1302       "EM_LIMITTEXT: set to 0, returned: %d, expected: 65536\n", ret);
1303
1304   /* Set textlimit to -1 */
1305   SendMessage (hwndRichEdit, EM_LIMITTEXT, -1, 0);
1306   ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1307   ok (ret == -1,
1308       "EM_LIMITTEXT: set to -1, returned: %d, expected: -1\n", ret);
1309
1310   /* Set textlimit to -2 */
1311   SendMessage (hwndRichEdit, EM_LIMITTEXT, -2, 0);
1312   ret = SendMessage (hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1313   ok (ret == -2,
1314       "EM_LIMITTEXT: set to -2, returned: %d, expected: -2\n", ret);
1315
1316   DestroyWindow (hwndRichEdit);
1317 }
1318
1319
1320 static void test_EM_EXLIMITTEXT(void)
1321 {
1322   int i, selBegin, selEnd, len1, len2;
1323   int result;
1324   char text[1024 + 1];
1325   char buffer[1024 + 1];
1326   int textlimit = 0; /* multiple of 100 */
1327   HWND hwndRichEdit = new_richedit(NULL);
1328   
1329   i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1330   ok(32767 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 32767, i); /* default */
1331   
1332   textlimit = 256000;
1333   SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1334   i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1335   /* set higher */
1336   ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i);
1337   
1338   textlimit = 1000;
1339   SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1340   i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1341   /* set lower */
1342   ok(textlimit == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", textlimit, i);
1343  
1344   SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, 0);
1345   i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1346   /* default for WParam = 0 */
1347   ok(65536 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 65536, i);
1348  
1349   textlimit = sizeof(text)-1;
1350   memset(text, 'W', textlimit);
1351   text[sizeof(text)-1] = 0;
1352   SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1353   /* maxed out text */
1354   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1355   
1356   SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);  /* select everything */
1357   SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1358   len1 = selEnd - selBegin;
1359   
1360   SendMessage(hwndRichEdit, WM_KEYDOWN, VK_BACK, 1);
1361   SendMessage(hwndRichEdit, WM_CHAR, VK_BACK, 1);
1362   SendMessage(hwndRichEdit, WM_KEYUP, VK_BACK, 1);
1363   SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1364   SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1365   len2 = selEnd - selBegin;
1366   
1367   ok(len1 != len2,
1368     "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1369     len1,len2,i);
1370   
1371   SendMessage(hwndRichEdit, WM_KEYDOWN, 'A', 1);
1372   SendMessage(hwndRichEdit, WM_CHAR, 'A', 1);
1373   SendMessage(hwndRichEdit, WM_KEYUP, 'A', 1);
1374   SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1375   SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1376   len1 = selEnd - selBegin;
1377   
1378   ok(len1 != len2,
1379     "EM_EXLIMITTEXT: Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1380     len1,len2,i);
1381   
1382   SendMessage(hwndRichEdit, WM_KEYDOWN, 'A', 1);
1383   SendMessage(hwndRichEdit, WM_CHAR, 'A', 1);
1384   SendMessage(hwndRichEdit, WM_KEYUP, 'A', 1);  /* full; should be no effect */
1385   SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1386   SendMessage(hwndRichEdit, EM_GETSEL, (WPARAM)&selBegin, (LPARAM)&selEnd);
1387   len2 = selEnd - selBegin;
1388   
1389   ok(len1 == len2, 
1390     "EM_EXLIMITTEXT: No Change Expected\nOld Length: %d, New Length: %d, Limit: %d\n",
1391     len1,len2,i);
1392
1393   /* set text up to the limit, select all the text, then add a char */
1394   textlimit = 5;
1395   memset(text, 'W', textlimit);
1396   text[textlimit] = 0;
1397   SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1398   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1399   SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);
1400   SendMessage(hwndRichEdit, WM_CHAR, 'A', 1);
1401   SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1402   result = strcmp(buffer, "A");
1403   ok(0 == result, "got string = \"%s\"\n", buffer);
1404
1405   /* WM_SETTEXT not limited */
1406   textlimit = 10;
1407   memset(text, 'W', textlimit);
1408   text[textlimit] = 0;
1409   SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit-5);
1410   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text);
1411   SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1412   i = strlen(buffer);
1413   ok(10 == i, "expected 10 chars\n");
1414   i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1415   ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
1416
1417   /* try inserting more text at end */
1418   i = SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1419   ok(0 == i, "WM_CHAR wasn't processed\n");
1420   SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1421   i = strlen(buffer);
1422   ok(10 == i, "expected 10 chars, got %i\n", i);
1423   i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1424   ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
1425
1426   /* try inserting text at beginning */
1427   SendMessage(hwndRichEdit, EM_SETSEL, 0, 0);
1428   i = SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1429   ok(0 == i, "WM_CHAR wasn't processed\n");
1430   SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1431   i = strlen(buffer);
1432   ok(10 == i, "expected 10 chars, got %i\n", i);
1433   i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1434   ok(10 == i, "EM_EXLIMITTEXT: expected: %d, actual: %d\n", 10, i);
1435
1436   /* WM_CHAR is limited */
1437   textlimit = 1;
1438   SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, textlimit);
1439   SendMessage(hwndRichEdit, EM_SETSEL, 0, -1);  /* select everything */
1440   i = SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1441   ok(0 == i, "WM_CHAR wasn't processed\n");
1442   i = SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1443   ok(0 == i, "WM_CHAR wasn't processed\n");
1444   SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1445   i = strlen(buffer);
1446   ok(1 == i, "expected 1 chars, got %i instead\n", i);
1447
1448   DestroyWindow(hwndRichEdit);
1449 }
1450
1451 static void test_EM_GETLIMITTEXT(void)
1452 {
1453   int i;
1454   HWND hwndRichEdit = new_richedit(NULL);
1455
1456   i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1457   ok(32767 == i, "expected: %d, actual: %d\n", 32767, i); /* default value */
1458
1459   SendMessage(hwndRichEdit, EM_EXLIMITTEXT, 0, 50000);
1460   i = SendMessage(hwndRichEdit, EM_GETLIMITTEXT, 0, 0);
1461   ok(50000 == i, "expected: %d, actual: %d\n", 50000, i);
1462
1463   DestroyWindow(hwndRichEdit);
1464 }
1465
1466 static void test_WM_SETFONT(void)
1467 {
1468   /* There is no invalid input or error conditions for this function.
1469    * NULL wParam and lParam just fall back to their default values 
1470    * It should be noted that even if you use a gibberish name for your fonts
1471    * here, it will still work because the name is stored. They will display as
1472    * System, but will report their name to be whatever they were created as */
1473   
1474   HWND hwndRichEdit = new_richedit(NULL);
1475   HFONT testFont1 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET, 
1476     OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | 
1477     FF_DONTCARE, "Marlett");
1478   HFONT testFont2 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET, 
1479     OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | 
1480     FF_DONTCARE, "MS Sans Serif");
1481   HFONT testFont3 = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET, 
1482     OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | 
1483     FF_DONTCARE, "Courier");
1484   LOGFONTA sentLogFont;
1485   CHARFORMAT2A returnedCF2A;
1486   
1487   returnedCF2A.cbSize = sizeof(returnedCF2A);
1488   
1489   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "x");
1490   SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont1,(LPARAM) MAKELONG((WORD) TRUE, 0));
1491   SendMessage(hwndRichEdit, EM_GETCHARFORMAT,   SCF_DEFAULT,  (LPARAM) &returnedCF2A);
1492
1493   GetObjectA(testFont1, sizeof(LOGFONTA), &sentLogFont);
1494   ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
1495     "EM_GETCHARFOMAT: Returned wrong font on test 1. Sent: %s, Returned: %s\n",
1496     sentLogFont.lfFaceName,returnedCF2A.szFaceName);
1497
1498   SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont2,(LPARAM) MAKELONG((WORD) TRUE, 0));
1499   SendMessage(hwndRichEdit, EM_GETCHARFORMAT,   SCF_DEFAULT,  (LPARAM) &returnedCF2A);
1500   GetObjectA(testFont2, sizeof(LOGFONTA), &sentLogFont);
1501   ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
1502     "EM_GETCHARFOMAT: Returned wrong font on test 2. Sent: %s, Returned: %s\n",
1503     sentLogFont.lfFaceName,returnedCF2A.szFaceName);
1504     
1505   SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont3,(LPARAM) MAKELONG((WORD) TRUE, 0));
1506   SendMessage(hwndRichEdit, EM_GETCHARFORMAT,   SCF_DEFAULT,  (LPARAM) &returnedCF2A);
1507   GetObjectA(testFont3, sizeof(LOGFONTA), &sentLogFont);
1508   ok (!strcmp(sentLogFont.lfFaceName,returnedCF2A.szFaceName),
1509     "EM_GETCHARFOMAT: Returned wrong font on test 3. Sent: %s, Returned: %s\n",
1510     sentLogFont.lfFaceName,returnedCF2A.szFaceName);
1511    
1512   /* This last test is special since we send in NULL. We clear the variables
1513    * and just compare to "System" instead of the sent in font name. */
1514   ZeroMemory(&returnedCF2A,sizeof(returnedCF2A));
1515   ZeroMemory(&sentLogFont,sizeof(sentLogFont));
1516   returnedCF2A.cbSize = sizeof(returnedCF2A);
1517   
1518   SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)NULL,(LPARAM) MAKELONG((WORD) TRUE, 0));
1519   SendMessage(hwndRichEdit, EM_GETCHARFORMAT,   SCF_DEFAULT,  (LPARAM) &returnedCF2A);
1520   GetObjectA(NULL, sizeof(LOGFONTA), &sentLogFont);
1521   ok (!strcmp("System",returnedCF2A.szFaceName),
1522     "EM_GETCHARFOMAT: Returned wrong font on test 4. Sent: NULL, Returned: %s. Expected \"System\".\n",returnedCF2A.szFaceName);
1523   
1524   DestroyWindow(hwndRichEdit);
1525 }
1526
1527
1528 static DWORD CALLBACK test_EM_GETMODIFY_esCallback(DWORD_PTR dwCookie,
1529                                          LPBYTE pbBuff,
1530                                          LONG cb,
1531                                          LONG *pcb)
1532 {
1533   const char** str = (const char**)dwCookie;
1534   int size = strlen(*str);
1535   if(size > 3)  /* let's make it peice-meal for fun */
1536     size = 3;
1537   *pcb = cb;
1538   if (*pcb > size) {
1539     *pcb = size;
1540   }
1541   if (*pcb > 0) {
1542     memcpy(pbBuff, *str, *pcb);
1543     *str += *pcb;
1544   }
1545   return 0;
1546 }
1547
1548 static void test_EM_GETMODIFY(void)
1549 {
1550   HWND hwndRichEdit = new_richedit(NULL);
1551   LRESULT result;
1552   SETTEXTEX setText;
1553   WCHAR TestItem1[] = {'T', 'e', 's', 't', 
1554                        'S', 'o', 'm', 'e', 
1555                        'T', 'e', 'x', 't', 0}; 
1556   WCHAR TestItem2[] = {'T', 'e', 's', 't', 
1557                        'S', 'o', 'm', 'e', 
1558                        'O', 't', 'h', 'e', 'r',
1559                        'T', 'e', 'x', 't', 0}; 
1560   const char* streamText = "hello world";
1561   CHARFORMAT2 cf2;
1562   PARAFORMAT2 pf2;
1563   EDITSTREAM es;
1564   
1565   HFONT testFont = CreateFontA (0,0,0,0,FW_LIGHT, 0, 0, 0, ANSI_CHARSET, 
1566     OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | 
1567     FF_DONTCARE, "Courier");
1568   
1569   setText.codepage = 1200;  /* no constant for unicode */
1570   setText.flags = ST_KEEPUNDO;
1571   
1572
1573   /* modify flag shouldn't be set when richedit is first created */
1574   result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1575   ok (result == 0, 
1576       "EM_GETMODIFY returned non-zero, instead of zero on create\n");
1577   
1578   /* setting modify flag should actually set it */
1579   SendMessage(hwndRichEdit, EM_SETMODIFY, TRUE, 0);
1580   result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1581   ok (result != 0, 
1582       "EM_GETMODIFY returned zero, instead of non-zero on EM_SETMODIFY\n");
1583   
1584   /* clearing modify flag should actually clear it */
1585   SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1586   result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1587   ok (result == 0, 
1588       "EM_GETMODIFY returned non-zero, instead of zero on EM_SETMODIFY\n");
1589  
1590   /* setting font doesn't change modify flag */
1591   SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1592   SendMessage(hwndRichEdit, WM_SETFONT, (WPARAM)testFont,(LPARAM) MAKELONG((WORD) TRUE, 0));
1593   result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1594   ok (result == 0,
1595       "EM_GETMODIFY returned non-zero, instead of zero on setting font\n");
1596
1597   /* setting text should set modify flag */
1598   SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1599   SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
1600   result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1601   ok (result != 0,
1602       "EM_GETMODIFY returned zero, instead of non-zero on setting text\n");
1603   
1604   /* undo previous text doesn't reset modify flag */
1605   SendMessage(hwndRichEdit, WM_UNDO, 0, 0);
1606   result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1607   ok (result != 0,
1608       "EM_GETMODIFY returned zero, instead of non-zero on undo after setting text\n");
1609   
1610   /* set text with no flag to keep undo stack should not set modify flag */
1611   SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1612   setText.flags = 0;
1613   SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
1614   result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1615   ok (result == 0,
1616       "EM_GETMODIFY returned non-zero, instead of zero when setting text while not keeping undo stack\n");
1617   
1618   /* WM_SETTEXT doesn't modify */
1619   SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1620   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem2);
1621   result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1622   ok (result == 0,
1623       "EM_GETMODIFY returned non-zero for WM_SETTEXT\n");
1624   
1625   /* clear the text */
1626   SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1627   SendMessage(hwndRichEdit, WM_CLEAR, 0, 0);
1628   result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1629   ok (result == 0,
1630       "EM_GETMODIFY returned non-zero, instead of zero for WM_CLEAR\n");
1631   
1632   /* replace text */
1633   SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1634   SendMessage(hwndRichEdit, EM_SETTEXTEX, (WPARAM)&setText, (LPARAM)TestItem1);
1635   SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
1636   SendMessage(hwndRichEdit, EM_REPLACESEL, TRUE, (LPARAM)TestItem2);
1637   result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1638   ok (result != 0,
1639       "EM_GETMODIFY returned zero, instead of non-zero when replacing text\n");
1640   
1641   /* copy/paste text 1 */
1642   SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1643   SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
1644   SendMessage(hwndRichEdit, WM_COPY, 0, 0);
1645   SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1646   result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1647   ok (result != 0,
1648       "EM_GETMODIFY returned zero, instead of non-zero when pasting identical text\n");
1649   
1650   /* copy/paste text 2 */
1651   SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1652   SendMessage(hwndRichEdit, EM_SETSEL, 0, 2);
1653   SendMessage(hwndRichEdit, WM_COPY, 0, 0);
1654   SendMessage(hwndRichEdit, EM_SETSEL, 0, 3);
1655   SendMessage(hwndRichEdit, WM_PASTE, 0, 0);
1656   result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1657   ok (result != 0,
1658       "EM_GETMODIFY returned zero, instead of non-zero when pasting different text\n");
1659   
1660   /* press char */
1661   SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1662   SendMessage(hwndRichEdit, EM_SETSEL, 0, 1);
1663   SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1664   result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1665   ok (result != 0,
1666       "EM_GETMODIFY returned zero, instead of non-zero for WM_CHAR\n");
1667
1668   /* press del */
1669   SendMessage(hwndRichEdit, WM_CHAR, 'A', 0);
1670   SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1671   SendMessage(hwndRichEdit, WM_KEYDOWN, VK_BACK, 0);
1672   result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1673   ok (result != 0,
1674       "EM_GETMODIFY returned zero, instead of non-zero for backspace\n");
1675   
1676   /* set char format */
1677   SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1678   cf2.cbSize = sizeof(CHARFORMAT2);
1679   SendMessage(hwndRichEdit, EM_GETCHARFORMAT, (WPARAM) SCF_DEFAULT,
1680              (LPARAM) &cf2);
1681   cf2.dwMask = CFM_ITALIC | cf2.dwMask;
1682   cf2.dwEffects = CFE_ITALIC ^ cf2.dwEffects;
1683   SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
1684   result = SendMessage(hwndRichEdit, EM_SETCHARFORMAT, (WPARAM) SCF_ALL, (LPARAM) &cf2);
1685   ok(result == 1, "EM_SETCHARFORMAT returned %ld instead of 1\n", result);
1686   result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1687   ok (result != 0,
1688       "EM_GETMODIFY returned zero, instead of non-zero for EM_SETCHARFORMAT\n");
1689   
1690   /* set para format */
1691   SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1692   pf2.cbSize = sizeof(PARAFORMAT2);
1693   SendMessage(hwndRichEdit, EM_GETPARAFORMAT, 0,
1694              (LPARAM) &pf2);
1695   pf2.dwMask = PFM_ALIGNMENT | pf2.dwMask;
1696   pf2.wAlignment = PFA_RIGHT;
1697   SendMessage(hwndRichEdit, EM_SETPARAFORMAT, 0, (LPARAM) &pf2);
1698   result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1699   ok (result == 0,
1700       "EM_GETMODIFY returned zero, instead of non-zero for EM_SETPARAFORMAT\n");
1701
1702   /* EM_STREAM */
1703   SendMessage(hwndRichEdit, EM_SETMODIFY, FALSE, 0);
1704   es.dwCookie = (DWORD_PTR)&streamText;
1705   es.dwError = 0;
1706   es.pfnCallback = test_EM_GETMODIFY_esCallback;
1707   SendMessage(hwndRichEdit, EM_STREAMIN, 
1708               (WPARAM)(SF_TEXT), (LPARAM)&es);
1709   result = SendMessage(hwndRichEdit, EM_GETMODIFY, 0, 0);
1710   ok (result != 0,
1711       "EM_GETMODIFY returned zero, instead of non-zero for EM_STREAM\n");
1712
1713   DestroyWindow(hwndRichEdit);
1714 }
1715
1716 struct exsetsel_s {
1717   long min;
1718   long max;
1719   long expected_retval;
1720   int expected_getsel_start;
1721   int expected_getsel_end;
1722   int _exsetsel_todo_wine;
1723   int _getsel_todo_wine;
1724 };
1725
1726 const struct exsetsel_s exsetsel_tests[] = {
1727   /* sanity tests */
1728   {5, 10, 10, 5, 10, 0, 0},
1729   {15, 17, 17, 15, 17, 0, 0},
1730   /* test cpMax > strlen() */
1731   {0, 100, 18, 0, 18, 0, 1},
1732   /* test cpMin == cpMax */
1733   {5, 5, 5, 5, 5, 0, 0},
1734   /* test cpMin < 0 && cpMax >= 0 (bug 4462) */
1735   {-1, 0, 5, 5, 5, 0, 0},
1736   {-1, 17, 5, 5, 5, 0, 0},
1737   {-1, 18, 5, 5, 5, 0, 0},
1738   /* test cpMin < 0 && cpMax < 0 */
1739   {-1, -1, 17, 17, 17, 0, 0},
1740   {-4, -5, 17, 17, 17, 0, 0},
1741   /* test cMin >=0 && cpMax < 0 (bug 6814) */
1742   {0, -1, 18, 0, 18, 0, 1},
1743   {17, -5, 18, 17, 18, 0, 1},
1744   {18, -3, 17, 17, 17, 0, 0},
1745   /* test if cpMin > cpMax */
1746   {15, 19, 18, 15, 18, 0, 1},
1747   {19, 15, 18, 15, 18, 0, 1}
1748 };
1749
1750 static void check_EM_EXSETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) {
1751     CHARRANGE cr;
1752     long result;
1753     int start, end;
1754
1755     cr.cpMin = setsel->min;
1756     cr.cpMax = setsel->max;
1757     result = SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &cr);
1758
1759     if (setsel->_exsetsel_todo_wine) {
1760         todo_wine {
1761             ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
1762         }
1763     } else {
1764         ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
1765     }
1766
1767     SendMessage(hwnd, EM_GETSEL, (WPARAM) &start, (LPARAM) &end);
1768
1769     if (setsel->_getsel_todo_wine) {
1770         todo_wine {
1771             ok(start == setsel->expected_getsel_start && end == setsel->expected_getsel_end, "EM_EXSETSEL(%d): expected (%d,%d) actual:(%d,%d)\n", id, setsel->expected_getsel_start, setsel->expected_getsel_end, start, end);
1772         }
1773     } else {
1774         ok(start == setsel->expected_getsel_start && end == setsel->expected_getsel_end, "EM_EXSETSEL(%d): expected (%d,%d) actual:(%d,%d)\n", id, setsel->expected_getsel_start, setsel->expected_getsel_end, start, end);
1775     }
1776 }
1777
1778 static void test_EM_EXSETSEL(void)
1779 {
1780     HWND hwndRichEdit = new_richedit(NULL);
1781     int i;
1782     const int num_tests = sizeof(exsetsel_tests)/sizeof(struct exsetsel_s);
1783
1784     /* sending some text to the window */
1785     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "testing selection");
1786     /*                                                 01234567890123456*/
1787     /*                                                          10      */
1788
1789     for (i = 0; i < num_tests; i++) {
1790         check_EM_EXSETSEL(hwndRichEdit, &exsetsel_tests[i], i);
1791     }
1792
1793     DestroyWindow(hwndRichEdit);
1794 }
1795
1796 static void test_EM_REPLACESEL(void)
1797 {
1798     HWND hwndRichEdit = new_richedit(NULL);
1799     char buffer[1024] = {0};
1800     int r;
1801     GETTEXTEX getText;
1802     CHARRANGE cr;
1803
1804     /* sending some text to the window */
1805     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) "testing selection");
1806     /*                                                 01234567890123456*/
1807     /*                                                          10      */
1808
1809     /* FIXME add more tests */
1810     SendMessage(hwndRichEdit, EM_SETSEL, 7, 17);
1811     r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) NULL);
1812     ok(0 == r, "EM_REPLACESEL returned %d, expected 0\n", r);
1813     SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1814     r = strcmp(buffer, "testing");
1815     ok(0 == r, "expected %d, got %d\n", 0, r);
1816
1817     DestroyWindow(hwndRichEdit);
1818
1819     hwndRichEdit = new_richedit(NULL);
1820
1821     /* Test behavior with carriage returns and newlines */
1822     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
1823     r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "RichEdit1");
1824     ok(9 == r, "EM_REPLACESEL returned %d, expected 9\n", r);
1825     SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1826     r = strcmp(buffer, "RichEdit1");
1827     ok(0 == r, "expected %d, got %d\n", 0, r);
1828     getText.cb = 1024;
1829     getText.codepage = CP_ACP;
1830     getText.flags = GT_DEFAULT;
1831     getText.lpDefaultChar = NULL;
1832     getText.lpUsedDefChar = NULL;
1833     SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
1834     ok(strcmp(buffer, "RichEdit1") == 0,
1835       "EM_GETTEXTEX results not what was set by EM_REPLACESEL\n");
1836
1837     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
1838     r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "RichEdit1\r");
1839     ok(10 == r, "EM_REPLACESEL returned %d, expected 10\n", r);
1840     SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1841     r = strcmp(buffer, "RichEdit1\r\n");
1842     ok(0 == r, "expected %d, got %d\n", 0, r);
1843     getText.cb = 1024;
1844     getText.codepage = CP_ACP;
1845     getText.flags = GT_DEFAULT;
1846     getText.lpDefaultChar = NULL;
1847     getText.lpUsedDefChar = NULL;
1848     SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
1849     ok(strcmp(buffer, "RichEdit1\r") == 0,
1850       "EM_GETTEXTEX returned incorrect string\n");
1851
1852     /* Win98's riched20 and WinXP's riched20 disagree on what to return from
1853        EM_REPLACESEL. The general rule seems to be that Win98's riched20
1854        returns the number of characters *inserted* into the control (after
1855        required conversions), but WinXP's riched20 returns the number of
1856        characters interpreted from the original lParam. Wine's builtin riched20
1857        implements the WinXP behavior.
1858      */
1859     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
1860     r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "RichEdit1\r\n");
1861     ok(11 == r /* WinXP */ || 10 == r /* Win98 */,
1862         "EM_REPLACESEL returned %d, expected 11 or 10\n", r);
1863
1864     r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
1865     ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
1866     ok(cr.cpMin == 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr.cpMin);
1867     ok(cr.cpMax == 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr.cpMax);
1868
1869     SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
1870     r = strcmp(buffer, "RichEdit1\r\n");
1871     ok(0 == r, "expected %d, got %d\n", 0, r);
1872     getText.cb = 1024;
1873     getText.codepage = CP_ACP;
1874     getText.flags = GT_DEFAULT;
1875     getText.lpDefaultChar = NULL;
1876     getText.lpUsedDefChar = NULL;
1877     SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
1878     ok(strcmp(buffer, "RichEdit1\r") == 0,
1879       "EM_GETTEXTEX returned incorrect string\n");
1880
1881     r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
1882     ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
1883     ok(cr.cpMin == 10, "EM_EXGETSEL returned cpMin=%d, expected 10\n", cr.cpMin);
1884     ok(cr.cpMax == 10, "EM_EXGETSEL returned cpMax=%d, expected 10\n", cr.cpMax);
1885
1886     /* The following tests show that richedit should handle the special \r\r\n
1887        sequence by turning it into a single space on insertion. However,
1888        EM_REPLACESEL on WinXP returns the number of characters in the original
1889        string.
1890      */
1891
1892     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
1893     r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r");
1894     ok(2 == r, "EM_REPLACESEL returned %d, expected 4\n", r);
1895     r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
1896     ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
1897     ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin);
1898     ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax);
1899
1900     /* Test the actual string */
1901     getText.cb = 1024;
1902     getText.codepage = CP_ACP;
1903     getText.flags = GT_DEFAULT;
1904     getText.lpDefaultChar = NULL;
1905     getText.lpUsedDefChar = NULL;
1906     SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
1907     ok(strcmp(buffer, "\r\r") == 0,
1908       "EM_GETTEXTEX returned incorrect string\n");
1909
1910     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
1911     r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\n");
1912     ok(3 == r /* WinXP */ || 1 == r /* Win98 */,
1913         "EM_REPLACESEL returned %d, expected 3 or 1\n", r);
1914     r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
1915     ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
1916     ok(cr.cpMin == 1, "EM_EXGETSEL returned cpMin=%d, expected 1\n", cr.cpMin);
1917     ok(cr.cpMax == 1, "EM_EXGETSEL returned cpMax=%d, expected 1\n", cr.cpMax);
1918
1919     /* Test the actual string */
1920     getText.cb = 1024;
1921     getText.codepage = CP_ACP;
1922     getText.flags = GT_DEFAULT;
1923     getText.lpDefaultChar = NULL;
1924     getText.lpUsedDefChar = NULL;
1925     SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
1926     ok(strcmp(buffer, " ") == 0,
1927       "EM_GETTEXTEX returned incorrect string\n");
1928
1929     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
1930     r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\r\r\r\n\r\r\r");
1931     ok(9 == r /* WinXP */ || 7 == r /* Win98 */,
1932         "EM_REPLACESEL returned %d, expected 9 or 7\n", r);
1933     r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
1934     ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
1935     ok(cr.cpMin == 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr.cpMin);
1936     ok(cr.cpMax == 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr.cpMax);
1937
1938     /* Test the actual string */
1939     getText.cb = 1024;
1940     getText.codepage = CP_ACP;
1941     getText.flags = GT_DEFAULT;
1942     getText.lpDefaultChar = NULL;
1943     getText.lpUsedDefChar = NULL;
1944     SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
1945     ok(strcmp(buffer, "\r\r\r \r\r\r") == 0,
1946       "EM_GETTEXTEX returned incorrect string\n");
1947
1948     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
1949     r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\n\r\n");
1950     ok(5 == r /* WinXP */ || 2 == r /* Win98 */,
1951         "EM_REPLACESEL returned %d, expected 5 or 2\n", r);
1952     r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
1953     ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
1954     ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin);
1955     ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax);
1956
1957     /* Test the actual string */
1958     getText.cb = 1024;
1959     getText.codepage = CP_ACP;
1960     getText.flags = GT_DEFAULT;
1961     getText.lpDefaultChar = NULL;
1962     getText.lpUsedDefChar = NULL;
1963     SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
1964     ok(strcmp(buffer, " \r") == 0,
1965       "EM_GETTEXTEX returned incorrect string\n");
1966
1967     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
1968     r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\r\r\n\r\r");
1969     ok(5 == r /* WinXP */ || 3 == r /* Win98 */,
1970         "EM_REPLACESEL returned %d, expected 5 or 3\n", r);
1971     r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
1972     ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
1973     ok(cr.cpMin == 3, "EM_EXGETSEL returned cpMin=%d, expected 3\n", cr.cpMin);
1974     ok(cr.cpMax == 3, "EM_EXGETSEL returned cpMax=%d, expected 3\n", cr.cpMax);
1975
1976     /* Test the actual string */
1977     getText.cb = 1024;
1978     getText.codepage = CP_ACP;
1979     getText.flags = GT_DEFAULT;
1980     getText.lpDefaultChar = NULL;
1981     getText.lpUsedDefChar = NULL;
1982     SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
1983     ok(strcmp(buffer, " \r\r") == 0,
1984       "EM_GETTEXTEX returned incorrect string\n");
1985
1986     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
1987     r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\rX\r\n\r\r");
1988     ok(6 == r /* WinXP */ || 5 == r /* Win98 */,
1989         "EM_REPLACESEL returned %d, expected 6 or 5\n", r);
1990     r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
1991     ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
1992     ok(cr.cpMin == 5, "EM_EXGETSEL returned cpMin=%d, expected 5\n", cr.cpMin);
1993     ok(cr.cpMax == 5, "EM_EXGETSEL returned cpMax=%d, expected 5\n", cr.cpMax);
1994
1995     /* Test the actual string */
1996     getText.cb = 1024;
1997     getText.codepage = CP_ACP;
1998     getText.flags = GT_DEFAULT;
1999     getText.lpDefaultChar = NULL;
2000     getText.lpUsedDefChar = NULL;
2001     SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2002     ok(strcmp(buffer, "\rX\r\r\r") == 0,
2003       "EM_GETTEXTEX returned incorrect string\n");
2004
2005     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
2006     r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\n\n");
2007     ok(2 == r, "EM_REPLACESEL returned %d, expected 2\n", r);
2008     r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
2009     ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
2010     ok(cr.cpMin == 2, "EM_EXGETSEL returned cpMin=%d, expected 2\n", cr.cpMin);
2011     ok(cr.cpMax == 2, "EM_EXGETSEL returned cpMax=%d, expected 2\n", cr.cpMax);
2012
2013     /* Test the actual string */
2014     getText.cb = 1024;
2015     getText.codepage = CP_ACP;
2016     getText.flags = GT_DEFAULT;
2017     getText.lpDefaultChar = NULL;
2018     getText.lpUsedDefChar = NULL;
2019     SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2020     ok(strcmp(buffer, "\r\r") == 0,
2021       "EM_GETTEXTEX returned incorrect string\n");
2022
2023     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)NULL);
2024     r = SendMessage(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM) "\n\n\n\n\r\r\r\r\n");
2025     ok(9 == r /* WinXP */ || 7 == r /* Win98 */,
2026         "EM_REPLACESEL returned %d, expected 9 or 7\n", r);
2027     r = SendMessage(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
2028     ok(0 == r, "EM_EXGETSEL returned %d, expected 0\n", r);
2029     ok(cr.cpMin == 7, "EM_EXGETSEL returned cpMin=%d, expected 7\n", cr.cpMin);
2030     ok(cr.cpMax == 7, "EM_EXGETSEL returned cpMax=%d, expected 7\n", cr.cpMax);
2031
2032     /* Test the actual string */
2033     getText.cb = 1024;
2034     getText.codepage = CP_ACP;
2035     getText.flags = GT_DEFAULT;
2036     getText.lpDefaultChar = NULL;
2037     getText.lpUsedDefChar = NULL;
2038     SendMessage(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM) buffer);
2039     ok(strcmp(buffer, "\r\r\r\r\r\r ") == 0,
2040       "EM_GETTEXTEX returned incorrect string\n");
2041
2042     DestroyWindow(hwndRichEdit);
2043 }
2044
2045 static void test_WM_PASTE(void)
2046 {
2047     MSG msg;
2048     int result;
2049     char buffer[1024] = {0};
2050     char key_info[][3] =
2051     {
2052         /* VirtualKey, ScanCode, WM_CHAR code */
2053         {'C', 0x2e,  3},        /* Ctrl-C */
2054         {'X', 0x2d, 24},        /* Ctrl-X */
2055         {'V', 0x2f, 22},        /* Ctrl-V */
2056         {'Z', 0x2c, 26},        /* Ctrl-Z */
2057         {'Y', 0x15, 25},        /* Ctrl-Y */
2058     };
2059     const char* text1 = "testing paste\r";
2060     const char* text1_step1 = "testing paste\r\ntesting paste\r\n";
2061     const char* text1_after = "testing paste\r\n";
2062     const char* text2 = "testing paste\r\rtesting paste";
2063     const char* text2_after = "testing paste\r\n\r\ntesting paste";
2064     const char* text3 = "testing paste\r\npaste\r\ntesting paste";
2065     HWND hwndRichEdit = new_richedit(NULL);
2066
2067     /* Native riched20 won't obey WM_CHAR messages or WM_KEYDOWN/WM_KEYUP
2068        messages, probably because it inspects the keyboard state itself.
2069        Therefore, native requires this in order to obey Ctrl-<key> keystrokes.
2070      */
2071 #define SEND_CTRL_KEY(hwnd, k) \
2072     keybd_event(VK_CONTROL, 0x1d, 0, 0);\
2073     keybd_event(k[0], k[1], 0, 0);\
2074     keybd_event(k[0], k[1], KEYEVENTF_KEYUP, 0);\
2075     keybd_event(VK_CONTROL, 0x1d, KEYEVENTF_KEYUP, 0); \
2076     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { \
2077         TranslateMessage(&msg); \
2078         DispatchMessage(&msg); \
2079     }
2080
2081 #define SEND_CTRL_C(hwnd) SEND_CTRL_KEY(hwnd, key_info[0])
2082 #define SEND_CTRL_X(hwnd) SEND_CTRL_KEY(hwnd, key_info[1])
2083 #define SEND_CTRL_V(hwnd) SEND_CTRL_KEY(hwnd, key_info[2])
2084 #define SEND_CTRL_Z(hwnd) SEND_CTRL_KEY(hwnd, key_info[3])
2085 #define SEND_CTRL_Y(hwnd) SEND_CTRL_KEY(hwnd, key_info[4])
2086
2087     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text1);
2088     SendMessage(hwndRichEdit, EM_SETSEL, 0, 14);
2089
2090     SEND_CTRL_C(hwndRichEdit)   /* Copy */
2091     SendMessage(hwndRichEdit, EM_SETSEL, 14, 14);
2092     SEND_CTRL_V(hwndRichEdit)   /* Paste */
2093     SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2094     /* Pasted text should be visible at this step */
2095     result = strcmp(text1_step1, buffer);
2096     ok(result == 0,
2097         "test paste: strcmp = %i\n", result);
2098     SEND_CTRL_Z(hwndRichEdit)   /* Undo */
2099     SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2100     /* Text should be the same as before (except for \r -> \r\n conversion) */
2101     result = strcmp(text1_after, buffer);
2102     ok(result == 0,
2103         "test paste: strcmp = %i\n", result);
2104
2105     SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) text2);
2106     SendMessage(hwndRichEdit, EM_SETSEL, 8, 13);
2107     SEND_CTRL_C(hwndRichEdit)   /* Copy */
2108     SendMessage(hwndRichEdit, EM_SETSEL, 14, 14);
2109     SEND_CTRL_V(hwndRichEdit)   /* Paste */
2110     SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2111     /* Pasted text should be visible at this step */
2112     result = strcmp(text3, buffer);
2113     ok(result == 0,
2114         "test paste: strcmp = %i\n", result);
2115     SEND_CTRL_Z(hwndRichEdit)   /* Undo */
2116     SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2117     /* Text should be the same as before (except for \r -> \r\n conversion) */
2118     result = strcmp(text2_after, buffer);
2119     ok(result == 0,
2120         "test paste: strcmp = %i\n", result);
2121     SEND_CTRL_Y(hwndRichEdit)   /* Redo */
2122     SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2123     /* Text should revert to post-paste state */
2124     result = strcmp(buffer,text3);
2125     ok(result == 0,
2126         "test paste: strcmp = %i\n", result);
2127
2128     DestroyWindow(hwndRichEdit);
2129 }
2130
2131 static void test_EM_FORMATRANGE(void)
2132 {
2133   int r;
2134   FORMATRANGE fr;
2135   HDC hdc;
2136   HWND hwndRichEdit = new_richedit(NULL);
2137
2138   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) haystack);
2139
2140   hdc = GetDC(hwndRichEdit);
2141   ok(hdc != NULL, "Could not get HDC\n");
2142
2143   fr.hdc = fr.hdcTarget = hdc;
2144   fr.rc.top = fr.rcPage.top = fr.rc.left = fr.rcPage.left = 0;
2145   fr.rc.right = fr.rcPage.right = GetDeviceCaps(hdc, HORZRES);
2146   fr.rc.bottom = fr.rcPage.bottom = GetDeviceCaps(hdc, VERTRES);
2147   fr.chrg.cpMin = 0;
2148   fr.chrg.cpMax = 20;
2149
2150   r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) NULL);
2151   todo_wine {
2152     ok(r == 31, "EM_FORMATRANGE expect %d, got %d\n", 31, r);
2153   }
2154
2155   r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) &fr);
2156   todo_wine {
2157     ok(r == 20, "EM_FORMATRANGE expect %d, got %d\n", 20, r);
2158   }
2159
2160   fr.chrg.cpMin = 0;
2161   fr.chrg.cpMax = 10;
2162
2163   r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) &fr);
2164   todo_wine {
2165     ok(r == 10, "EM_FORMATRANGE expect %d, got %d\n", 10, r);
2166   }
2167
2168   r = SendMessage(hwndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) NULL);
2169   todo_wine {
2170     ok(r == 31, "EM_FORMATRANGE expect %d, got %d\n", 31, r);
2171   }
2172
2173   DestroyWindow(hwndRichEdit);
2174 }
2175
2176 static int nCallbackCount = 0;
2177
2178 static DWORD CALLBACK EditStreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff,
2179                                  LONG cb, LONG* pcb)
2180 {
2181   const char text[] = {'t','e','s','t'};
2182
2183   if (sizeof(text) <= cb)
2184   {
2185     if ((int)dwCookie != nCallbackCount)
2186     {
2187       *pcb = 0;
2188       return 0;
2189     }
2190
2191     memcpy (pbBuff, text, sizeof(text));
2192     *pcb = sizeof(text);
2193
2194     nCallbackCount++;
2195
2196     return 0;
2197   }
2198   else
2199     return 1; /* indicates callback failed */
2200 }
2201
2202 static void test_EM_StreamIn_Undo(void)
2203 {
2204   /* The purpose of this test is to determine when a EM_StreamIn should be
2205    * undoable. This is important because WM_PASTE currently uses StreamIn and
2206    * pasting should always be undoable but streaming isn't always.
2207    *
2208    * cases to test:
2209    * StreamIn plain text without SFF_SELECTION.
2210    * StreamIn plain text with SFF_SELECTION set but a zero-length selection
2211    * StreamIn plain text with SFF_SELECTION and a valid, normal selection
2212    * StreamIn plain text with SFF_SELECTION and a backwards-selection (from>to)
2213    * Feel free to add tests for other text modes or StreamIn things.
2214    */
2215
2216
2217   HWND hwndRichEdit = new_richedit(NULL);
2218   LRESULT result;
2219   EDITSTREAM es;
2220   char buffer[1024] = {0};
2221   const char randomtext[] = "Some text";
2222
2223   es.pfnCallback = (EDITSTREAMCALLBACK) EditStreamCallback;
2224
2225   /* StreamIn, no SFF_SELECTION */
2226   es.dwCookie = nCallbackCount;
2227   SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
2228   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) randomtext);
2229   SendMessage(hwndRichEdit, EM_SETSEL,0,0);
2230   SendMessage(hwndRichEdit, EM_STREAMIN, (WPARAM)SF_TEXT, (LPARAM)&es);
2231   SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2232   result = strcmp (buffer,"test");
2233   ok (result  == 0,
2234       "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer);
2235
2236   result = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
2237   ok (result == FALSE,
2238       "EM_STREAMIN without SFF_SELECTION wrongly allows undo\n");
2239
2240   /* StreamIn, SFF_SELECTION, but nothing selected */
2241   es.dwCookie = nCallbackCount;
2242   SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
2243   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) randomtext);
2244   SendMessage(hwndRichEdit, EM_SETSEL,0,0);
2245   SendMessage(hwndRichEdit, EM_STREAMIN,
2246               (WPARAM)(SF_TEXT|SFF_SELECTION), (LPARAM)&es);
2247   SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2248   result = strcmp (buffer,"testSome text");
2249   ok (result  == 0,
2250       "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
2251
2252   result = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
2253   ok (result == TRUE,
2254      "EM_STREAMIN with SFF_SELECTION but no selection set "
2255       "should create an undo\n");
2256
2257   /* StreamIn, SFF_SELECTION, with a selection */
2258   es.dwCookie = nCallbackCount;
2259   SendMessage(hwndRichEdit,EM_EMPTYUNDOBUFFER, 0,0);
2260   SendMessage(hwndRichEdit, WM_SETTEXT, 0, (LPARAM) randomtext);
2261   SendMessage(hwndRichEdit, EM_SETSEL,4,5);
2262   SendMessage(hwndRichEdit, EM_STREAMIN,
2263               (WPARAM)(SF_TEXT|SFF_SELECTION), (LPARAM)&es);
2264   SendMessage(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM) buffer);
2265   result = strcmp (buffer,"Sometesttext");
2266   ok (result  == 0,
2267       "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
2268
2269   result = SendMessage(hwndRichEdit, EM_CANUNDO, 0, 0);
2270   ok (result == TRUE,
2271       "EM_STREAMIN with SFF_SELECTION and selection set "
2272       "should create an undo\n");
2273
2274 }
2275
2276 static BOOL is_em_settextex_supported(HWND hwnd)
2277 {
2278     SETTEXTEX stex = { ST_DEFAULT, CP_ACP };
2279     return SendMessageA(hwnd, EM_SETTEXTEX, (WPARAM)&stex, 0) != 0;
2280 }
2281
2282 static void test_unicode_conversions(void)
2283 {
2284     static const WCHAR tW[] = {'t',0};
2285     static const WCHAR teW[] = {'t','e',0};
2286     static const WCHAR textW[] = {'t','e','s','t',0};
2287     static const char textA[] = "test";
2288     char bufA[64];
2289     WCHAR bufW[64];
2290     HWND hwnd;
2291     int is_win9x, em_settextex_supported, ret;
2292
2293     is_win9x = GetVersion() & 0x80000000;
2294
2295 #define set_textA(hwnd, wm_set_text, txt) \
2296     do { \
2297         SETTEXTEX stex = { ST_DEFAULT, CP_ACP }; \
2298         WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
2299         assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
2300         ret = SendMessageA(hwnd, wm_set_text, wparam, (LPARAM)txt); \
2301         ok(ret, "SendMessageA(%02x) error %u\n", wm_set_text, GetLastError()); \
2302     } while(0)
2303 #define expect_textA(hwnd, wm_get_text, txt) \
2304     do { \
2305         GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
2306         WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)&gtex; \
2307         assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
2308         memset(bufA, 0xAA, sizeof(bufA)); \
2309         ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
2310         ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
2311         ret = lstrcmpA(bufA, txt); \
2312         ok(!ret, "%02x: strings do not match: expected %s got %s\n", wm_get_text, txt, bufA); \
2313     } while(0)
2314
2315 #define set_textW(hwnd, wm_set_text, txt) \
2316     do { \
2317         SETTEXTEX stex = { ST_DEFAULT, 1200 }; \
2318         WPARAM wparam = (wm_set_text == WM_SETTEXT) ? 0 : (WPARAM)&stex; \
2319         assert(wm_set_text == WM_SETTEXT || wm_set_text == EM_SETTEXTEX); \
2320         ret = SendMessageW(hwnd, wm_set_text, wparam, (LPARAM)txt); \
2321         ok(ret, "SendMessageW(%02x) error %u\n", wm_set_text, GetLastError()); \
2322     } while(0)
2323 #define expect_textW(hwnd, wm_get_text, txt) \
2324     do { \
2325         GETTEXTEX gtex = { 64, GT_DEFAULT, 1200, NULL, NULL }; \
2326         WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)&gtex; \
2327         assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
2328         memset(bufW, 0xAA, sizeof(bufW)); \
2329         if (is_win9x) \
2330         { \
2331             assert(wm_get_text == EM_GETTEXTEX); \
2332             ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
2333             ok(ret, "SendMessageA(%02x) error %u\n", wm_get_text, GetLastError()); \
2334         } \
2335         else \
2336         { \
2337             ret = SendMessageW(hwnd, wm_get_text, wparam, (LPARAM)bufW); \
2338             ok(ret, "SendMessageW(%02x) error %u\n", wm_get_text, GetLastError()); \
2339         } \
2340         ret = lstrcmpW(bufW, txt); \
2341         ok(!ret, "%02x: strings do not match: expected[0] %x got[0] %x\n", wm_get_text, txt[0], bufW[0]); \
2342     } while(0)
2343 #define expect_empty(hwnd, wm_get_text) \
2344     do { \
2345         GETTEXTEX gtex = { 64, GT_DEFAULT, CP_ACP, NULL, NULL }; \
2346         WPARAM wparam = (wm_get_text == WM_GETTEXT) ? 64 : (WPARAM)&gtex; \
2347         assert(wm_get_text == WM_GETTEXT || wm_get_text == EM_GETTEXTEX); \
2348         memset(bufA, 0xAA, sizeof(bufA)); \
2349         ret = SendMessageA(hwnd, wm_get_text, wparam, (LPARAM)bufA); \
2350         ok(!ret, "empty richedit should return 0, got %d\n", ret); \
2351         ok(!*bufA, "empty richedit should return empty string, got %s\n", bufA); \
2352     } while(0)
2353
2354     hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
2355                            0, 0, 200, 60, 0, 0, 0, 0);
2356     ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
2357
2358     ret = IsWindowUnicode(hwnd);
2359     if (is_win9x)
2360         ok(!ret, "RichEdit20W should NOT be unicode under Win9x\n");
2361     else
2362         ok(ret, "RichEdit20W should be unicode under NT\n");
2363
2364     /* EM_SETTEXTEX is supported starting from version 3.0 */
2365     em_settextex_supported = is_em_settextex_supported(hwnd);
2366     trace("EM_SETTEXTEX is %ssupported on this platform\n",
2367           em_settextex_supported ? "" : "NOT ");
2368
2369     expect_empty(hwnd, WM_GETTEXT);
2370     expect_empty(hwnd, EM_GETTEXTEX);
2371
2372     ret = SendMessageA(hwnd, WM_CHAR, (WPARAM)textW[0], 0);
2373     ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret);
2374     expect_textA(hwnd, WM_GETTEXT, "t");
2375     expect_textA(hwnd, EM_GETTEXTEX, "t");
2376     expect_textW(hwnd, EM_GETTEXTEX, tW);
2377
2378     ret = SendMessageA(hwnd, WM_CHAR, (WPARAM)textA[1], 0);
2379     ok(!ret, "SendMessageA(WM_CHAR) should return 0, got %d\n", ret);
2380     expect_textA(hwnd, WM_GETTEXT, "te");
2381     expect_textA(hwnd, EM_GETTEXTEX, "te");
2382     expect_textW(hwnd, EM_GETTEXTEX, teW);
2383
2384     set_textA(hwnd, WM_SETTEXT, NULL);
2385     expect_empty(hwnd, WM_GETTEXT);
2386     expect_empty(hwnd, EM_GETTEXTEX);
2387
2388     if (is_win9x)
2389         set_textA(hwnd, WM_SETTEXT, textW);
2390     else
2391         set_textA(hwnd, WM_SETTEXT, textA);
2392     expect_textA(hwnd, WM_GETTEXT, textA);
2393     expect_textA(hwnd, EM_GETTEXTEX, textA);
2394     expect_textW(hwnd, EM_GETTEXTEX, textW);
2395
2396     if (em_settextex_supported)
2397     {
2398         set_textA(hwnd, EM_SETTEXTEX, textA);
2399         expect_textA(hwnd, WM_GETTEXT, textA);
2400         expect_textA(hwnd, EM_GETTEXTEX, textA);
2401         expect_textW(hwnd, EM_GETTEXTEX, textW);
2402     }
2403
2404     if (!is_win9x)
2405     {
2406         set_textW(hwnd, WM_SETTEXT, textW);
2407         expect_textW(hwnd, WM_GETTEXT, textW);
2408         expect_textA(hwnd, WM_GETTEXT, textA);
2409         expect_textW(hwnd, EM_GETTEXTEX, textW);
2410         expect_textA(hwnd, EM_GETTEXTEX, textA);
2411
2412         if (em_settextex_supported)
2413         {
2414             set_textW(hwnd, EM_SETTEXTEX, textW);
2415             expect_textW(hwnd, WM_GETTEXT, textW);
2416             expect_textA(hwnd, WM_GETTEXT, textA);
2417             expect_textW(hwnd, EM_GETTEXTEX, textW);
2418             expect_textA(hwnd, EM_GETTEXTEX, textA);
2419         }
2420     }
2421     DestroyWindow(hwnd);
2422
2423     hwnd = CreateWindowExA(0, "RichEdit20A", NULL, WS_POPUP,
2424                            0, 0, 200, 60, 0, 0, 0, 0);
2425     ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
2426
2427     ret = IsWindowUnicode(hwnd);
2428     ok(!ret, "RichEdit20A should NOT be unicode\n");
2429
2430     set_textA(hwnd, WM_SETTEXT, textA);
2431     expect_textA(hwnd, WM_GETTEXT, textA);
2432     expect_textA(hwnd, EM_GETTEXTEX, textA);
2433     expect_textW(hwnd, EM_GETTEXTEX, textW);
2434
2435     if (em_settextex_supported)
2436     {
2437         set_textA(hwnd, EM_SETTEXTEX, textA);
2438         expect_textA(hwnd, WM_GETTEXT, textA);
2439         expect_textA(hwnd, EM_GETTEXTEX, textA);
2440         expect_textW(hwnd, EM_GETTEXTEX, textW);
2441     }
2442
2443     if (!is_win9x)
2444     {
2445         set_textW(hwnd, WM_SETTEXT, textW);
2446         expect_textW(hwnd, WM_GETTEXT, textW);
2447         expect_textA(hwnd, WM_GETTEXT, textA);
2448         expect_textW(hwnd, EM_GETTEXTEX, textW);
2449         expect_textA(hwnd, EM_GETTEXTEX, textA);
2450
2451         if (em_settextex_supported)
2452         {
2453             set_textW(hwnd, EM_SETTEXTEX, textW);
2454             expect_textW(hwnd, WM_GETTEXT, textW);
2455             expect_textA(hwnd, WM_GETTEXT, textA);
2456             expect_textW(hwnd, EM_GETTEXTEX, textW);
2457             expect_textA(hwnd, EM_GETTEXTEX, textA);
2458         }
2459     }
2460     DestroyWindow(hwnd);
2461 }
2462
2463 static void test_WM_CHAR(void)
2464 {
2465     HWND hwnd;
2466     int ret;
2467     const char * char_list = "abc\rabc\r";
2468     const char * expected_content_single = "abcabc";
2469     const char * expected_content_multi = "abc\r\nabc\r\n";
2470     char buffer[64] = {0};
2471     const char * p;
2472
2473     /* single-line control must IGNORE carriage returns */
2474     hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
2475                            0, 0, 200, 60, 0, 0, 0, 0);
2476     ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
2477
2478     p = char_list;
2479     while (*p != '\0') {
2480         SendMessageA(hwnd, WM_KEYDOWN, *p, 1);
2481         ret = SendMessageA(hwnd, WM_CHAR, *p, 1);
2482         ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *p, ret);
2483         SendMessageA(hwnd, WM_KEYUP, *p, 1);
2484         p++;
2485     }
2486
2487     SendMessage(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2488     ret = strcmp(buffer, expected_content_single);
2489     ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n");
2490
2491     DestroyWindow(hwnd);
2492
2493     /* multi-line control inserts CR normally */
2494     hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP|ES_MULTILINE,
2495                            0, 0, 200, 60, 0, 0, 0, 0);
2496     ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
2497
2498     p = char_list;
2499     while (*p != '\0') {
2500         SendMessageA(hwnd, WM_KEYDOWN, *p, 1);
2501         ret = SendMessageA(hwnd, WM_CHAR, *p, 1);
2502         ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *p, ret);
2503         SendMessageA(hwnd, WM_KEYUP, *p, 1);
2504         p++;
2505     }
2506
2507     SendMessage(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2508     ret = strcmp(buffer, expected_content_multi);
2509     ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n");
2510
2511     DestroyWindow(hwnd);
2512 }
2513
2514 static void test_EM_GETTEXTLENGTHEX(void)
2515 {
2516     HWND hwnd;
2517     GETTEXTLENGTHEX gtl;
2518     int ret;
2519     const char * base_string = "base string";
2520     const char * test_string = "a\nb\n\n\r\n";
2521     const char * test_string_after = "a";
2522     const char * test_string_2 = "a\rtest\rstring";
2523     char buffer[64] = {0};
2524
2525     /* single line */
2526     hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP,
2527                            0, 0, 200, 60, 0, 0, 0, 0);
2528     ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
2529
2530     gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2531     gtl.codepage = CP_ACP;
2532     ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2533     ok(ret == 0, "ret %d\n",ret);
2534
2535     gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2536     gtl.codepage = CP_ACP;
2537     ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2538     ok(ret == 0, "ret %d\n",ret);
2539
2540     SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) base_string);
2541
2542     gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2543     gtl.codepage = CP_ACP;
2544     ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2545     ok(ret == strlen(base_string), "ret %d\n",ret);
2546
2547     gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2548     gtl.codepage = CP_ACP;
2549     ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2550     ok(ret == strlen(base_string), "ret %d\n",ret);
2551
2552     SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) test_string);
2553
2554     gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2555     gtl.codepage = CP_ACP;
2556     ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2557     ok(ret == 1, "ret %d\n",ret);
2558
2559     gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2560     gtl.codepage = CP_ACP;
2561     ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2562     ok(ret == 1, "ret %d\n",ret);
2563
2564     SendMessage(hwnd, WM_GETTEXT, sizeof(buffer), (LPARAM)buffer);
2565     ret = strcmp(buffer, test_string_after);
2566     ok(ret == 0, "WM_GETTEXT recovered incorrect string!\n");
2567
2568     DestroyWindow(hwnd);
2569
2570     /* multi line */
2571     hwnd = CreateWindowExA(0, "RichEdit20W", NULL, WS_POPUP | ES_MULTILINE,
2572                            0, 0, 200, 60, 0, 0, 0, 0);
2573     ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
2574
2575     gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2576     gtl.codepage = CP_ACP;
2577     ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2578     ok(ret == 0, "ret %d\n",ret);
2579
2580     gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2581     gtl.codepage = CP_ACP;
2582     ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2583     ok(ret == 0, "ret %d\n",ret);
2584
2585     SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) base_string);
2586
2587     gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2588     gtl.codepage = CP_ACP;
2589     ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2590     ok(ret == strlen(base_string), "ret %d\n",ret);
2591
2592     gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2593     gtl.codepage = CP_ACP;
2594     ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2595     ok(ret == strlen(base_string), "ret %d\n",ret);
2596
2597     SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) test_string_2);
2598
2599     gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2600     gtl.codepage = CP_ACP;
2601     ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2602     ok(ret == strlen(test_string_2) + 2, "ret %d\n",ret);
2603
2604     gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2605     gtl.codepage = CP_ACP;
2606     ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2607     ok(ret == strlen(test_string_2), "ret %d\n",ret);
2608
2609     SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM) test_string);
2610
2611     gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
2612     gtl.codepage = CP_ACP;
2613     ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2614     ok(ret == 10, "ret %d\n",ret);
2615
2616     gtl.flags = GTL_NUMCHARS | GTL_PRECISE;
2617     gtl.codepage = CP_ACP;
2618     ret = SendMessageA(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
2619     ok(ret == 6, "ret %d\n",ret);
2620
2621     DestroyWindow(hwnd);
2622 }
2623
2624
2625 /* globals that parent and child access when checking event masks & notifications */
2626 static HWND eventMaskEditHwnd = 0;
2627 static int queriedEventMask;
2628 static int watchForEventMask = 0;
2629
2630 /* parent proc that queries the edit's event mask when it gets a WM_COMMAND */
2631 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2632 {
2633     if(message == WM_COMMAND && (watchForEventMask & (wParam >> 16)))
2634     {
2635       queriedEventMask = SendMessage(eventMaskEditHwnd, EM_GETEVENTMASK, 0, 0);
2636     }
2637     return DefWindowProcA(hwnd, message, wParam, lParam);
2638 }
2639
2640 /* test event masks in combination with WM_COMMAND */
2641 static void test_eventMask(void)
2642 {
2643     HWND parent;
2644     int ret;
2645     WNDCLASSA cls;
2646     const char text[] = "foo bar\n";
2647     int eventMask;
2648
2649     /* register class to capture WM_COMMAND */
2650     cls.style = 0;
2651     cls.lpfnWndProc = ParentMsgCheckProcA;
2652     cls.cbClsExtra = 0;
2653     cls.cbWndExtra = 0;
2654     cls.hInstance = GetModuleHandleA(0);
2655     cls.hIcon = 0;
2656     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
2657     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
2658     cls.lpszMenuName = NULL;
2659     cls.lpszClassName = "EventMaskParentClass";
2660     if(!RegisterClassA(&cls)) assert(0);
2661
2662     parent = CreateWindow(cls.lpszClassName, NULL, WS_POPUP|WS_VISIBLE,
2663                           0, 0, 200, 60, NULL, NULL, NULL, NULL);
2664     ok (parent != 0, "Failed to create parent window\n");
2665
2666     eventMaskEditHwnd = new_richedit(parent);
2667     ok(eventMaskEditHwnd != 0, "Failed to create edit window\n");
2668
2669     eventMask = ENM_CHANGE | ENM_UPDATE;
2670     ret = SendMessage(eventMaskEditHwnd, EM_SETEVENTMASK, 0, (LPARAM) eventMask);
2671     ok(ret == ENM_NONE, "wrong event mask\n");
2672     ret = SendMessage(eventMaskEditHwnd, EM_GETEVENTMASK, 0, 0);
2673     ok(ret == eventMask, "failed to set event mask\n");
2674
2675     /* check what happens when we ask for EN_CHANGE and send WM_SETTEXT */
2676     queriedEventMask = 0;  /* initialize to something other than we expect */
2677     watchForEventMask = EN_CHANGE;
2678     ret = SendMessage(eventMaskEditHwnd, WM_SETTEXT, 0, (LPARAM) text);
2679     ok(ret == TRUE, "failed to set text\n");
2680     /* richedit should mask off ENM_CHANGE when it sends an EN_CHANGE
2681        notification in response to WM_SETTEXT */
2682     ok(queriedEventMask == (eventMask & ~ENM_CHANGE),
2683             "wrong event mask (0x%x) during WM_COMMAND\n", queriedEventMask);
2684
2685 }
2686
2687
2688 START_TEST( editor )
2689 {
2690   MSG msg;
2691   time_t end;
2692
2693   /* Must explicitly LoadLibrary(). The test has no references to functions in
2694    * RICHED20.DLL, so the linker doesn't actually link to it. */
2695   hmoduleRichEdit = LoadLibrary("RICHED20.DLL");
2696   ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError());
2697
2698   test_WM_CHAR();
2699   test_EM_FINDTEXT();
2700   test_EM_GETLINE();
2701   test_EM_SCROLLCARET();
2702   test_EM_SCROLL();
2703   test_WM_SETTEXT();
2704   test_EM_SETCHARFORMAT();
2705   test_EM_SETTEXTMODE();
2706   test_TM_PLAINTEXT();
2707   test_EM_SETOPTIONS();
2708   test_WM_GETTEXT();
2709   test_EM_AUTOURLDETECT();
2710   test_EM_SETUNDOLIMIT();
2711   test_ES_PASSWORD();
2712   test_EM_SETTEXTEX();
2713   test_EM_LIMITTEXT();
2714   test_EM_EXLIMITTEXT();
2715   test_EM_GETLIMITTEXT();
2716   test_WM_SETFONT();
2717   test_EM_GETMODIFY();
2718   test_EM_EXSETSEL();
2719   test_WM_PASTE();
2720   test_EM_StreamIn_Undo();
2721   test_EM_FORMATRANGE();
2722   test_unicode_conversions();
2723   test_EM_GETTEXTLENGTHEX();
2724   test_EM_REPLACESEL();
2725   test_eventMask();
2726
2727   /* Set the environment variable WINETEST_RICHED20 to keep windows
2728    * responsive and open for 30 seconds. This is useful for debugging.
2729    *
2730    * The message pump uses PeekMessage() to empty the queue and then sleeps for
2731    * 50ms before retrying the queue. */
2732   end = time(NULL) + 30;
2733   if (getenv( "WINETEST_RICHED20" )) {
2734     while (time(NULL) < end) {
2735       if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
2736         TranslateMessage(&msg);
2737         DispatchMessage(&msg);
2738       } else {
2739         Sleep(50);
2740       }
2741     }
2742   }
2743
2744   OleFlushClipboard();
2745   ok(FreeLibrary(hmoduleRichEdit) != 0, "error: %d\n", (int) GetLastError());
2746 }