msvcrt: Don't include msvcrt headers, instead duplicate the definitions in msvcrt.h.
[wine] / dlls / kernel32 / tests / console.c
1 /*
2  * Unit tests for console API
3  *
4  * Copyright (c) 2003,2004 Eric Pouech
5  * Copyright (c) 2007 Kirill K. Smirnov
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "wine/test.h"
23 #include <windows.h>
24 #include <stdio.h>
25
26 static BOOL (WINAPI *pGetConsoleInputExeNameA)(DWORD, LPSTR);
27 static BOOL (WINAPI *pSetConsoleInputExeNameA)(LPCSTR);
28
29 /* DEFAULT_ATTRIB is used for all initial filling of the console.
30  * all modifications are made with TEST_ATTRIB so that we could check
31  * what has to be modified or not
32  */
33 #define TEST_ATTRIB    (BACKGROUND_BLUE | FOREGROUND_GREEN)
34 #define DEFAULT_ATTRIB (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED)
35 /* when filling the screen with non-blank chars, this macro defines
36  * what character should be at position 'c'
37  */
38 #define CONTENT(c)    ('A' + (((c).Y * 17 + (c).X) % 23))
39
40 #define okCURSOR(hCon, c) do { \
41   CONSOLE_SCREEN_BUFFER_INFO __sbi; \
42   BOOL expect = GetConsoleScreenBufferInfo((hCon), &__sbi) && \
43                 __sbi.dwCursorPosition.X == (c).X && __sbi.dwCursorPosition.Y == (c).Y; \
44   ok(expect, "Expected cursor at (%d,%d), got (%d,%d)\n", \
45      (c).X, (c).Y, __sbi.dwCursorPosition.X, __sbi.dwCursorPosition.Y); \
46 } while (0)
47
48 #define okCHAR(hCon, c, ch, attr) do { \
49   char __ch; WORD __attr; DWORD __len; BOOL expect; \
50   expect = ReadConsoleOutputCharacter((hCon), &__ch, 1, (c), &__len) == 1 && __len == 1 && __ch == (ch); \
51   ok(expect, "At (%d,%d): expecting char '%c'/%02x got '%c'/%02x\n", (c).X, (c).Y, (ch), (ch), __ch, __ch); \
52   expect = ReadConsoleOutputAttribute((hCon), &__attr, 1, (c), &__len) == 1 && __len == 1 && __attr == (attr); \
53   ok(expect, "At (%d,%d): expecting attr %04x got %04x\n", (c).X, (c).Y, (attr), __attr); \
54 } while (0)
55
56 static void init_function_pointers(void)
57 {
58     HMODULE hKernel32;
59
60 #define KERNEL32_GET_PROC(func)                                     \
61     p##func = (void *)GetProcAddress(hKernel32, #func);             \
62     if(!p##func) trace("GetProcAddress(hKernel32, '%s') failed\n", #func);
63
64     hKernel32 = GetModuleHandleA("kernel32.dll");
65     KERNEL32_GET_PROC(GetConsoleInputExeNameA);
66     KERNEL32_GET_PROC(SetConsoleInputExeNameA);
67
68 #undef KERNEL32_GET_PROC
69 }
70
71 /* FIXME: this could be optimized on a speed point of view */
72 static void resetContent(HANDLE hCon, COORD sbSize, BOOL content)
73 {
74     COORD       c;
75     WORD        attr = DEFAULT_ATTRIB;
76     char        ch;
77     DWORD       len;
78
79     for (c.X = 0; c.X < sbSize.X; c.X++)
80     {
81         for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
82         {
83             ch = (content) ? CONTENT(c) : ' ';
84             WriteConsoleOutputAttribute(hCon, &attr, 1, c, &len);
85             WriteConsoleOutputCharacterA(hCon, &ch, 1, c, &len);
86         }
87     }
88 }
89
90 static void testCursor(HANDLE hCon, COORD sbSize)
91 {
92     COORD               c;
93
94     c.X = c.Y = 0;
95     ok(SetConsoleCursorPosition(0, c) == 0, "No handle\n");
96     ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n",
97        ERROR_INVALID_HANDLE, GetLastError());
98
99     c.X = c.Y = 0;
100     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
101     okCURSOR(hCon, c);
102
103     c.X = sbSize.X - 1;
104     c.Y = sbSize.Y - 1;
105     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in lower-right\n");
106     okCURSOR(hCon, c);
107
108     c.X = sbSize.X;
109     c.Y = sbSize.Y - 1;
110     ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
111     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n",
112        ERROR_INVALID_PARAMETER, GetLastError());
113
114     c.X = sbSize.X - 1;
115     c.Y = sbSize.Y;
116     ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
117     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n",
118        ERROR_INVALID_PARAMETER, GetLastError());
119
120     c.X = -1;
121     c.Y = 0;
122     ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
123     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n",
124        ERROR_INVALID_PARAMETER, GetLastError());
125
126     c.X = 0;
127     c.Y = -1;
128     ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
129     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n",
130        ERROR_INVALID_PARAMETER, GetLastError());
131 }
132
133 static void testCursorInfo(HANDLE hCon)
134 {
135     BOOL ret;
136     CONSOLE_CURSOR_INFO info;
137
138     SetLastError(0xdeadbeef);
139     ret = GetConsoleCursorInfo(NULL, NULL);
140     ok(!ret, "Expected failure\n");
141     ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n",
142        ERROR_INVALID_HANDLE, GetLastError());
143
144     SetLastError(0xdeadbeef);
145     info.dwSize = -1;
146     ret = GetConsoleCursorInfo(NULL, &info);
147     ok(!ret, "Expected failure\n");
148     ok(info.dwSize == -1, "Expected no change for dwSize\n");
149     ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n",
150        ERROR_INVALID_HANDLE, GetLastError());
151
152     /* Test the correct call first to distinguish between win9x and the rest */
153     SetLastError(0xdeadbeef);
154     ret = GetConsoleCursorInfo(hCon, &info);
155     ok(ret, "Expected success\n");
156     ok(info.dwSize == 25 ||
157        info.dwSize == 12 /* win9x */,
158        "Expected 12 or 25, got %d\n", info.dwSize);
159     ok(info.bVisible, "Expected the cursor to be visible\n");
160     ok(GetLastError() == 0xdeadbeef, "GetLastError: expecting %u got %u\n",
161        0xdeadbeef, GetLastError());
162
163     if (info.dwSize == 12)
164     {
165         skip("NULL CONSOLE_CURSOR_INFO will crash on win9x\n");
166         return;
167     }
168
169     SetLastError(0xdeadbeef);
170     ret = GetConsoleCursorInfo(hCon, NULL);
171     ok(!ret, "Expected failure\n");
172     ok(GetLastError() == ERROR_INVALID_ACCESS, "GetLastError: expecting %u got %u\n",
173        ERROR_INVALID_ACCESS, GetLastError());
174 }
175
176 static void testWriteSimple(HANDLE hCon, COORD sbSize)
177 {
178     COORD               c;
179     DWORD               len;
180     const char*         mytest = "abcdefg";
181     const int   mylen = strlen(mytest);
182
183     /* single line write */
184     c.X = c.Y = 0;
185     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
186
187     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
188     c.Y = 0;
189     for (c.X = 0; c.X < mylen; c.X++)
190     {
191         okCHAR(hCon, c, mytest[c.X], TEST_ATTRIB);
192     }
193
194     okCURSOR(hCon, c);
195     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
196 }
197
198 static void testWriteNotWrappedNotProcessed(HANDLE hCon, COORD sbSize)
199 {
200     COORD               c;
201     DWORD               len, mode;
202     const char*         mytest = "123";
203     const int           mylen = strlen(mytest);
204     int                 ret;
205     int                 p;
206
207     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode & ~(ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT)),
208        "clearing wrap at EOL & processed output\n");
209
210     /* write line, wrapping disabled, buffer exceeds sb width */
211     c.X = sbSize.X - 3; c.Y = 0;
212     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
213
214     ret = WriteConsole(hCon, mytest, mylen, &len, NULL);
215     ok(ret != 0 && len == mylen, "Couldn't write, ret = %d, len = %d\n", ret, len);
216     c.Y = 0;
217     for (p = mylen - 3; p < mylen; p++)
218     {
219         c.X = sbSize.X - 3 + p % 3;
220         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
221     }
222
223     c.X = 0; c.Y = 1;
224     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
225
226     p = sbSize.X - 3 + mylen % 3;
227     c.X = p; c.Y = 0;
228
229     /* write line, wrapping disabled, strings end on end of line */
230     c.X = sbSize.X - mylen; c.Y = 0;
231     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
232
233     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
234 }
235
236 static void testWriteNotWrappedProcessed(HANDLE hCon, COORD sbSize)
237 {
238     COORD               c;
239     DWORD               len, mode;
240     const char*         mytest = "abcd\nf\tg";
241     const int   mylen = strlen(mytest);
242     const int   mylen2 = strchr(mytest, '\n') - mytest;
243     int                 p;
244
245     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, (mode | ENABLE_PROCESSED_OUTPUT) & ~ENABLE_WRAP_AT_EOL_OUTPUT),
246        "clearing wrap at EOL & setting processed output\n");
247
248     /* write line, wrapping disabled, buffer exceeds sb width */
249     c.X = sbSize.X - 5; c.Y = 0;
250     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-5\n");
251
252     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
253     c.Y = 0;
254     for (c.X = sbSize.X - 5; c.X < sbSize.X - 1; c.X++)
255     {
256         okCHAR(hCon, c, mytest[c.X - sbSize.X + 5], TEST_ATTRIB);
257     }
258     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
259
260     c.X = 0; c.Y++;
261     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
262     for (c.X = 1; c.X < 8; c.X++)
263         okCHAR(hCon, c, ' ', TEST_ATTRIB);
264     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
265     c.X++;
266     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
267
268     okCURSOR(hCon, c);
269
270     /* write line, wrapping disabled, strings end on end of line */
271     c.X = sbSize.X - 4; c.Y = 0;
272     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-4\n");
273
274     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
275     c.Y = 0;
276     for (c.X = sbSize.X - 4; c.X < sbSize.X; c.X++)
277     {
278         okCHAR(hCon, c, mytest[c.X - sbSize.X + 4], TEST_ATTRIB);
279     }
280     c.X = 0; c.Y++;
281     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
282     for (c.X = 1; c.X < 8; c.X++)
283         okCHAR(hCon, c, ' ', TEST_ATTRIB);
284     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
285     c.X++;
286     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
287
288     okCURSOR(hCon, c);
289
290     /* write line, wrapping disabled, strings end after end of line */
291     c.X = sbSize.X - 3; c.Y = 0;
292     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-4\n");
293
294     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
295     c.Y = 0;
296     for (p = mylen2 - 3; p < mylen2; p++)
297     {
298         c.X = sbSize.X - 3 + p % 3;
299         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
300     }
301     c.X = 0; c.Y = 1;
302     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
303     for (c.X = 1; c.X < 8; c.X++)
304         okCHAR(hCon, c, ' ', TEST_ATTRIB);
305     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
306     c.X++;
307     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
308
309     okCURSOR(hCon, c);
310 }
311
312 static void testWriteWrappedNotProcessed(HANDLE hCon, COORD sbSize)
313 {
314     COORD               c;
315     DWORD               len, mode;
316     const char*         mytest = "abcd\nf\tg";
317     const int   mylen = strlen(mytest);
318     int                 p;
319
320     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon,(mode | ENABLE_WRAP_AT_EOL_OUTPUT) & ~(ENABLE_PROCESSED_OUTPUT)),
321        "setting wrap at EOL & clearing processed output\n");
322
323     /* write line, wrapping enabled, buffer doesn't exceed sb width */
324     c.X = sbSize.X - 9; c.Y = 0;
325     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-9\n");
326
327     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
328     c.Y = 0;
329     for (p = 0; p < mylen; p++)
330     {
331         c.X = sbSize.X - 9 + p;
332         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
333     }
334     c.X = sbSize.X - 9 + mylen;
335     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
336     c.X = 0; c.Y = 1;
337     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
338
339     /* write line, wrapping enabled, buffer does exceed sb width */
340     c.X = sbSize.X - 3; c.Y = 0;
341     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
342
343     c.Y = 1;
344     c.X = mylen - 3;
345     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
346 }
347
348 static void testWriteWrappedProcessed(HANDLE hCon, COORD sbSize)
349 {
350     COORD               c;
351     DWORD               len, mode;
352     const char*         mytest = "abcd\nf\tg";
353     const int   mylen = strlen(mytest);
354     int                 p;
355
356     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode | (ENABLE_WRAP_AT_EOL_OUTPUT|ENABLE_PROCESSED_OUTPUT)),
357        "setting wrap at EOL & processed output\n");
358
359     /* write line, wrapping enabled, buffer doesn't exceed sb width */
360     c.X = sbSize.X - 9; c.Y = 0;
361     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-9\n");
362
363     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
364     for (p = 0; p < 4; p++)
365     {
366         c.X = sbSize.X - 9 + p;
367         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
368     }
369     c.X = sbSize.X - 9 + p;
370     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
371     c.X = 0; c.Y++;
372     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
373     for (c.X = 1; c.X < 8; c.X++)
374         okCHAR(hCon, c, ' ', TEST_ATTRIB);
375     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
376     c.X++;
377     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
378     okCURSOR(hCon, c);
379
380     /* write line, wrapping enabled, buffer does exceed sb width */
381     c.X = sbSize.X - 3; c.Y = 2;
382     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
383
384     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
385     for (p = 0; p < 3; p++)
386     {
387         c.X = sbSize.X - 3 + p;
388         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
389     }
390     c.X = 0; c.Y++;
391     okCHAR(hCon, c, mytest[3], TEST_ATTRIB);
392     c.X++;
393     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
394
395     c.X = 0; c.Y++;
396     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
397     for (c.X = 1; c.X < 8; c.X++)
398         okCHAR(hCon, c, ' ', TEST_ATTRIB);
399     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
400     c.X++;
401     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
402     okCURSOR(hCon, c);
403 }
404
405 static void testWrite(HANDLE hCon, COORD sbSize)
406 {
407     /* FIXME: should in fact insure that the sb is at least 10 character wide */
408     ok(SetConsoleTextAttribute(hCon, TEST_ATTRIB), "Setting default text color\n");
409     resetContent(hCon, sbSize, FALSE);
410     testWriteSimple(hCon, sbSize);
411     resetContent(hCon, sbSize, FALSE);
412     testWriteNotWrappedNotProcessed(hCon, sbSize);
413     resetContent(hCon, sbSize, FALSE);
414     testWriteNotWrappedProcessed(hCon, sbSize);
415     resetContent(hCon, sbSize, FALSE);
416     testWriteWrappedNotProcessed(hCon, sbSize);
417     resetContent(hCon, sbSize, FALSE);
418     testWriteWrappedProcessed(hCon, sbSize);
419 }
420
421 static void testScroll(HANDLE hCon, COORD sbSize)
422 {
423     SMALL_RECT  scroll, clip;
424     COORD       dst, c, tc;
425     CHAR_INFO   ci;
426     BOOL ret;
427
428 #define W 11
429 #define H 7
430
431 #define IN_SRECT(r,c) ((r).Left <= (c).X && (c).X <= (r).Right && (r).Top <= (c).Y && (c).Y <= (r).Bottom)
432 #define IN_SRECT2(r,d,c) ((d).X <= (c).X && (c).X <= (d).X + (r).Right - (r).Left && (d).Y <= (c).Y && (c).Y <= (d).Y + (r).Bottom - (r).Top)
433
434     /* no clipping, src & dst rect don't overlap */
435     resetContent(hCon, sbSize, TRUE);
436
437     scroll.Left = 0;
438     scroll.Right = W - 1;
439     scroll.Top = 0;
440     scroll.Bottom = H - 1;
441     dst.X = W + 3;
442     dst.Y = H + 3;
443     ci.Char.UnicodeChar = '#';
444     ci.Attributes = TEST_ATTRIB;
445
446     clip.Left = 0;
447     clip.Right = sbSize.X - 1;
448     clip.Top = 0;
449     clip.Bottom = sbSize.Y - 1;
450
451     ok(ScrollConsoleScreenBuffer(hCon, &scroll, NULL, dst, &ci), "Scrolling SB\n");
452
453     for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
454     {
455         for (c.X = 0; c.X < sbSize.X; c.X++)
456         {
457             if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
458             {
459                 tc.X = c.X - dst.X;
460                 tc.Y = c.Y - dst.Y;
461                 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
462             }
463             else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
464                 okCHAR(hCon, c, '#', TEST_ATTRIB);
465             else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
466         }
467     }
468
469     /* no clipping, src & dst rect do overlap */
470     resetContent(hCon, sbSize, TRUE);
471
472     scroll.Left = 0;
473     scroll.Right = W - 1;
474     scroll.Top = 0;
475     scroll.Bottom = H - 1;
476     dst.X = W /2;
477     dst.Y = H / 2;
478     ci.Char.UnicodeChar = '#';
479     ci.Attributes = TEST_ATTRIB;
480
481     clip.Left = 0;
482     clip.Right = sbSize.X - 1;
483     clip.Top = 0;
484     clip.Bottom = sbSize.Y - 1;
485
486     ok(ScrollConsoleScreenBuffer(hCon, &scroll, NULL, dst, &ci), "Scrolling SB\n");
487
488     for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
489     {
490         for (c.X = 0; c.X < sbSize.X; c.X++)
491         {
492             if (dst.X <= c.X && c.X < dst.X + W && dst.Y <= c.Y && c.Y < dst.Y + H)
493             {
494                 tc.X = c.X - dst.X;
495                 tc.Y = c.Y - dst.Y;
496                 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
497             }
498             else if (c.X < W && c.Y < H) okCHAR(hCon, c, '#', TEST_ATTRIB);
499             else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
500         }
501     }
502
503     /* clipping, src & dst rect don't overlap */
504     resetContent(hCon, sbSize, TRUE);
505
506     scroll.Left = 0;
507     scroll.Right = W - 1;
508     scroll.Top = 0;
509     scroll.Bottom = H - 1;
510     dst.X = W + 3;
511     dst.Y = H + 3;
512     ci.Char.UnicodeChar = '#';
513     ci.Attributes = TEST_ATTRIB;
514
515     clip.Left = W / 2;
516     clip.Right = min(W + W / 2, sbSize.X - 1);
517     clip.Top = H / 2;
518     clip.Bottom = min(H + H / 2, sbSize.Y - 1);
519
520     SetLastError(0xdeadbeef);
521     ret = ScrollConsoleScreenBuffer(hCon, &scroll, &clip, dst, &ci);
522     if (ret)
523     {
524         for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
525         {
526             for (c.X = 0; c.X < sbSize.X; c.X++)
527             {
528                 if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
529                 {
530                     tc.X = c.X - dst.X;
531                     tc.Y = c.Y - dst.Y;
532                     okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
533                 }
534                 else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
535                     okCHAR(hCon, c, '#', TEST_ATTRIB);
536                 else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
537             }
538         }
539     }
540     else
541     {
542         /* Win9x will fail, Only accept ERROR_NOT_ENOUGH_MEMORY */
543         ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY,
544             "Expected ERROR_NOT_ENOUGH_MEMORY, got %u\n", GetLastError());
545     }
546
547     /* clipping, src & dst rect do overlap */
548     resetContent(hCon, sbSize, TRUE);
549
550     scroll.Left = 0;
551     scroll.Right = W - 1;
552     scroll.Top = 0;
553     scroll.Bottom = H - 1;
554     dst.X = W / 2 - 3;
555     dst.Y = H / 2 - 3;
556     ci.Char.UnicodeChar = '#';
557     ci.Attributes = TEST_ATTRIB;
558
559     clip.Left = W / 2;
560     clip.Right = min(W + W / 2, sbSize.X - 1);
561     clip.Top = H / 2;
562     clip.Bottom = min(H + H / 2, sbSize.Y - 1);
563
564     ok(ScrollConsoleScreenBuffer(hCon, &scroll, &clip, dst, &ci), "Scrolling SB\n");
565
566     for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
567     {
568         for (c.X = 0; c.X < sbSize.X; c.X++)
569         {
570             if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
571             {
572                 tc.X = c.X - dst.X;
573                 tc.Y = c.Y - dst.Y;
574                 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
575             }
576             else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
577                 okCHAR(hCon, c, '#', TEST_ATTRIB);
578             else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
579         }
580     }
581 }
582
583 static int mch_count;
584 /* we need the event as Wine console event generation isn't synchronous
585  * (ie GenerateConsoleCtrlEvent returns before all ctrl-handlers in all
586  * processes have been called).
587  */
588 static HANDLE mch_event;
589 static BOOL WINAPI mch(DWORD event)
590 {
591     mch_count++;
592     SetEvent(mch_event);
593     return TRUE;
594 }
595
596 static void testCtrlHandler(void)
597 {
598     ok(!SetConsoleCtrlHandler(mch, FALSE), "Shouldn't succeed\n");
599     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %u\n", GetLastError());
600     ok(SetConsoleCtrlHandler(mch, TRUE), "Couldn't set handler\n");
601     /* wine requires the event for the test, as we cannot insure, so far, that event
602      * are processed synchronously in GenerateConsoleCtrlEvent()
603      */
604     mch_event = CreateEventA(NULL, TRUE, FALSE, NULL);
605     mch_count = 0;
606     ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n");
607     /* FIXME: it isn't synchronous on wine but it can still happen before we test */
608     if (0) ok(mch_count == 1, "Event isn't synchronous\n");
609     ok(WaitForSingleObject(mch_event, 3000) == WAIT_OBJECT_0, "event sending didn't work\n");
610     CloseHandle(mch_event);
611
612     /* Turning off ctrl-c handling doesn't work on win9x such way ... */
613     ok(SetConsoleCtrlHandler(NULL, TRUE), "Couldn't turn off ctrl-c handling\n");
614     mch_event = CreateEventA(NULL, TRUE, FALSE, NULL);
615     mch_count = 0;
616     if(!(GetVersion() & 0x80000000))
617         /* ... and next line leads to an unhandled exception on 9x.  Avoid it on 9x. */
618         ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n");
619     ok(WaitForSingleObject(mch_event, 3000) == WAIT_TIMEOUT && mch_count == 0, "Event shouldn't have been sent\n");
620     CloseHandle(mch_event);
621     ok(SetConsoleCtrlHandler(mch, FALSE), "Couldn't remove handler\n");
622     ok(!SetConsoleCtrlHandler(mch, FALSE), "Shouldn't succeed\n");
623     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %u\n", GetLastError());
624 }
625
626 /*
627  * Test console screen buffer:
628  * 1) Try to set invalid handle.
629  * 2) Try to set non-console handles.
630  * 3) Use CONOUT$ file as active SB.
631  * 4) Test cursor.
632  * 5) Test output codepage to show it is not a property of SB.
633  * 6) Test switching to old SB if we close all handles to current SB - works
634  * in Windows, TODO in wine.
635  *
636  * What is not tested but should be:
637  * 1) ScreenBufferInfo
638  */
639 static void testScreenBuffer(HANDLE hConOut)
640 {
641     HANDLE hConOutRW, hConOutRO, hConOutWT;
642     HANDLE hFileOutRW, hFileOutRO, hFileOutWT;
643     HANDLE hConOutNew;
644     char test_str1[] = "Test for SB1";
645     char test_str2[] = "Test for SB2";
646     char test_cp866[] = {0xe2, 0xa5, 0xe1, 0xe2, 0};
647     char test_cp1251[] = {0xf2, 0xe5, 0xf1, 0xf2, 0};
648     WCHAR test_unicode[] = {0x0442, 0x0435, 0x0441, 0x0442, 0};
649     WCHAR str_wbuf[20];
650     char str_buf[20];
651     DWORD len;
652     COORD c;
653     BOOL ret;
654     DWORD oldcp;
655
656     if (!IsValidCodePage(866))
657     {
658         skip("Codepage 866 not available\n");
659         return;
660     }
661
662     /* In the beginning set output codepage to 866 */
663     oldcp = GetConsoleOutputCP();
664     SetLastError(0xdeadbeef);
665     ret = SetConsoleOutputCP(866);
666     if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
667     {
668         skip("SetConsoleOutputCP is not implemented\n");
669         return;
670     }
671     ok(ret, "Cannot set output codepage to 866\n");
672
673     hConOutRW = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
674                          FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
675                          CONSOLE_TEXTMODE_BUFFER, NULL);
676     ok(hConOutRW != INVALID_HANDLE_VALUE,
677        "Cannot create a new screen buffer for ReadWrite\n");
678     hConOutRO = CreateConsoleScreenBuffer(GENERIC_READ,
679                          FILE_SHARE_READ, NULL,
680                          CONSOLE_TEXTMODE_BUFFER, NULL);
681     ok(hConOutRO != INVALID_HANDLE_VALUE,
682        "Cannot create a new screen buffer for ReadOnly\n");
683     hConOutWT = CreateConsoleScreenBuffer(GENERIC_WRITE,
684                          FILE_SHARE_WRITE, NULL,
685                          CONSOLE_TEXTMODE_BUFFER, NULL);
686     ok(hConOutWT != INVALID_HANDLE_VALUE,
687        "Cannot create a new screen buffer for WriteOnly\n");
688
689     hFileOutRW = CreateFileA("NUL", GENERIC_READ | GENERIC_WRITE,
690                              FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
691                              OPEN_EXISTING, 0, NULL);
692     ok(hFileOutRW != INVALID_HANDLE_VALUE, "Cannot open NUL for ReadWrite\n");
693     hFileOutRO = CreateFileA("NUL", GENERIC_READ, FILE_SHARE_READ,
694                              NULL, OPEN_EXISTING, 0, NULL);
695     ok(hFileOutRO != INVALID_HANDLE_VALUE, "Cannot open NUL for ReadOnly\n");
696     hFileOutWT = CreateFileA("NUL", GENERIC_WRITE, FILE_SHARE_WRITE,
697                              NULL, OPEN_EXISTING, 0, NULL);
698     ok(hFileOutWT != INVALID_HANDLE_VALUE, "Cannot open NUL for WriteOnly\n");
699
700     /* Trying to set invalid handle */
701     SetLastError(0);
702     ok(!SetConsoleActiveScreenBuffer(INVALID_HANDLE_VALUE),
703        "Shouldn't succeed\n");
704     ok(GetLastError() == ERROR_INVALID_HANDLE,
705        "GetLastError: expecting %u got %u\n",
706        ERROR_INVALID_HANDLE, GetLastError());
707
708     /* Trying to set non-console handles */
709     SetLastError(0);
710     ok(!SetConsoleActiveScreenBuffer(hFileOutRW), "Shouldn't succeed\n");
711     ok(GetLastError() == ERROR_INVALID_HANDLE,
712        "GetLastError: expecting %u got %u\n",
713        ERROR_INVALID_HANDLE, GetLastError());
714
715     SetLastError(0);
716     ok(!SetConsoleActiveScreenBuffer(hFileOutRO), "Shouldn't succeed\n");
717     ok(GetLastError() == ERROR_INVALID_HANDLE,
718        "GetLastError: expecting %u got %u\n",
719        ERROR_INVALID_HANDLE, GetLastError());
720
721     SetLastError(0);
722     ok(!SetConsoleActiveScreenBuffer(hFileOutWT), "Shouldn't succeed\n");
723     ok(GetLastError() == ERROR_INVALID_HANDLE,
724        "GetLastError: expecting %u got %u\n",
725        ERROR_INVALID_HANDLE, GetLastError());
726
727     CloseHandle(hFileOutRW);
728     CloseHandle(hFileOutRO);
729     CloseHandle(hFileOutWT);
730
731     /* Trying to set SB handles with various access modes */
732     SetLastError(0);
733     ok(!SetConsoleActiveScreenBuffer(hConOutRO), "Shouldn't succeed\n");
734     ok(GetLastError() == ERROR_INVALID_HANDLE,
735        "GetLastError: expecting %u got %u\n",
736        ERROR_INVALID_HANDLE, GetLastError());
737
738     ok(SetConsoleActiveScreenBuffer(hConOutWT), "Couldn't set new WriteOnly SB\n");
739
740     ok(SetConsoleActiveScreenBuffer(hConOutRW), "Couldn't set new ReadWrite SB\n");
741
742     CloseHandle(hConOutWT);
743     CloseHandle(hConOutRO);
744
745     /* Now we have two ReadWrite SB, active must be hConOutRW */
746     /* Open current SB via CONOUT$ */
747     hConOutNew = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0,
748                              NULL, OPEN_EXISTING, 0, 0);
749     ok(hConOutNew != INVALID_HANDLE_VALUE, "CONOUT$ is not opened\n");
750
751
752     /* test cursor */
753     c.X = c.Y = 10;
754     SetConsoleCursorPosition(hConOut, c);
755     c.X = c.Y = 5;
756     SetConsoleCursorPosition(hConOutRW, c);
757     okCURSOR(hConOutNew, c);
758     c.X = c.Y = 10;
759     okCURSOR(hConOut, c);
760
761
762     c.X = c.Y = 0;
763
764     /* Write using hConOutNew... */
765     SetConsoleCursorPosition(hConOutNew, c);
766     ret = WriteConsoleA(hConOutNew, test_str2, lstrlenA(test_str2), &len, NULL);
767     ok (ret && len == lstrlenA(test_str2), "WriteConsoleA failed\n");
768     /* ... and read it back via hConOutRW */
769     ret = ReadConsoleOutputCharacterA(hConOutRW, str_buf, lstrlenA(test_str2), c, &len);
770     ok(ret && len == lstrlenA(test_str2), "ReadConsoleOutputCharacterA failed\n");
771     str_buf[lstrlenA(test_str2)] = 0;
772     ok(!lstrcmpA(str_buf, test_str2), "got '%s' expected '%s'\n", str_buf, test_str2);
773
774
775     /* Now test output codepage handling. Current is 866 as we set earlier. */
776     SetConsoleCursorPosition(hConOutRW, c);
777     ret = WriteConsoleA(hConOutRW, test_cp866, lstrlenA(test_cp866), &len, NULL);
778     ok(ret && len == lstrlenA(test_cp866), "WriteConsoleA failed\n");
779     ret = ReadConsoleOutputCharacterW(hConOutRW, str_wbuf, lstrlenA(test_cp866), c, &len);
780     ok(ret && len == lstrlenA(test_cp866), "ReadConsoleOutputCharacterW failed\n");
781     str_wbuf[lstrlenA(test_cp866)] = 0;
782     ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n");
783
784     /*
785      * cp866 is OK, let's switch to cp1251.
786      * We expect that this codepage will be used in every SB - active and not.
787      */
788     ok(SetConsoleOutputCP(1251), "Cannot set output cp to 1251\n");
789     SetConsoleCursorPosition(hConOutRW, c);
790     ret = WriteConsoleA(hConOutRW, test_cp1251, lstrlenA(test_cp1251), &len, NULL);
791     ok(ret && len == lstrlenA(test_cp1251), "WriteConsoleA failed\n");
792     ret = ReadConsoleOutputCharacterW(hConOutRW, str_wbuf, lstrlenA(test_cp1251), c, &len);
793     ok(ret && len == lstrlenA(test_cp1251), "ReadConsoleOutputCharacterW failed\n");
794     str_wbuf[lstrlenA(test_cp1251)] = 0;
795     ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n");
796
797     /* Check what has happened to hConOut. */
798     SetConsoleCursorPosition(hConOut, c);
799     ret = WriteConsoleA(hConOut, test_cp1251, lstrlenA(test_cp1251), &len, NULL);
800     ok(ret && len == lstrlenA(test_cp1251), "WriteConsoleA failed\n");
801     ret = ReadConsoleOutputCharacterW(hConOut, str_wbuf, lstrlenA(test_cp1251), c, &len);
802     ok(ret && len == lstrlenA(test_cp1251), "ReadConsoleOutputCharacterW failed\n");
803     str_wbuf[lstrlenA(test_cp1251)] = 0;
804     ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n");
805
806     /* Close all handles of current console SB */
807     CloseHandle(hConOutNew);
808     CloseHandle(hConOutRW);
809
810     /* Now active SB should be hConOut */
811     hConOutNew = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0,
812                              NULL, OPEN_EXISTING, 0, 0);
813     ok(hConOutNew != INVALID_HANDLE_VALUE, "CONOUT$ is not opened\n");
814
815     /* Write using hConOutNew... */
816     SetConsoleCursorPosition(hConOutNew, c);
817     ret = WriteConsoleA(hConOutNew, test_str1, lstrlenA(test_str1), &len, NULL);
818     ok (ret && len == lstrlenA(test_str1), "WriteConsoleA failed\n");
819     /* ... and read it back via hConOut */
820     ret = ReadConsoleOutputCharacterA(hConOut, str_buf, lstrlenA(test_str1), c, &len);
821     ok(ret && len == lstrlenA(test_str1), "ReadConsoleOutputCharacterA failed\n");
822     str_buf[lstrlenA(test_str1)] = 0;
823     todo_wine ok(!lstrcmpA(str_buf, test_str1), "got '%s' expected '%s'\n", str_buf, test_str1);
824     CloseHandle(hConOutNew);
825
826     /* This is not really needed under Windows */
827     SetConsoleActiveScreenBuffer(hConOut);
828
829     /* restore codepage */
830     SetConsoleOutputCP(oldcp);
831 }
832
833 static void test_GetSetConsoleInputExeName(void)
834 {
835     BOOL ret;
836     DWORD error;
837     char buffer[MAX_PATH], module[MAX_PATH], *p;
838     static char input_exe[MAX_PATH] = "winetest.exe";
839
840     SetLastError(0xdeadbeef);
841     ret = pGetConsoleInputExeNameA(0, NULL);
842     error = GetLastError();
843     ok(ret, "GetConsoleInputExeNameA failed\n");
844     ok(error == ERROR_BUFFER_OVERFLOW, "got %u expected ERROR_BUFFER_OVERFLOW\n", error);
845
846     SetLastError(0xdeadbeef);
847     ret = pGetConsoleInputExeNameA(0, buffer);
848     error = GetLastError();
849     ok(ret, "GetConsoleInputExeNameA failed\n");
850     ok(error == ERROR_BUFFER_OVERFLOW, "got %u expected ERROR_BUFFER_OVERFLOW\n", error);
851
852     GetModuleFileNameA(GetModuleHandle(NULL), module, sizeof(module));
853     p = strrchr(module, '\\') + 1;
854
855     ret = pGetConsoleInputExeNameA(sizeof(buffer)/sizeof(buffer[0]), buffer);
856     ok(ret, "GetConsoleInputExeNameA failed\n");
857     todo_wine ok(!lstrcmpA(buffer, p), "got %s expected %s\n", buffer, p);
858
859     SetLastError(0xdeadbeef);
860     ret = pSetConsoleInputExeNameA(NULL);
861     error = GetLastError();
862     ok(!ret, "SetConsoleInputExeNameA failed\n");
863     ok(error == ERROR_INVALID_PARAMETER, "got %u expected ERROR_INVALID_PARAMETER\n", error);
864
865     SetLastError(0xdeadbeef);
866     ret = pSetConsoleInputExeNameA("");
867     error = GetLastError();
868     ok(!ret, "SetConsoleInputExeNameA failed\n");
869     ok(error == ERROR_INVALID_PARAMETER, "got %u expected ERROR_INVALID_PARAMETER\n", error);
870
871     ret = pSetConsoleInputExeNameA(input_exe);
872     ok(ret, "SetConsoleInputExeNameA failed\n");
873
874     ret = pGetConsoleInputExeNameA(sizeof(buffer)/sizeof(buffer[0]), buffer);
875     ok(ret, "GetConsoleInputExeNameA failed\n");
876     ok(!lstrcmpA(buffer, input_exe), "got %s expected %s\n", buffer, input_exe);
877 }
878
879 START_TEST(console)
880 {
881     HANDLE hConIn, hConOut;
882     BOOL ret;
883     CONSOLE_SCREEN_BUFFER_INFO  sbi;
884
885     init_function_pointers();
886
887     /* be sure we have a clean console (and that's our own)
888      * FIXME: this will make the test fail (currently) if we don't run
889      * under X11
890      * Another solution would be to rerun the test under wineconsole with
891      * the curses backend
892      */
893
894     /* first, we detach and open a fresh console to play with */
895     FreeConsole();
896     ok(AllocConsole(), "Couldn't alloc console\n");
897     hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
898     hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
899
900     /* now verify everything's ok */
901     ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n");
902     ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n");
903
904     ok(ret = GetConsoleScreenBufferInfo(hConOut, &sbi), "Getting sb info\n");
905     if (!ret) return;
906
907     /* Non interactive tests */
908     testCursor(hConOut, sbi.dwSize);
909     /* test parameters (FIXME: test functionality) */
910     testCursorInfo(hConOut);
911     /* will test wrapped (on/off) & processed (on/off) strings output */
912     testWrite(hConOut, sbi.dwSize);
913     /* will test line scrolling at the bottom of the screen */
914     /* testBottomScroll(); */
915     /* will test all the scrolling operations */
916     testScroll(hConOut, sbi.dwSize);
917     /* will test sb creation / modification / codepage handling */
918     testScreenBuffer(hConOut);
919     testCtrlHandler();
920     /* still to be done: access rights & access on objects */
921
922     if (!pGetConsoleInputExeNameA || !pSetConsoleInputExeNameA)
923     {
924         skip("GetConsoleInputExeNameA and/or SetConsoleInputExeNameA is not available\n");
925         return;
926     }
927     else
928         test_GetSetConsoleInputExeName();
929 }