ReactOS  0.4.14-dev-390-g34947ad
editor.c
Go to the documentation of this file.
1 /*
2 * Unit test suite for rich edit control 1.0
3 *
4 * Copyright 2006 Google (Thomas Kho)
5 * Copyright 2007 Matt Finnicum
6 * Copyright 2007 Dmitry Timoshkov
7 * Copyright 2007 Alex VillacĂ­s Lasso
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23 
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <windef.h>
27 #include <winbase.h>
28 #include <wingdi.h>
29 #include <winuser.h>
30 #include <winnls.h>
31 #include <ole2.h>
32 #include <commdlg.h>
33 #include <richedit.h>
34 #include <time.h>
35 #include <wine/test.h>
36 
39 
40 static HWND new_window(LPCSTR lpClassName, DWORD dwStyle, HWND parent) {
41  HWND hwnd;
42  hwnd = CreateWindowA(lpClassName, NULL, dwStyle|WS_POPUP|WS_HSCROLL|WS_VSCROLL
43  |WS_VISIBLE, 0, 0, 500, 60, parent, NULL,
45  ok(hwnd != NULL, "class: %s, error: %d\n", lpClassName, (int) GetLastError());
46  return hwnd;
47 }
48 
51 }
52 
53 static BOOL is_rtl(void) {
54  LOCALESIGNATURE sig;
55 
57  (LPSTR) &sig, sizeof(LOCALESIGNATURE)) &&
58  (sig.lsUsb[3] & 0x08000000) != 0);
59 }
60 
61 static void test_WM_SETTEXT(void)
62 {
63  static const struct {
64  const char *itemtext;
65  DWORD lines;
66  DWORD lines_rtl;
67  DWORD lines_broken;
68  } testitems[] = {
69  { "TestSomeText", 1, 1},
70  { "TestSomeText\r", 1, 1},
71  { "TestSomeText\rSomeMoreText\r", 2, 1, 1}, /* NT4 and below */
72  { "TestSomeText\n\nTestSomeText", 3, 3},
73  { "TestSomeText\r\r\nTestSomeText", 2, 2},
74  { "TestSomeText\r\r\n\rTestSomeText", 3, 2, 2}, /* NT4 and below */
75  { "TestSomeText\r\n\r\r\n\rTestSomeText", 4, 3, 3}, /* NT4 and below */
76  { "TestSomeText\r\n", 2, 2},
77  { "TestSomeText\r\nSomeMoreText\r\n", 3, 3},
78  { "TestSomeText\r\n\r\nTestSomeText", 3, 3},
79  { "TestSomeText TestSomeText", 1, 1},
80  { "TestSomeText \r\nTestSomeText", 2, 2},
81  { "TestSomeText\r\n \r\nTestSomeText", 3, 3},
82  { "TestSomeText\n", 2, 2},
83  { "TestSomeText\r\r\r", 3, 1, 1}, /* NT4 and below */
84  { "TestSomeText\r\r\rSomeMoreText", 4, 1, 1} /* NT4 and below */
85  };
86  HWND hwndRichEdit = new_richedit(NULL);
87  int i;
88  BOOL rtl = is_rtl();
89 
90  /* This test attempts to show that WM_SETTEXT on a riched32 control does not
91  * attempt to modify the text that is pasted into the control, and should
92  * return it as is. In particular, \r\r\n is NOT converted, unlike riched20.
93  *
94  * For riched32, the rules for breaking lines seem to be the following:
95  * - \r\n is one line break. This is the normal case.
96  * - \r{0,2}\n is one line break. In particular, \n by itself is a line break.
97  * - \r{0,N-1}\r\r\n is N line breaks.
98  * - \n{1,N} are that many line breaks.
99  * - \r with text or other characters (except \n) past it, is a line break. That
100  * is, a run of \r{N} without a terminating \n is considered N line breaks
101  * - \r at the end of the text is NOT a line break. This differs from riched20,
102  * where \r at the end of the text is a proper line break.
103  * However, on RTL language versions, \r is simply skipped and never used
104  * for line breaking (only \n adds a line break)
105  */
106 
107  for (i = 0; i < ARRAY_SIZE(testitems); i++) {
108 
109  char buf[1024] = {0};
110  LRESULT result;
111 
112  result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)testitems[i].itemtext);
113  ok (result == 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i, result);
114  result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf);
115  ok (result == lstrlenA(buf),
116  "[%d] WM_GETTEXT returned %ld instead of expected %u\n",
117  i, result, lstrlenA(buf));
118  result = strcmp(testitems[i].itemtext, buf);
119  ok (result == 0,
120  "[%d] WM_SETTEXT round trip: strcmp = %ld\n", i, result);
121  result = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
122  ok (result == (rtl ? testitems[i].lines_rtl : testitems[i].lines) ||
123  broken(testitems[i].lines_broken && result == testitems[i].lines_broken),
124  "[%d] EM_GETLINECOUNT returned %ld, expected %d\n", i, result, testitems[i].lines);
125  }
126 
127  DestroyWindow(hwndRichEdit);
128 }
129 
130 static void test_WM_GETTEXTLENGTH(void)
131 {
132  HWND hwndRichEdit = new_richedit(NULL);
133  static const char text1[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee";
134  static const char text2[] = "aaa\r\nbbb\r\nccc\r\nddd\r\neee\r\n";
135  static const char text3[] = "abcdef\x8e\xf0";
136  int result;
137 
138  /* Test for WM_GETTEXTLENGTH */
139  SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
140  result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
141  ok(result == lstrlenA(text1),
142  "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
143  result, lstrlenA(text1));
144 
145  SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
146  result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
147  ok(result == lstrlenA(text2),
148  "WM_GETTEXTLENGTH reports incorrect length %d, expected %d\n",
149  result, lstrlenA(text2));
150 
151  /* Test with multibyte character */
152  if (!is_lang_japanese)
153  skip("Skip multibyte character tests on non-Japanese platform\n");
154  else
155  {
156  SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text3);
157  result = SendMessageA(hwndRichEdit, WM_GETTEXTLENGTH, 0, 0);
158  ok(result == 8, "WM_GETTEXTLENGTH returned %d, expected 8\n", result);
159  }
160 
161  DestroyWindow(hwndRichEdit);
162 }
163 
165  LPBYTE pbBuff,
166  LONG cb,
167  LONG *pcb)
168 {
169  const char** str = (const char**)dwCookie;
170  int size = strlen(*str);
171  *pcb = cb;
172  if (*pcb > size) {
173  *pcb = size;
174  }
175  if (*pcb > 0) {
176  memcpy(pbBuff, *str, *pcb);
177  *str += *pcb;
178  }
179  return 0;
180 }
181 
182 
183 static void test_EM_STREAMIN(void)
184 {
185  HWND hwndRichEdit = new_richedit(NULL);
186  LRESULT result;
187  EDITSTREAM es;
188  char buffer[1024] = {0};
189 
190  const char * streamText0 = "{\\rtf1 TestSomeText}";
191  const char * streamText0a = "{\\rtf1 TestSomeText\\par}";
192  const char * streamText0b = "{\\rtf1 TestSomeText\\par\\par}";
193 
194  const char * streamText1 =
195  "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang12298{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset0 System;}}\r\n"
196  "\\viewkind4\\uc1\\pard\\f0\\fs17 TestSomeText\\par\r\n"
197  "}\r\n";
198 
199  /* This should be accepted in richedit 1.0 emulation. See bug #8326 */
200  const char * streamText2 =
201  "{{\\colortbl;\\red0\\green255\\blue102;\\red255\\green255\\blue255;"
202  "\\red170\\green255\\blue255;\\red255\\green238\\blue0;\\red51\\green255"
203  "\\blue221;\\red238\\green238\\blue238;}\\tx0 \\tx424 \\tx848 \\tx1272 "
204  "\\tx1696 \\tx2120 \\tx2544 \\tx2968 \\tx3392 \\tx3816 \\tx4240 \\tx4664 "
205  "\\tx5088 \\tx5512 \\tx5936 \\tx6360 \\tx6784 \\tx7208 \\tx7632 \\tx8056 "
206  "\\tx8480 \\tx8904 \\tx9328 \\tx9752 \\tx10176 \\tx10600 \\tx11024 "
207  "\\tx11448 \\tx11872 \\tx12296 \\tx12720 \\tx13144 \\cf2 RichEdit1\\line }";
208 
209  const char * streamText3 = "RichEdit1";
210 
211  /* Minimal test without \par at the end */
212  es.dwCookie = (DWORD_PTR)&streamText0;
213  es.dwError = 0;
214  es.pfnCallback = test_EM_STREAMIN_esCallback;
215  SendMessageA(hwndRichEdit, EM_STREAMIN,
216  (WPARAM)(SF_RTF), (LPARAM)&es);
217 
218  result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
219  ok (result == 12,
220  "EM_STREAMIN: Test 0 returned %ld, expected 12\n", result);
221  result = strcmp (buffer,"TestSomeText");
222  ok (result == 0,
223  "EM_STREAMIN: Test 0 set wrong text: Result: %s\n",buffer);
224  ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0);
225 
226  /* Native richedit 2.0 ignores last \par */
227  es.dwCookie = (DWORD_PTR)&streamText0a;
228  es.dwError = 0;
229  es.pfnCallback = test_EM_STREAMIN_esCallback;
230  SendMessageA(hwndRichEdit, EM_STREAMIN,
231  (WPARAM)(SF_RTF), (LPARAM)&es);
232 
233  result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
234  ok (result == 12,
235  "EM_STREAMIN: Test 0-a returned %ld, expected 12\n", result);
236  result = strcmp (buffer,"TestSomeText");
237  ok (result == 0,
238  "EM_STREAMIN: Test 0-a set wrong text: Result: %s\n",buffer);
239  ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0);
240 
241  /* Native richedit 2.0 ignores last \par, next-to-last \par appears */
242  es.dwCookie = (DWORD_PTR)&streamText0b;
243  es.dwError = 0;
244  es.pfnCallback = test_EM_STREAMIN_esCallback;
245  SendMessageA(hwndRichEdit, EM_STREAMIN,
246  (WPARAM)(SF_RTF), (LPARAM)&es);
247 
248  result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
249  ok (result == 14,
250  "EM_STREAMIN: Test 0-b returned %ld, expected 14\n", result);
251  result = strcmp (buffer,"TestSomeText\r\n");
252  ok (result == 0,
253  "EM_STREAMIN: Test 0-b set wrong text: Result: %s\n",buffer);
254  ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0);
255 
256  es.dwCookie = (DWORD_PTR)&streamText1;
257  es.dwError = 0;
258  es.pfnCallback = test_EM_STREAMIN_esCallback;
259  SendMessageA(hwndRichEdit, EM_STREAMIN,
260  (WPARAM)(SF_RTF), (LPARAM)&es);
261 
262  result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
263  ok (result == 12,
264  "EM_STREAMIN: Test 1 returned %ld, expected 12\n", result);
265  result = strcmp (buffer,"TestSomeText");
266  ok (result == 0,
267  "EM_STREAMIN: Test 1 set wrong text: Result: %s\n",buffer);
268  ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0);
269 
270 
271  es.dwCookie = (DWORD_PTR)&streamText2;
272  es.dwError = 0;
273  SendMessageA(hwndRichEdit, EM_STREAMIN,
274  (WPARAM)(SF_RTF), (LPARAM)&es);
275 
276  result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
277  todo_wine {
278  ok (result == 9,
279  "EM_STREAMIN: Test 2 returned %ld, expected 9\n", result);
280  }
281  result = strcmp (buffer,"RichEdit1");
282  todo_wine {
283  ok (result == 0,
284  "EM_STREAMIN: Test 2 set wrong text: Result: %s\n",buffer);
285  }
286  ok(es.dwError == 0, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, 0);
287 
288  es.dwCookie = (DWORD_PTR)&streamText3;
289  es.dwError = 0;
290  SendMessageA(hwndRichEdit, EM_STREAMIN,
291  (WPARAM)(SF_RTF), (LPARAM)&es);
292 
293  result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buffer);
294  ok (result == 0,
295  "EM_STREAMIN: Test 3 returned %ld, expected 0\n", result);
296  ok (strlen(buffer) == 0,
297  "EM_STREAMIN: Test 3 set wrong text: Result: %s\n",buffer);
298  ok(es.dwError == -16, "EM_STREAMIN: Test 0 set error %d, expected %d\n", es.dwError, -16);
299 
300  DestroyWindow(hwndRichEdit);
301 }
302 
304  LPBYTE pbBuff,
305  LONG cb,
306  LONG *pcb)
307 {
308  char** str = (char**)dwCookie;
309  *pcb = cb;
310  if (*pcb > 0) {
311  memcpy(*str, pbBuff, *pcb);
312  *str += *pcb;
313  }
314  return 0;
315 }
316 
317 static void test_EM_STREAMOUT(void)
318 {
319  HWND hwndRichEdit = new_richedit(NULL);
320  int r;
321  EDITSTREAM es;
322  char buf[1024] = {0};
323  char * p;
324 
325  const char * TestItem1 = "TestSomeText";
326  const char * TestItem2 = "TestSomeText\r";
327  const char * TestItem3 = "TestSomeText\r\n";
328 
329  SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem1);
330  p = buf;
331  es.dwCookie = (DWORD_PTR)&p;
332  es.dwError = 0;
333  es.pfnCallback = test_WM_SETTEXT_esCallback;
334  memset(buf, 0, sizeof(buf));
335  SendMessageA(hwndRichEdit, EM_STREAMOUT,
336  (WPARAM)(SF_TEXT), (LPARAM)&es);
337  r = strlen(buf);
338  ok(r == 12, "streamed text length is %d, expecting 12\n", r);
339  ok(strcmp(buf, TestItem1) == 0,
340  "streamed text different, got %s\n", buf);
341 
342  SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem2);
343  p = buf;
344  es.dwCookie = (DWORD_PTR)&p;
345  es.dwError = 0;
346  es.pfnCallback = test_WM_SETTEXT_esCallback;
347  memset(buf, 0, sizeof(buf));
348  SendMessageA(hwndRichEdit, EM_STREAMOUT,
349  (WPARAM)(SF_TEXT), (LPARAM)&es);
350  r = strlen(buf);
351 
352  ok(r == 13, "streamed text length is %d, expecting 13\n", r);
353  ok(strcmp(buf, TestItem2) == 0,
354  "streamed text different, got %s\n", buf);
355 
356  SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)TestItem3);
357  p = buf;
358  es.dwCookie = (DWORD_PTR)&p;
359  es.dwError = 0;
360  es.pfnCallback = test_WM_SETTEXT_esCallback;
361  memset(buf, 0, sizeof(buf));
362  SendMessageA(hwndRichEdit, EM_STREAMOUT,
363  (WPARAM)(SF_TEXT), (LPARAM)&es);
364  r = strlen(buf);
365  ok(r == 14, "streamed text length is %d, expecting 14\n", r);
366  ok(strcmp(buf, TestItem3) == 0,
367  "streamed text different, got %s\n", buf);
368 
369  DestroyWindow(hwndRichEdit);
370 }
371 
372 static const struct getline_s {
373  int line;
374  size_t buffer_len;
375  const char *text;
376  const char *broken_text;
377 } gl[] = {
378  {0, 10, "foo bar\r\n", "foo bar\r\n"},
379  {1, 10, "\r", "\r\r\r\n"},
380  {2, 10, "\r\r\n", "bar\n"},
381  {3, 10, "bar\n", "\r\n"},
382  {4, 10, "\r\n"},
383 
384  /* Buffer smaller than line length */
385  {0, 2, "foo bar\r"},
386  {0, 1, "foo bar\r"},
387  {0, 0, "foo bar\r"}
388 };
389 
390 static void test_EM_GETLINE(void)
391 {
392  int i;
393  HWND hwndRichEdit = new_richedit(NULL);
394  static const int nBuf = 1024;
395  char dest[1024], origdest[1024];
396  LRESULT linecount;
397  const char text[] = "foo bar\r\n"
398  "\r"
399  "\r\r\n"
400  "bar\n";
401  BOOL broken_os = FALSE;
402  BOOL rtl = is_rtl();
403 
404  SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
405  linecount = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
406  if (linecount == 4)
407  {
408  broken_os = TRUE;
409  win_skip("Win9x, WinME and NT4 handle '\\r only' differently\n");
410  }
411 
412  memset(origdest, 0xBB, nBuf);
413  for (i = 0; i < ARRAY_SIZE(gl); i++)
414  {
415  int nCopied, expected_nCopied, expected_bytes_written;
416  char gl_text[1024];
417 
418  if (gl[i].line >= linecount)
419  continue; /* Win9x, WinME and NT4 */
420 
421  if (broken_os && gl[i].broken_text)
422  /* Win9x, WinME and NT4 */
423  strcpy(gl_text, gl[i].broken_text);
424  else
425  strcpy(gl_text, gl[i].text);
426 
427  expected_nCopied = min(gl[i].buffer_len, strlen(gl_text));
428  /* Cater for the fact that Win9x, WinME and NT4 don't append the '\0' */
429  expected_bytes_written = min(gl[i].buffer_len, strlen(gl_text) + (broken_os ? 0 : 1));
430 
431  memset(dest, 0xBB, nBuf);
432  *(WORD *) dest = gl[i].buffer_len;
433 
434  /* EM_GETLINE appends a "\r\0" to the end of the line
435  * nCopied counts up to and including the '\r' */
436  nCopied = SendMessageA(hwndRichEdit, EM_GETLINE, gl[i].line, (LPARAM)dest);
437  ok(nCopied == expected_nCopied, "%d: %d!=%d\n", i, nCopied,
438  expected_nCopied);
439  /* two special cases since a parameter is passed via dest */
440  if (gl[i].buffer_len == 0)
441  ok(!dest[0] && !dest[1] && !strncmp(dest+2, origdest+2, nBuf-2),
442  "buffer_len=0\n");
443  else if (gl[i].buffer_len == 1)
444  ok(dest[0] == gl_text[0] && !dest[1] &&
445  !strncmp(dest+2, origdest+2, nBuf-2), "buffer_len=1\n");
446  else
447  {
448  ok(!strncmp(dest, gl_text, expected_bytes_written),
449  "%d: expected_bytes_written=%d\n", i, expected_bytes_written);
450  if (! rtl || expected_bytes_written == gl[i].buffer_len)
451  ok(!strncmp(dest + expected_bytes_written, origdest
452  + expected_bytes_written, nBuf - expected_bytes_written),
453  "%d: expected_bytes_written=%d\n", i, expected_bytes_written);
454  else
455  ok(dest[expected_bytes_written] == 0 &&
456  !strncmp(dest + expected_bytes_written + 1, origdest
457  + expected_bytes_written + 1, nBuf - (expected_bytes_written + 1)),
458  "%d: expected_bytes_written=%d\n", i, expected_bytes_written);
459  }
460  }
461 
462  DestroyWindow(hwndRichEdit);
463 }
464 
465 static void test_EM_LINELENGTH(void)
466 {
467  HWND hwndRichEdit = new_richedit(NULL);
468  const char * text =
469  "richedit1\r"
470  "richedit1\n"
471  "richedit1\r\n"
472  "short\r"
473  "richedit1\r"
474  "\r"
475  "\r"
476  "\r\r\n";
477  int offset_test[16][2] = {
478  {0, 9}, /* Line 1: |richedit1\r */
479  {5, 9}, /* Line 1: riche|dit1\r */
480  {10, 9}, /* Line 2: |richedit1\n */
481  {15, 9}, /* Line 2: riche|dit1\n */
482  {20, 9}, /* Line 3: |richedit1\r\n */
483  {25, 9}, /* Line 3: riche|dit1\r\n */
484  {30, 9}, /* Line 3: richedit1\r|\n */
485  {31, 5}, /* Line 4: |short\r */
486  {42, 9}, /* Line 5: riche|dit1\r */
487  {46, 9}, /* Line 5: richedit1|\r */
488  {47, 0}, /* Line 6: |\r */
489  {48, 0}, /* Line 7: |\r */
490  {49, 0}, /* Line 8: |\r\r\n */
491  {50, 0}, /* Line 8: \r|\r\n */
492  {51, 0}, /* Line 8: \r\r|\n */
493  {52, 0}, /* Line 9: \r\r\n| */
494  };
495  int i;
496  LRESULT result;
497 
498  SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
499 
500  result = SendMessageA(hwndRichEdit, EM_GETLINECOUNT, 0, 0);
501  if (result == 4) {
502  win_skip("Win9x, WinME and NT4 don't handle '\\r only' correctly\n");
503  return;
504  }
505  ok(result == 9, "Incorrect line count of %ld\n", result);
506 
507  for (i = 0; i < ARRAY_SIZE(offset_test); i++) {
508  result = SendMessageA(hwndRichEdit, EM_LINELENGTH, offset_test[i][0], 0);
509  ok(result == offset_test[i][1], "Length of line at offset %d is %ld, expected %d\n",
510  offset_test[i][0], result, offset_test[i][1]);
511  }
512 
513  /* Test with multibyte character */
514  if (!is_lang_japanese)
515  skip("Skip multibyte character tests on non-Japanese platform\n");
516  else
517  {
518  const char *text1 =
519  "wine\n"
520  "richedit\x8e\xf0\n"
521  "wine";
522  static int offset_test1[3][3] = {
523  {0, 4}, /* Line 1: |wine\n */
524  {5, 10, 1}, /* Line 2: |richedit\x8e\xf0\n */
525  {16, 4}, /* Line 3: |wine */
526  };
527  SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
528  for (i = 0; i < ARRAY_SIZE(offset_test1); i++) {
529  result = SendMessageA(hwndRichEdit, EM_LINELENGTH, offset_test1[i][0], 0);
530  todo_wine_if (offset_test1[i][2])
531  ok(result == offset_test1[i][1], "Length of line at offset %d is %ld, expected %d\n",
532  offset_test1[i][0], result, offset_test1[i][1]);
533  }
534  }
535 
536  DestroyWindow(hwndRichEdit);
537 }
538 
539 static void test_EM_GETTEXTRANGE(void)
540 {
541  HWND hwndRichEdit = new_richedit(NULL);
542  const char * text1 = "foo bar\r\nfoo bar";
543  const char * text3 = "foo bar\rfoo bar";
544  const char * expect1 = "bar\r\nfoo";
545  const char * expect2 = "\nfoo";
546  const char * expect3 = "bar\rfoo";
547  char buffer[1024] = {0};
548  LRESULT result;
549  TEXTRANGEA textRange;
550 
551  SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
552 
553  textRange.lpstrText = buffer;
554  textRange.chrg.cpMin = 4;
555  textRange.chrg.cpMax = 12;
556  result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
557  ok(result == 8, "EM_GETTEXTRANGE returned %ld\n", result);
558  ok(!strcmp(expect1, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
559 
560  textRange.lpstrText = buffer;
561  textRange.chrg.cpMin = 8;
562  textRange.chrg.cpMax = 12;
563  result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
564  ok(result == 4, "EM_GETTEXTRANGE returned %ld\n", result);
565  ok(!strcmp(expect2, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
566 
567  SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text3);
568 
569  textRange.lpstrText = buffer;
570  textRange.chrg.cpMin = 4;
571  textRange.chrg.cpMax = 11;
572  result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
573  ok(result == 7, "EM_GETTEXTRANGE returned %ld\n", result);
574 
575  ok(!strcmp(expect3, buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
576 
577  /* Test with multibyte character */
578  if (!is_lang_japanese)
579  skip("Skip multibyte character tests on non-Japanese platform\n");
580  else
581  {
582  SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk");
583  textRange.chrg.cpMin = 4;
584  textRange.chrg.cpMax = 8;
585  result = SendMessageA(hwndRichEdit, EM_GETTEXTRANGE, 0, (LPARAM)&textRange);
586  ok(result == 4, "EM_GETTEXTRANGE returned %ld\n", result);
587  todo_wine ok(!strcmp("ef\x8e\xf0", buffer), "EM_GETTEXTRANGE filled %s\n", buffer);
588  }
589 
590  DestroyWindow(hwndRichEdit);
591 }
592 
593 static void test_EM_GETSELTEXT(void)
594 {
595  HWND hwndRichEdit = new_richedit(NULL);
596  const char * text1 = "foo bar\r\nfoo bar";
597  const char * text2 = "foo bar\rfoo bar";
598  const char * expect1 = "bar\r\nfoo";
599  const char * expect2 = "bar\rfoo";
600  char buffer[1024] = {0};
601  LRESULT result;
602 
603  SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text1);
604 
605  SendMessageA(hwndRichEdit, EM_SETSEL, 4, 12);
606  result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
607  ok(result == 8, "EM_GETSELTEXT returned %ld\n", result);
608  ok(!strcmp(expect1, buffer), "EM_GETSELTEXT filled %s\n", buffer);
609 
610  SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text2);
611 
612  SendMessageA(hwndRichEdit, EM_SETSEL, 4, 11);
613  result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
614  ok(result == 7, "EM_GETSELTEXT returned %ld\n", result);
615  ok(!strcmp(expect2, buffer), "EM_GETSELTEXT filled %s\n", buffer);
616 
617  /* Test with multibyte character */
618  if (!is_lang_japanese)
619  skip("Skip multibyte character tests on non-Japanese platform\n");
620  else
621  {
622  SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk");
623  SendMessageA(hwndRichEdit, EM_SETSEL, 4, 8);
624  result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffer);
625  ok(result == 4, "EM_GETSELTEXT returned %ld\n", result);
626  todo_wine ok(!strcmp("ef\x8e\xf0", buffer), "EM_GETSELTEXT filled %s\n", buffer);
627  }
628 
629  DestroyWindow(hwndRichEdit);
630 }
631 
632 static const char haystack[] = "WINEWine wineWine wine WineWine";
633  /* ^0 ^10 ^20 ^30 */
634 
635 static const char haystack2[] = "first\r\r\nsecond";
636 
637 struct find_s {
638  int start;
639  int end;
640  const char *needle;
641  int flags;
642  int expected_loc;
643 };
644 
645 
646 static struct find_s find_tests[] = {
647  /* Find in empty text */
648  {0, -1, "foo", FR_DOWN, -1},
649  {0, -1, "foo", 0, -1},
650  {0, -1, "", FR_DOWN, -1},
651  {20, 5, "foo", FR_DOWN, -1},
652  {5, 20, "foo", FR_DOWN, -1}
653 };
654 
655 static struct find_s find_tests2[] = {
656  /* No-result find */
657  {0, -1, "foo", FR_DOWN | FR_MATCHCASE, -1},
658  {5, 20, "WINE", FR_DOWN | FR_MATCHCASE, -1},
659 
660  /* Subsequent finds */
661  {0, -1, "Wine", FR_DOWN | FR_MATCHCASE, 4},
662  {5, 31, "Wine", FR_DOWN | FR_MATCHCASE, 13},
663  {14, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23},
664  {24, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27},
665 
666  /* Find backwards */
667  {19, 20, "Wine", FR_MATCHCASE, -1},
668  {10, 20, "Wine", FR_MATCHCASE, 13},
669  {20, 10, "Wine", FR_MATCHCASE, -1},
670 
671  /* Case-insensitive */
672  {1, 31, "wInE", FR_DOWN, 4},
673  {1, 31, "Wine", FR_DOWN, 4},
674 
675  /* High-to-low ranges */
676  {20, 5, "Wine", FR_DOWN, -1},
677  {2, 1, "Wine", FR_DOWN, -1},
678  {30, 29, "Wine", FR_DOWN, -1},
679  {20, 5, "Wine", 0, /*13*/ -1},
680 
681  /* Find nothing */
682  {5, 10, "", FR_DOWN, -1},
683  {10, 5, "", FR_DOWN, -1},
684  {0, -1, "", FR_DOWN, -1},
685  {10, 5, "", 0, -1},
686 
687  /* Whole-word search */
688  {0, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18},
689  {0, -1, "win", FR_DOWN | FR_WHOLEWORD, -1},
690  {13, -1, "wine", FR_DOWN | FR_WHOLEWORD, 18},
691  {0, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 0},
692  {10, -1, "winewine", FR_DOWN | FR_WHOLEWORD, 23},
693  {11, -1, "winewine", FR_WHOLEWORD, 23},
694  {31, -1, "winewine", FR_WHOLEWORD, -1},
695 
696  /* Bad ranges */
697  {5, 200, "XXX", FR_DOWN, -1},
698  {-20, 20, "Wine", FR_DOWN, -1},
699  {-20, 20, "Wine", FR_DOWN, -1},
700  {-15, -20, "Wine", FR_DOWN, -1},
701  {1<<12, 1<<13, "Wine", FR_DOWN, -1},
702 
703  /* Check the case noted in bug 4479 where matches at end aren't recognized */
704  {23, 31, "Wine", FR_DOWN | FR_MATCHCASE, 23},
705  {27, 31, "Wine", FR_DOWN | FR_MATCHCASE, 27},
706  {27, 32, "Wine", FR_DOWN | FR_MATCHCASE, 27},
707  {13, 31, "WineWine", FR_DOWN | FR_MATCHCASE, 23},
708  {13, 32, "WineWine", FR_DOWN | FR_MATCHCASE, 23},
709 
710  /* The backwards case of bug 4479; bounds look right
711  * Fails because backward find is wrong */
712  {19, 20, "WINE", FR_MATCHCASE, -1},
713  {0, 20, "WINE", FR_MATCHCASE, 0},
714 
715  {0, -1, "wineWine wine", FR_DOWN, 0},
716  {0, -1, "wineWine wine", 0, 0},
717  {0, -1, "INEW", 0, 1},
718  {0, 31, "INEW", 0, 1},
719  {4, -1, "INEW", 0, 10},
720 };
721 
722 static struct find_s find_tests3[] = {
723  /* Searching for end of line characters */
724  {0, -1, "t\r\r\ns", FR_DOWN | FR_MATCHCASE, 4},
725  {6, -1, "\r\n", FR_DOWN | FR_MATCHCASE, 6},
726  {7, -1, "\n", FR_DOWN | FR_MATCHCASE, 7},
727 };
728 
729 static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id) {
730  int findloc;
731  FINDTEXTA ft;
732  memset(&ft, 0, sizeof(ft));
733  ft.chrg.cpMin = f->start;
734  ft.chrg.cpMax = f->end;
735  ft.lpstrText = f->needle;
736  findloc = SendMessageA(hwnd, EM_FINDTEXT, f->flags, (LPARAM)&ft);
737  ok(findloc == f->expected_loc,
738  "EM_FINDTEXT(%s,%d) '%s' in range(%d,%d), flags %08x, got start at %d, expected %d\n",
739  name, id, f->needle, f->start, f->end, f->flags, findloc, f->expected_loc);
740 }
741 
742 static void check_EM_FINDTEXTEX(HWND hwnd, const char *name, struct find_s *f,
743  int id) {
744  int findloc;
745  FINDTEXTEXA ft;
746  int expected_end_loc;
747 
748  memset(&ft, 0, sizeof(ft));
749  ft.chrg.cpMin = f->start;
750  ft.chrg.cpMax = f->end;
751  ft.lpstrText = f->needle;
752  ft.chrgText.cpMax = 0xdeadbeef;
753  findloc = SendMessageA(hwnd, EM_FINDTEXTEX, f->flags, (LPARAM)&ft);
754  ok(findloc == f->expected_loc,
755  "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d\n",
756  name, id, f->needle, f->start, f->end, f->flags, findloc);
757  ok(ft.chrgText.cpMin == f->expected_loc,
758  "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, start at %d, expected %d\n",
759  name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMin, f->expected_loc);
760  expected_end_loc = ((f->expected_loc == -1) ? -1
761  : f->expected_loc + strlen(f->needle));
762  ok(ft.chrgText.cpMax == expected_end_loc ||
763  broken(ft.chrgText.cpMin == -1 && ft.chrgText.cpMax == 0xdeadbeef), /* Win9x, WinME and NT4 */
764  "EM_FINDTEXTEX(%s,%d) '%s' in range(%d,%d), flags %08x, end at %d, expected %d\n",
765  name, id, f->needle, f->start, f->end, f->flags, ft.chrgText.cpMax, expected_end_loc);
766 }
767 
768 static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *find,
769  int num_tests)
770 {
771  int i;
772 
773  for (i = 0; i < num_tests; i++) {
776  }
777 }
778 
779 static void test_EM_FINDTEXT(void)
780 {
781  HWND hwndRichEdit = new_richedit(NULL);
782 
783  /* Empty rich edit control */
785 
786  SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)haystack);
787 
788  /* Haystack text */
790 
791  SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)haystack2);
792 
793  /* Haystack text 2 (with EOL characters) */
795 
796  DestroyWindow(hwndRichEdit);
797 }
798 
799 static void test_EM_POSFROMCHAR(void)
800 {
801  HWND hwndRichEdit = new_richedit(NULL);
802  int i;
803  POINTL pl;
804  LRESULT result;
805  unsigned int height = 0;
806  int xpos = 0;
807  int xpos_rtl_adjusted = 0;
808  static const char text[] = "aa\n"
809  "this is a long line of text that should be longer than the "
810  "control's width\n"
811  "cc\n"
812  "dd\n"
813  "ee\n"
814  "ff\n"
815  "gg\n"
816  "hh\n";
817 
818  /* Fill the control to lines to ensure that most of them are offscreen */
819  for (i = 0; i < 50; i++)
820  {
821  /* Do not modify the string; it is exactly 16 characters long. */
822  SendMessageA(hwndRichEdit, EM_SETSEL, 0, 0);
823  SendMessageA(hwndRichEdit, EM_REPLACESEL, 0, (LPARAM)"0123456789ABCD\r\n");
824  }
825 
826  /*
827  Richedit 1.0 receives a POINTL* on wParam and character offset on lParam, returns void.
828  Richedit 2.0 receives character offset on wParam, ignores lParam, returns MAKELONG(x,y)
829  Richedit 3.0 accepts either of the above API conventions.
830  */
831 
832  /* Testing Richedit 1.0 API format */
833 
834  /* Testing start of lines. X-offset should be constant on all cases (native is 1).
835  Since all lines are identical and drawn with the same font,
836  they should have the same height... right?
837  */
838  for (i = 0; i < 50; i++)
839  {
840  /* All the lines are 16 characters long */
841  result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, i * 16);
842  ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
843  if (i == 0)
844  {
845  ok(pl.y == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", pl.y);
846  ok(pl.x == 1 ||
847  broken(pl.x == 0), /* Win9x, WinME and NT4 */
848  "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x);
849  xpos = pl.x;
850  xpos_rtl_adjusted = xpos + (is_rtl() ? 7 : 0);
851  }
852  else if (i == 1)
853  {
854  ok(pl.y > 0, "EM_POSFROMCHAR reports y=%d, expected > 0\n", pl.y);
855  ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected %d\n", pl.x, xpos);
856  height = pl.y;
857  }
858  else
859  {
860  ok(pl.y == i * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl.y, i * height);
861  ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected %d\n", pl.x, xpos);
862  }
863  }
864 
865  /* Testing position at end of text */
866  result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 50 * 16);
867  ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
868  ok(pl.y == 50 * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl.y, 50 * height);
869  ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected %d\n", pl.x, xpos);
870 
871  /* Testing position way past end of text */
872  result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 55 * 16);
873  ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
874  ok(pl.y == 50 * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl.y, 50 * height);
875 
876  ok(pl.x == xpos_rtl_adjusted, "EM_POSFROMCHAR reports x=%d, expected %d\n", pl.x, xpos_rtl_adjusted);
877 
878 
879  /* Testing that vertical scrolling does, in fact, have an effect on EM_POSFROMCHAR */
880  SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEDOWN, 0); /* line down */
881  for (i = 0; i < 50; i++)
882  {
883  /* All the lines are 16 characters long */
884  result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, i * 16);
885  ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
886  ok(pl.y == (i - 1) * height,
887  "EM_POSFROMCHAR reports y=%d, expected %d\n",
888  pl.y, (i - 1) * height);
889  ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected %d\n", pl.x, xpos);
890  }
891 
892  /* Testing position at end of text */
893  result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 50 * 16);
894  ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
895  ok(pl.y == (50 - 1) * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl.y, (50 - 1) * height);
896  ok(pl.x == xpos, "EM_POSFROMCHAR reports x=%d, expected %d\n", pl.x, xpos);
897 
898  /* Testing position way past end of text */
899  result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 55 * 16);
900  ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
901  ok(pl.y == (50 - 1) * height, "EM_POSFROMCHAR reports y=%d, expected %d\n", pl.y, (50 - 1) * height);
902  ok(pl.x == xpos_rtl_adjusted, "EM_POSFROMCHAR reports x=%d, expected %d\n", pl.x, xpos_rtl_adjusted);
903 
904  /* Testing that horizontal scrolling does, in fact, have an effect on EM_POSFROMCHAR */
905  SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)text);
906  SendMessageA(hwndRichEdit, EM_SCROLL, SB_LINEUP, 0); /* line up */
907 
908  result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 0);
909  ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
910  ok(pl.y == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", pl.y);
911  ok(pl.x == 1 ||
912  broken(pl.x == 0), /* Win9x, WinME and NT4 */
913  "EM_POSFROMCHAR reports x=%d, expected 1\n", pl.x);
914  xpos = pl.x;
915 
916  SendMessageA(hwndRichEdit, WM_HSCROLL, SB_LINERIGHT, 0);
917  result = SendMessageA(hwndRichEdit, EM_POSFROMCHAR, (WPARAM)&pl, 0);
918  ok(result == 0, "EM_POSFROMCHAR returned %ld, expected 0\n", result);
919  ok(pl.y == 0, "EM_POSFROMCHAR reports y=%d, expected 0\n", pl.y);
920  todo_wine {
921  /* Fails on builtin because horizontal scrollbar is not being shown */
922  ok(pl.x < xpos ||
923  broken(pl.x == xpos), /* Win9x, WinME and NT4 */
924  "EM_POSFROMCHAR reports x=%d, expected value less than %d\n", pl.x, xpos);
925  }
926  DestroyWindow(hwndRichEdit);
927 }
928 
929 static void test_word_wrap(void)
930 {
931  HWND hwnd;
932  POINTL point = {0, 60}; /* This point must be below the first line */
933  const char *text = "Must be long enough to test line wrapping";
935  int res, pos, lines, prevlines, reflines[3];
936 
937  /* Test the effect of WS_HSCROLL and ES_AUTOHSCROLL styles on wrapping
938  * when specified on window creation and set later. */
939  hwnd = CreateWindowA(RICHEDIT_CLASS10A, NULL, dwCommonStyle,
940  0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
941  ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
943  ok(res, "WM_SETTEXT failed.\n");
945  ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
947  ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines);
948 
951  ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
953 
955  0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
956  ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
957 
959  ok(res, "WM_SETTEXT failed.\n");
961  ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
963  ok(lines > 1, "Line was expected to wrap (lines=%d).\n", lines);
964 
967  ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
969 
971  0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
972  ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
974  ok(res, "WM_SETTEXT failed.\n");
976  ok(!pos ||
977  broken(pos == lstrlenA(text)), /* Win9x, WinME and NT4 */
978  "pos=%d indicating word wrap when none is expected.\n", pos);
980  ok(lines == 1, "Line was not expected to wrap (lines=%d).\n", lines);
981 
982  SetWindowLongA(hwnd, GWL_STYLE, dwCommonStyle);
984  ok(!pos ||
985  broken(pos == lstrlenA(text)), /* Win9x, WinME and NT4 */
986  "pos=%d indicating word wrap when none is expected.\n", pos);
988  ok(lines == 1, "Line was not expected to wrap (lines=%d).\n", lines);
990 
992  dwCommonStyle|WS_HSCROLL|ES_AUTOHSCROLL,
993  0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
994  ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
996  ok(res, "WM_SETTEXT failed.\n");
998  ok(!pos ||
999  broken(pos == lstrlenA(text)), /* Win9x, WinME and NT4 */
1000  "pos=%d indicating word wrap when none is expected.\n", pos);
1002  ok(lines == 1, "Line was not expected to wrap (lines=%d).\n", lines);
1003 
1004  SetWindowLongA(hwnd, GWL_STYLE, dwCommonStyle);
1006  ok(!pos ||
1007  broken(pos == lstrlenA(text)), /* Win9x, WinME and NT4 */
1008  "pos=%d indicating word wrap when none is expected.\n", pos);
1010  ok(lines == 1, "Line was not expected to wrap (lines=%d).\n", lines);
1011 
1012  /* Test the effect of EM_SETTARGETDEVICE on word wrap. */
1014  ok(res, "EM_SETTARGETDEVICE failed (returned %d).\n", res);
1016  ok(!pos ||
1017  broken(pos == lstrlenA(text)), /* Win9x, WinME and NT4 */
1018  "pos=%d indicating word wrap when none is expected.\n", pos);
1020  ok(lines == 1, "Line was not expected to wrap (lines=%d).\n", lines);
1021 
1023  ok(res, "EM_SETTARGETDEVICE failed (returned %d).\n", res);
1025  ok(pos, "pos=%d indicating no word wrap when it is expected.\n", pos);
1027 
1028  /* First lets see if the text would wrap normally (needed for reference) */
1029  hwnd = CreateWindowA(RICHEDIT_CLASS10A, NULL, dwCommonStyle,
1030  0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
1031  ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
1032  ok(IsWindowVisible(hwnd), "Window should be visible.\n");
1034  ok(res, "EM_REPLACESEL failed.\n");
1035  /* Should have wrapped */
1036  reflines[0] = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0);
1037  ok(reflines[0] > 1, "Line was expected to wrap (%d lines).\n", reflines[0]);
1038  /* Resize the window to fit the line */
1039  MoveWindow(hwnd, 0, 0, 600, 80, TRUE);
1040  /* Text should not be wrapped */
1041  reflines[1] = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0);
1042  ok(reflines[1] == 1, "Line wasn't expected to wrap (%d lines).\n", reflines[1]);
1043  /* Resize the window again to make sure the line wraps again */
1044  MoveWindow(hwnd, 0, 0, 10, 80, TRUE);
1045  reflines[2] = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0);
1046  ok(reflines[2] > 1, "Line was expected to wrap (%d lines).\n", reflines[2]);
1048 
1049  /* Same test with redraw disabled */
1050  hwnd = CreateWindowA(RICHEDIT_CLASS10A, NULL, dwCommonStyle,
1051  0, 0, 200, 80, NULL, NULL, hmoduleRichEdit, NULL);
1052  ok(hwnd != NULL, "error: %d\n", (int) GetLastError());
1053  ok(IsWindowVisible(hwnd), "Window should be visible.\n");
1054  /* Redraw is disabled by making the window invisible. */
1056  ok(!IsWindowVisible(hwnd), "Window shouldn't be visible.\n");
1058  ok(res, "EM_REPLACESEL failed.\n");
1059  /* Should have wrapped */
1060  prevlines = SendMessageA(hwnd, EM_GETLINECOUNT, 0, 0);
1061  ok(prevlines == reflines[0],
1062  "Line was expected to wrap (%d lines).\n", prevlines);
1063  /* Resize the window to fit the line, no change to the number of lines */
1064  MoveWindow(hwnd, 0, 0, 600, 80, TRUE);
1066  todo_wine
1067  ok(lines == prevlines ||
1068  broken(lines == reflines[1]), /* Win98, WinME and NT4 */
1069  "Expected no change in the number of lines\n");
1070  /* Resize the window again to make sure the line wraps again */
1071  MoveWindow(hwnd, 0, 0, 10, 80, TRUE);
1073  todo_wine
1074  ok(lines == prevlines ||
1075  broken(lines == reflines[2]), /* Win98, WinME and NT4 */
1076  "Expected no change in the number of lines\n");
1078 }
1079 
1080 static void test_EM_GETOPTIONS(void)
1081 {
1082  HWND hwnd;
1083  DWORD options;
1084 
1086  WS_POPUP,
1087  0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
1089  ok(options == 0, "Incorrect options %x\n", options);
1091 
1094  0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
1096  ok(options == ECO_AUTOVSCROLL ||
1097  broken(options == 0), /* Win9x, WinME and NT4 */
1098  "Incorrect initial options %x\n", options);
1100 }
1101 
1102 static void test_autoscroll(void)
1103 {
1104  HWND hwnd;
1105  UINT ret;
1106 
1107  /* The WS_VSCROLL and WS_HSCROLL styles implicitly set
1108  * auto vertical/horizontal scrolling options. */
1111  0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
1112  ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS10A, (int) GetLastError());
1113  ret = SendMessageA(hwnd, EM_GETOPTIONS, 0, 0);
1114  ok(ret & ECO_AUTOVSCROLL ||
1115  broken(!(ret & ECO_AUTOVSCROLL)), /* Win9x, WinME and NT4 */
1116  "ECO_AUTOVSCROLL isn't set.\n");
1117  ok(!(ret & ECO_AUTOHSCROLL), "ECO_AUTOHSCROLL is set.\n");
1119  todo_wine
1120  ok(ret & ES_AUTOVSCROLL ||
1121  broken(!(ret & ES_AUTOVSCROLL)), /* Win9x, WinMe and NT4 */
1122  "ES_AUTOVSCROLL isn't set.\n");
1123  ok(!(ret & ES_AUTOHSCROLL), "ES_AUTOHSCROLL is set.\n");
1125 
1128  0, 0, 200, 60, NULL, NULL, hmoduleRichEdit, NULL);
1129  ok(hwnd != NULL, "class: %s, error: %d\n", RICHEDIT_CLASS10A, (int) GetLastError());
1130  ret = SendMessageA(hwnd, EM_GETOPTIONS, 0, 0);
1131  ok(!(ret & ECO_AUTOVSCROLL), "ECO_AUTOVSCROLL is set.\n");
1132  ok(!(ret & ECO_AUTOHSCROLL), "ECO_AUTOHSCROLL is set.\n");
1134  ok(!(ret & ES_AUTOVSCROLL), "ES_AUTOVSCROLL is set.\n");
1135  ok(!(ret & ES_AUTOHSCROLL), "ES_AUTOHSCROLL is set.\n");
1137 }
1138 
1139 static void simulate_typing_characters(HWND hwnd, const char* szChars)
1140 {
1141  int ret;
1142 
1143  while (*szChars != '\0') {
1144  SendMessageA(hwnd, WM_KEYDOWN, *szChars, 1);
1145  ret = SendMessageA(hwnd, WM_CHAR, *szChars, 1);
1146  ok(ret == 0, "WM_CHAR('%c') ret=%d\n", *szChars, ret);
1147  SendMessageA(hwnd, WM_KEYUP, *szChars, 1);
1148  szChars++;
1149  }
1150 }
1151 
1152 static void format_test_result(char *target, const char *src)
1153 {
1154  int i;
1155  for (i = 0; i < strlen(src); i++)
1156  sprintf(target + 2*i, "%02x", src[i] & 0xFF);
1157  target[2*i] = 0;
1158 }
1159 
1160 /*
1161  * This test attempts to show the effect of enter on a richedit
1162  * control v1.0 inserts CRLF whereas for higher versions it only
1163  * inserts CR. If shows that EM_GETTEXTEX with GT_USECRLF == WM_GETTEXT
1164  * and also shows that GT_USECRLF has no effect in richedit 1.0, but
1165  * does for higher. The same test is cloned in riched32 and riched20.
1166  * Also shows the difference between WM_CHAR/WM_KEYDOWN in v1.0 and higher versions
1167  */
1168 static void test_enter(void)
1169 {
1170  static const struct {
1171  const char *initialtext;
1172  const int cursor;
1173  const char *expectedtext;
1174  } testenteritems[] = {
1175  { "aaabbb\r\n", 3, "aaa\r\nbbb\r\n"},
1176  { "aaabbb\r\n", 6, "aaabbb\r\n\r\n"},
1177  { "aa\rabbb\r\n", 7, "aa\rabbb\r\n\r\n"},
1178  { "aa\rabbb\r\n", 3, "aa\r\r\nabbb\r\n"},
1179  { "aa\rabbb\r\n", 2, "aa\r\n\rabbb\r\n"}
1180  };
1181 
1182  char expectedbuf[1024];
1183  char resultbuf[1024];
1184  HWND hwndRichEdit = new_richedit(NULL);
1185  UINT i;
1186  char buf[1024] = {0};
1187  GETTEXTEX getText = {sizeof(buf)};
1188  LRESULT result;
1189  const char *expected;
1190 
1191  for (i = 0; i < ARRAY_SIZE(testenteritems); i++)
1192  {
1193  /* Set the text to the initial text */
1194  result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)testenteritems[i].initialtext);
1195  ok (result == 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i, result);
1196 
1197  /* Send Enter */
1198  SendMessageA(hwndRichEdit, EM_SETSEL, testenteritems[i].cursor, testenteritems[i].cursor);
1199  simulate_typing_characters(hwndRichEdit, "\r");
1200 
1201  /* 1. Retrieve with WM_GETTEXT */
1202  buf[0] = 0x00;
1203  result = SendMessageA(hwndRichEdit, WM_GETTEXT, 1024, (LPARAM)buf);
1204  expected = testenteritems[i].expectedtext;
1205 
1206  format_test_result(resultbuf, buf);
1207  format_test_result(expectedbuf, expected);
1208 
1209  result = strcmp(expected, buf);
1210  ok (result == 0,
1211  "[%d] WM_GETTEXT unexpected '%s' expected '%s'\n",
1212  i, resultbuf, expectedbuf);
1213 
1214  /* 2. Retrieve with EM_GETTEXTEX, GT_DEFAULT */
1215  getText.flags = GT_DEFAULT;
1216  getText.codepage = CP_ACP;
1217  buf[0] = 0x00;
1218  result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
1219  expected = testenteritems[i].expectedtext;
1220 
1221  format_test_result(resultbuf, buf);
1222  format_test_result(expectedbuf, expected);
1223 
1224  result = strcmp(expected, buf);
1225  ok (result == 0 || broken(buf[0]==0x00 /* WinNT4 */),
1226  "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n",
1227  i, resultbuf, expectedbuf);
1228 
1229  /* 3. Retrieve with EM_GETTEXTEX, GT_USECRLF */
1230  getText.flags = GT_USECRLF;
1231  getText.codepage = CP_ACP;
1232  buf[0] = 0x00;
1233  result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
1234  expected = testenteritems[i].expectedtext;
1235 
1236  format_test_result(resultbuf, buf);
1237  format_test_result(expectedbuf, expected);
1238 
1239  result = strcmp(expected, buf);
1240  ok (result == 0 || broken(buf[0]==0x00 /* WinNT4 */),
1241  "[%d] EM_GETTEXTEX, GT_USECRLF unexpected '%s', expected '%s'\n",
1242  i, resultbuf, expectedbuf);
1243  }
1244 
1245  /* Show that WM_CHAR is handled differently from WM_KEYDOWN */
1246  getText.flags = GT_DEFAULT;
1247  getText.codepage = CP_ACP;
1248 
1249  result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
1250  ok (result == 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i, result);
1251  SendMessageW(hwndRichEdit, WM_CHAR, 'T', 0);
1252  SendMessageW(hwndRichEdit, WM_KEYDOWN, VK_RETURN, 0);
1253 
1254  result = SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
1255  ok(result == 1, "Got %d\n", (int)result);
1256  format_test_result(resultbuf, buf);
1257  format_test_result(expectedbuf, "T");
1258  result = strcmp(resultbuf, expectedbuf);
1259  ok (result == 0, "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n", i, resultbuf, expectedbuf);
1260 
1261  result = SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"");
1262  ok (result == 1, "[%d] WM_SETTEXT returned %ld instead of 1\n", i, result);
1263  SendMessageW(hwndRichEdit, WM_CHAR, 'T', 0);
1264  SendMessageW(hwndRichEdit, WM_CHAR, '\r', 0);
1265 
1266  SendMessageA(hwndRichEdit, EM_GETTEXTEX, (WPARAM)&getText, (LPARAM)buf);
1267  ok(result == 1, "Got %d\n", (int)result);
1268  format_test_result(resultbuf, buf);
1269  format_test_result(expectedbuf, "T\r\n");
1270  result = strcmp(resultbuf, expectedbuf);
1271  ok (result == 0, "[%d] EM_GETTEXTEX, GT_DEFAULT unexpected '%s', expected '%s'\n", i, resultbuf, expectedbuf);
1272 
1273  DestroyWindow(hwndRichEdit);
1274 }
1275 
1276 struct exsetsel_s {
1277  LONG min;
1278  LONG max;
1281  int expected_getsel_end;
1284 };
1285 
1286 static const struct exsetsel_s exsetsel_tests[] = {
1287  /* sanity tests */
1288  {5, 10, 10, 5, 10, 0, 0 },
1289  {15, 17, 17, 15, 17, 0, 0 },
1290  /* test cpMax > strlen() */
1291  {0, 100, 19, 0, 19, 1, 0 },
1292  /* test cpMin < 0 && cpMax >= 0 after cpMax > strlen() */
1293  {-1, 1, 17, 17, 17, 1, 0 },
1294  /* test cpMin == cpMax */
1295  {5, 5, 5, 5, 5, 0, 0 },
1296  /* test cpMin < 0 && cpMax >= 0 (bug 4462) */
1297  {-1, 0, 5, 5, 5, 0, 0 },
1298  {-1, 17, 5, 5, 5, 0, 0 },
1299  {-1, 18, 5, 5, 5, 0, 0 },
1300  /* test cpMin < 0 && cpMax < 0 */
1301  {-1, -1, 17, 17, 17, 0, 0 },
1302  {-4, -5, 17, 17, 17, 0, 0 },
1303  /* test cpMin >=0 && cpMax < 0 (bug 6814) */
1304  {0, -1, 19, 0, 19, 1, 0 },
1305  {17, -5, 19, 17, 19, 1, 0 },
1306  {18, -3, 19, 17, 19, 1, 1 },
1307  /* test if cpMin > cpMax */
1308  {15, 19, 19, 15, 19, 1, 0 },
1309  {19, 15, 19, 15, 19, 1, 0 },
1310  /* cpMin == strlen() && cpMax > cpMin */
1311  {17, 18, 17, 17, 17, 1, 1 },
1312  {17, 50, 19, 17, 19, 1, 0 },
1313 };
1314 
1315 static void check_EM_EXSETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) {
1316  CHARRANGE cr;
1317  LRESULT result;
1318  int start, end;
1319 
1320  cr.cpMin = setsel->min;
1321  cr.cpMax = setsel->max;
1322  result = SendMessageA(hwnd, EM_EXSETSEL, 0, (LPARAM)&cr);
1323 
1324  todo_wine_if (setsel->result_todo)
1325  ok(result == setsel->expected_retval, "EM_EXSETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
1326 
1328 
1329  todo_wine_if (setsel->sel_todo)
1330  ok(start == setsel->expected_getsel_start && end == setsel->expected_getsel_end,
1331  "EM_EXSETSEL(%d): expected (%d,%d) actual:(%d,%d)\n",
1332  id, setsel->expected_getsel_start, setsel->expected_getsel_end, start, end);
1333 }
1334 
1335 static void test_EM_EXSETSEL(void)
1336 {
1337  HWND hwndRichEdit = new_richedit(NULL);
1338  int i;
1339  const int num_tests = ARRAY_SIZE(exsetsel_tests);
1340 
1341  /* sending some text to the window */
1342  SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection");
1343  /* 01234567890123456 */
1344 
1345  for (i = 0; i < num_tests; i++) {
1346  check_EM_EXSETSEL(hwndRichEdit, &exsetsel_tests[i], i);
1347  }
1348 
1349  if (!is_lang_japanese)
1350  skip("Skip multibyte character tests on non-Japanese platform\n");
1351  else
1352  {
1353  CHARRANGE cr;
1354  LRESULT result;
1355 #define MAX_BUF_LEN 1024
1356  char bufA[MAX_BUF_LEN] = {0};
1357 
1358  /* Test with multibyte character */
1359  SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk");
1360  /* 012345 6 7 8901 */
1361  cr.cpMin = 4, cr.cpMax = 8;
1362  result = SendMessageA(hwndRichEdit, EM_EXSETSEL, 0, (LPARAM)&cr);
1363  todo_wine ok(result == 7, "EM_EXSETSEL return %ld expected 7\n", result);
1364  result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, sizeof(bufA), (LPARAM)bufA);
1365  todo_wine ok(!strcmp(bufA, "ef\x8e\xf0"), "EM_GETSELTEXT return incorrect string\n");
1366  SendMessageA(hwndRichEdit, EM_EXGETSEL, 0, (LPARAM)&cr);
1367  ok(cr.cpMin == 4, "Selection start incorrectly: %d expected 4\n", cr.cpMin);
1368  ok(cr.cpMax == 8, "Selection end incorrectly: %d expected 8\n", cr.cpMax);
1369  }
1370 
1371  DestroyWindow(hwndRichEdit);
1372 }
1373 
1374 static void check_EM_SETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id) {
1375  LRESULT result;
1376  int start, end;
1377 
1378  result = SendMessageA(hwnd, EM_SETSEL, setsel->min, setsel->max);
1379 
1380  todo_wine_if (setsel->result_todo)
1381  ok(result == setsel->expected_retval, "EM_SETSEL(%d): expected: %ld actual: %ld\n", id, setsel->expected_retval, result);
1382 
1384 
1385  todo_wine_if (setsel->sel_todo)
1386  ok(start == setsel->expected_getsel_start && end == setsel->expected_getsel_end,
1387  "EM_SETSEL(%d): expected (%d,%d) actual:(%d,%d)\n",
1388  id, setsel->expected_getsel_start, setsel->expected_getsel_end, start, end);
1389 }
1390 
1391 static void test_EM_SETSEL(void)
1392 {
1393  char buffA[32] = {0};
1394  HWND hwndRichEdit = new_richedit(NULL);
1395  int i;
1396  const int num_tests = ARRAY_SIZE(exsetsel_tests);
1397 
1398  /* sending some text to the window */
1399  SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"testing selection");
1400  /* 01234567890123456 */
1401 
1402  for (i = 0; i < num_tests; i++) {
1403  check_EM_SETSEL(hwndRichEdit, &exsetsel_tests[i], i);
1404  }
1405 
1406  SendMessageA(hwndRichEdit, EM_SETSEL, 17, 18);
1407  buffA[0] = 123;
1408  SendMessageA(hwndRichEdit, EM_GETSELTEXT, 0, (LPARAM)buffA);
1409  ok(buffA[0] == 0, "selection text %s\n", buffA);
1410 
1411  if (!is_lang_japanese)
1412  skip("Skip multibyte character tests on non-Japanese platform\n");
1413  else
1414  {
1415  int sel_start, sel_end;
1416  LRESULT result;
1417 
1418  /* Test with multibyte character */
1419  SendMessageA(hwndRichEdit, WM_SETTEXT, 0, (LPARAM)"abcdef\x8e\xf0ghijk");
1420  /* 012345 6 7 8901 */
1421  result = SendMessageA(hwndRichEdit, EM_SETSEL, 4, 8);
1422  todo_wine ok(result == 7, "EM_SETSEL return %ld expected 7\n", result);
1423  result = SendMessageA(hwndRichEdit, EM_GETSELTEXT, sizeof(buffA), (LPARAM)buffA);
1424  todo_wine ok(!strcmp(buffA, "ef\x8e\xf0"), "EM_GETSELTEXT return incorrect string\n");
1425  result = SendMessageA(hwndRichEdit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end);
1426  ok(sel_start == 4, "Selection start incorrectly: %d expected 4\n", sel_start);
1427  ok(sel_end == 8, "Selection end incorrectly: %d expected 8\n", sel_end);
1428  }
1429 
1430  DestroyWindow(hwndRichEdit);
1431 }
1432 
1433 START_TEST( editor )
1434 {
1435  MSG msg;
1436  time_t end;
1437  BOOL ret;
1438 
1439  /* Must explicitly LoadLibrary(). The test has no references to functions in
1440  * RICHED32.DLL, so the linker doesn't actually link to it. */
1441  hmoduleRichEdit = LoadLibraryA("riched32.dll");
1442  ok(hmoduleRichEdit != NULL, "error: %d\n", (int) GetLastError());
1444 
1445  test_WM_SETTEXT();
1449  test_EM_STREAMIN();
1451  test_EM_GETLINE();
1453  test_EM_FINDTEXT();
1455  test_word_wrap();
1457  test_autoscroll();
1458  test_enter();
1459  test_EM_EXSETSEL();
1460  test_EM_SETSEL();
1461 
1462  /* Set the environment variable WINETEST_RICHED32 to keep windows
1463  * responsive and open for 30 seconds. This is useful for debugging.
1464  *
1465  * The message pump uses PeekMessage() to empty the queue and then sleeps for
1466  * 50ms before retrying the queue. */
1467  end = time(NULL) + 30;
1468  if (getenv( "WINETEST_RICHED32" )) {
1469  while (time(NULL) < end) {
1470  if (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
1473  } else {
1474  Sleep(50);
1475  }
1476  }
1477  }
1478 
1481  ok(ret, "error: %u\n", GetLastError());
1482 }
#define WM_GETTEXTLENGTH
Definition: winuser.h:1601
CHARRANGE chrg
Definition: richedit.h:508
#define ECO_AUTOVSCROLL
Definition: richedit.h:457
const DOCKBAR PVOID HWND HWND * hwnd
Definition: tooldock.h:22
static void test_EM_STREAMOUT(void)
Definition: editor.c:317
BOOL WINAPI TranslateMessage(_In_ const MSG *)
LRESULT WINAPI DispatchMessageA(_In_ const MSG *)
CHARRANGE chrgText
Definition: richedit.h:595
#define TRUE
Definition: types.h:120
VOID WINAPI DECLSPEC_HOTPATCH Sleep(IN DWORD dwMilliseconds)
Definition: synch.c:790
static HMODULE hmoduleRichEdit
Definition: editor.c:37
LRESULT expected_retval
Definition: editor.c:4879
#define EM_LINELENGTH
Definition: winuser.h:1985
static BOOL rtl
Definition: propsheet.c:36
#define WM_CHAR
Definition: winuser.h:1699
#define DWORD_PTR
Definition: treelist.c:76
#define EM_GETTEXTRANGE
Definition: richedit.h:108
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
int end
Definition: editor.c:150
#define SF_RTF
Definition: richedit.h:721
LRESULT WINAPI SendMessageA(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
const WCHAR * text
Definition: package.c:1827
#define CP_ACP
Definition: compat.h:99
INT WINAPI GetLocaleInfoA(LCID lcid, LCTYPE lctype, LPSTR buffer, INT len)
Definition: lang.c:1018
#define LOCALE_USER_DEFAULT
TW_UINT32 TW_UINT16 TW_UINT16 MSG
Definition: twain.h:1827
#define WM_GETTEXT
Definition: winuser.h:1600
static void check_EM_EXSETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id)
Definition: editor.c:1315
#define ES_MULTILINE
Definition: pedump.c:667
static void test_EM_LINELENGTH(void)
Definition: editor.c:465
#define CALLBACK
Definition: compat.h:27
#define WM_SETREDRAW
Definition: winuser.h:1598
static void test_EM_GETOPTIONS(void)
Definition: editor.c:1080
static void test_word_wrap(void)
Definition: editor.c:929
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
LONG cpMax
Definition: richedit.h:501
GLuint buffer
Definition: glext.h:5915
static void run_tests_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *find, int num_tests)
Definition: editor.c:768
UINT_PTR WPARAM
Definition: windef.h:207
GLuint GLuint end
Definition: gl.h:1545
__u16 time
Definition: mkdosfs.c:366
LPCSTR lpstrText
Definition: richedit.h:594
BOOL WINAPI PeekMessageA(_Out_ LPMSG, _In_opt_ HWND, _In_ UINT, _In_ UINT, _In_ UINT)
DWORD flags
Definition: richedit.h:707
char * LPSTR
Definition: xmlstorage.h:182
BOOL WINAPI DestroyWindow(_In_ HWND)
static void test_EM_GETSELTEXT(void)
Definition: editor.c:593
int flags
Definition: editor.c:152
#define VK_RETURN
Definition: winuser.h:2176
POINTL point
Definition: edittest.c:50
static void test_autoscroll(void)
Definition: editor.c:1102
const char * broken_text
Definition: editor.c:376
#define MAX_BUF_LEN
#define EM_CHARFROMPOS
Definition: richedit.h:78
static BOOL is_rtl(void)
Definition: editor.c:53
#define EM_GETSEL
Definition: winuser.h:1979
static void test_WM_GETTEXTLENGTH(void)
Definition: editor.c:130
#define EM_POSFROMCHAR
Definition: richedit.h:77
#define EM_EXGETSEL
Definition: richedit.h:85
#define sprintf(buf, format,...)
Definition: sprintf.c:55
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
unsigned char * LPBYTE
Definition: typedefs.h:52
#define EM_GETTEXTEX
Definition: richedit.h:128
#define LANG_JAPANESE
Definition: nls.h:76
static void test_EM_GETTEXTRANGE(void)
Definition: editor.c:539
LONG WINAPI GetWindowLongA(_In_ HWND, _In_ int)
static DWORD CALLBACK test_EM_STREAMIN_esCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
Definition: editor.c:164
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
HINSTANCE WINAPI DECLSPEC_HOTPATCH LoadLibraryA(LPCSTR lpLibFileName)
Definition: loader.c:111
LPCSTR lpstrText
Definition: richedit.h:582
#define CreateWindowA(a, b, c, d, e, f, g, h, i, j, k)
Definition: winuser.h:4216
#define GT_DEFAULT
Definition: richedit.h:1036
CHARRANGE chrg
Definition: richedit.h:581
const WCHAR * str
#define EM_FINDTEXT
Definition: richedit.h:89
#define expect2(expected1, expected2, got1, got2)
Definition: listview.c:50
smooth NULL
Definition: ftsmooth.c:416
static const struct exsetsel_s exsetsel_tests[]
Definition: editor.c:1286
#define WM_KEYDOWN
Definition: winuser.h:1697
LONG_PTR LPARAM
Definition: windef.h:208
Definition: parser.c:48
static void check_EM_FINDTEXTEX(HWND hwnd, const char *name, struct find_s *f, int id)
Definition: editor.c:742
static void test_WM_SETTEXT(void)
Definition: editor.c:61
const char * LPCSTR
Definition: xmlstorage.h:183
static void format_test_result(char *target, const char *src)
Definition: editor.c:1152
#define WM_SETTEXT
Definition: winuser.h:1599
int options
Definition: main.c:106
#define EM_STREAMIN
Definition: richedit.h:106
#define SF_TEXT
Definition: richedit.h:720
eMaj lines
Definition: tritemp.h:206
#define todo_wine_if(is_todo)
Definition: test.h:155
#define ES_AUTOVSCROLL
Definition: pedump.c:671
#define EM_SETTARGETDEVICE
Definition: richedit.h:105
GLfloat f
Definition: glext.h:7540
#define FR_MATCHCASE
Definition: commdlg.h:136
#define FreeLibrary(x)
Definition: compat.h:413
GLsizeiptr size
Definition: glext.h:5919
size_t buffer_len
Definition: editor.c:380
r parent
Definition: btrfs.c:2869
#define EM_SCROLL
Definition: winuser.h:1989
static void test_EM_GETLINE(void)
Definition: editor.c:390
#define EM_SETSEL
Definition: winuser.h:2000
#define WM_KEYUP
Definition: winuser.h:1698
int expected_loc
Definition: editor.c:153
static const char haystack[]
Definition: editor.c:632
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
unsigned short WORD
Definition: ntddk_ex.h:93
unsigned long DWORD
Definition: ntddk_ex.h:95
static void test_EM_SETSEL(void)
Definition: editor.c:1391
#define EM_FINDTEXTEX
Definition: richedit.h:112
#define WS_HSCROLL
Definition: pedump.c:628
int line
Definition: editor.c:379
#define LOCALE_FONTSIGNATURE
Definition: winnls.h:126
#define EM_EXSETSEL
Definition: richedit.h:88
int ret
static int gl_text(adns_state ads, getline_ctx *src_io, const char *filename, int lno, char *buf, int buflen)
Definition: setup.c:337
#define todo_wine
Definition: test.h:154
#define ECO_AUTOHSCROLL
Definition: richedit.h:458
UINT codepage
Definition: richedit.h:708
static void test_EM_EXSETSEL(void)
Definition: editor.c:1335
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
static const struct getline_s gl[]
GLenum src
Definition: glext.h:6340
LONG max
Definition: editor.c:4878
static HWND new_richedit(HWND parent)
Definition: editor.c:49
uint32_t DWORD_PTR
Definition: typedefs.h:63
BOOL WINAPI MoveWindow(_In_ HWND, _In_ int, _In_ int, _In_ int, _In_ int, _In_ BOOL)
#define SB_LINERIGHT
Definition: winuser.h:567
GLint GLint GLsizei GLsizei height
Definition: gl.h:1546
#define broken(x)
Definition: _sntprintf.h:21
static struct find_s find_tests2[]
Definition: editor.c:655
static void test_EM_STREAMIN(void)
Definition: editor.c:183
#define FR_WHOLEWORD
Definition: commdlg.h:145
#define GWL_STYLE
Definition: winuser.h:846
static struct find_s find_tests3[]
Definition: editor.c:722
static void check_EM_SETSEL(HWND hwnd, const struct exsetsel_s *setsel, int id)
Definition: editor.c:1374
#define EM_STREAMOUT
Definition: richedit.h:107
int start
Definition: editor.c:149
_Check_return_ char *__cdecl getenv(_In_z_ const char *_VarName)
int WINAPI lstrlenA(LPCSTR lpString)
Definition: lstring.c:145
static HWND new_window(LPCSTR lpClassName, DWORD dwStyle, HWND parent)
Definition: editor.c:40
const char cursor[]
Definition: icontest.c:13
static DWORD CALLBACK test_WM_SETTEXT_esCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
Definition: editor.c:303
#define RICHEDIT_CLASS10A
Definition: richedit.h:52
__kernel_time_t time_t
Definition: linux.h:252
GLuint start
Definition: gl.h:1545
#define ARRAY_SIZE(a)
Definition: main.h:24
BOOL result_todo
Definition: editor.c:1282
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define ok(value,...)
Definition: atltest.h:57
CHARRANGE chrg
Definition: richedit.h:593
static void test_EM_POSFROMCHAR(void)
Definition: editor.c:799
LPSTR lpstrText
Definition: richedit.h:509
#define min(a, b)
Definition: monoChain.cc:55
#define WS_POPUP
Definition: pedump.c:616
unsigned int UINT
Definition: ndis.h:50
#define SB_LINEDOWN
Definition: winuser.h:565
#define WM_HSCROLL
Definition: winuser.h:1725
#define SB_LINEUP
Definition: winuser.h:564
#define WS_VSCROLL
Definition: pedump.c:627
LONG WINAPI SetWindowLongA(_In_ HWND, _In_ int, _In_ LONG)
START_TEST(editor)
Definition: editor.c:8924
BOOL sel_todo
Definition: editor.c:1283
const char * needle
Definition: editor.c:151
#define FR_DOWN
Definition: commdlg.h:127
static BOOL is_lang_japanese
Definition: editor.c:38
int expected_getsel_start
Definition: editor.c:4880
static void test_enter(void)
Definition: editor.c:1168
#define skip(...)
Definition: atltest.h:64
int expected_getsel_end
Definition: editor.c:4881
static HMODULE MODULEINFO DWORD cb
Definition: module.c:32
static void test_EM_FINDTEXT(void)
Definition: editor.c:779
#define msg(x)
Definition: auth_time.c:54
static TAGID TAGID find
Definition: db.cpp:153
Definition: name.c:36
static void simulate_typing_characters(HWND hwnd, const char *szChars)
Definition: editor.c:1139
GLuint res
Definition: glext.h:9613
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
HWND WINAPI CreateWindowExA(_In_ DWORD dwExStyle, _In_opt_ LPCSTR lpClassName, _In_opt_ LPCSTR lpWindowName, _In_ DWORD dwStyle, _In_ int X, _In_ int Y, _In_ int nWidth, _In_ int nHeight, _In_opt_ HWND hWndParent, _In_opt_ HMENU hMenu, _In_opt_ HINSTANCE hInstance, _In_opt_ LPVOID lpParam)
#define EM_GETLINE
Definition: winuser.h:1973
GLenum target
Definition: glext.h:7315
BOOL WINAPI IsWindowVisible(_In_ HWND)
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
LANGID WINAPI GetUserDefaultLangID(void)
Definition: lang.c:734
static struct find_s find_tests[]
Definition: editor.c:646
#define GT_USECRLF
Definition: richedit.h:1037
static char * dest
Definition: rtl.c:135
Definition: editor.c:148
#define PM_REMOVE
Definition: winuser.h:1182
LONG min
Definition: editor.c:4877
HRESULT WINAPI OleFlushClipboard(void)
Definition: clipboard.c:2293
GLfloat GLfloat p
Definition: glext.h:8902
LONG_PTR LRESULT
Definition: windef.h:209
#define es
Definition: i386-dis.c:431
const char * text
Definition: editor.c:381
#define EM_GETSELTEXT
Definition: richedit.h:95
#define WS_VISIBLE
Definition: pedump.c:620
GLuint64EXT * result
Definition: glext.h:11304
#define memset(x, y, z)
Definition: compat.h:39
#define win_skip
Definition: test.h:141
#define ES_AUTOHSCROLL
Definition: pedump.c:672
static const char haystack2[]
Definition: editor.c:635
LONG cpMin
Definition: richedit.h:500
static void check_EM_FINDTEXT(HWND hwnd, const char *name, struct find_s *f, int id)
Definition: editor.c:729
BOOL expected
Definition: store.c:2063
#define EM_REPLACESEL
Definition: winuser.h:1988
#define EM_GETOPTIONS
Definition: richedit.h:111
#define PRIMARYLANGID(l)
Definition: nls.h:16
#define EM_GETLINECOUNT
Definition: winuser.h:1974