mshtml: Correct test for another unknown dispID.
[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 DWORD (WINAPI *pGetConsoleProcessList)(LPDWORD, DWORD);
28 static HANDLE (WINAPI *pOpenConsoleW)(LPCWSTR,DWORD,BOOL,DWORD);
29 static BOOL (WINAPI *pSetConsoleInputExeNameA)(LPCSTR);
30
31 /* DEFAULT_ATTRIB is used for all initial filling of the console.
32  * all modifications are made with TEST_ATTRIB so that we could check
33  * what has to be modified or not
34  */
35 #define TEST_ATTRIB    (BACKGROUND_BLUE | FOREGROUND_GREEN)
36 #define DEFAULT_ATTRIB (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED)
37 /* when filling the screen with non-blank chars, this macro defines
38  * what character should be at position 'c'
39  */
40 #define CONTENT(c)    ('A' + (((c).Y * 17 + (c).X) % 23))
41
42 #define okCURSOR(hCon, c) do { \
43   CONSOLE_SCREEN_BUFFER_INFO __sbi; \
44   BOOL expect = GetConsoleScreenBufferInfo((hCon), &__sbi) && \
45                 __sbi.dwCursorPosition.X == (c).X && __sbi.dwCursorPosition.Y == (c).Y; \
46   ok(expect, "Expected cursor at (%d,%d), got (%d,%d)\n", \
47      (c).X, (c).Y, __sbi.dwCursorPosition.X, __sbi.dwCursorPosition.Y); \
48 } while (0)
49
50 #define okCHAR(hCon, c, ch, attr) do { \
51   char __ch; WORD __attr; DWORD __len; BOOL expect; \
52   expect = ReadConsoleOutputCharacter((hCon), &__ch, 1, (c), &__len) == 1 && __len == 1 && __ch == (ch); \
53   ok(expect, "At (%d,%d): expecting char '%c'/%02x got '%c'/%02x\n", (c).X, (c).Y, (ch), (ch), __ch, __ch); \
54   expect = ReadConsoleOutputAttribute((hCon), &__attr, 1, (c), &__len) == 1 && __len == 1 && __attr == (attr); \
55   ok(expect, "At (%d,%d): expecting attr %04x got %04x\n", (c).X, (c).Y, (attr), __attr); \
56 } while (0)
57
58 static void init_function_pointers(void)
59 {
60     HMODULE hKernel32;
61
62 #define KERNEL32_GET_PROC(func)                                     \
63     p##func = (void *)GetProcAddress(hKernel32, #func);             \
64     if(!p##func) trace("GetProcAddress(hKernel32, '%s') failed\n", #func);
65
66     hKernel32 = GetModuleHandleA("kernel32.dll");
67     KERNEL32_GET_PROC(GetConsoleInputExeNameA);
68     KERNEL32_GET_PROC(GetConsoleProcessList);
69     KERNEL32_GET_PROC(OpenConsoleW);
70     KERNEL32_GET_PROC(SetConsoleInputExeNameA);
71
72 #undef KERNEL32_GET_PROC
73 }
74
75 /* FIXME: this could be optimized on a speed point of view */
76 static void resetContent(HANDLE hCon, COORD sbSize, BOOL content)
77 {
78     COORD       c;
79     WORD        attr = DEFAULT_ATTRIB;
80     char        ch;
81     DWORD       len;
82
83     for (c.X = 0; c.X < sbSize.X; c.X++)
84     {
85         for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
86         {
87             ch = (content) ? CONTENT(c) : ' ';
88             WriteConsoleOutputAttribute(hCon, &attr, 1, c, &len);
89             WriteConsoleOutputCharacterA(hCon, &ch, 1, c, &len);
90         }
91     }
92 }
93
94 static void testCursor(HANDLE hCon, COORD sbSize)
95 {
96     COORD               c;
97
98     c.X = c.Y = 0;
99     ok(SetConsoleCursorPosition(0, c) == 0, "No handle\n");
100     ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n",
101        ERROR_INVALID_HANDLE, GetLastError());
102
103     c.X = c.Y = 0;
104     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
105     okCURSOR(hCon, c);
106
107     c.X = sbSize.X - 1;
108     c.Y = sbSize.Y - 1;
109     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in lower-right\n");
110     okCURSOR(hCon, c);
111
112     c.X = sbSize.X;
113     c.Y = sbSize.Y - 1;
114     ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
115     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n",
116        ERROR_INVALID_PARAMETER, GetLastError());
117
118     c.X = sbSize.X - 1;
119     c.Y = sbSize.Y;
120     ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
121     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n",
122        ERROR_INVALID_PARAMETER, GetLastError());
123
124     c.X = -1;
125     c.Y = 0;
126     ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
127     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n",
128        ERROR_INVALID_PARAMETER, GetLastError());
129
130     c.X = 0;
131     c.Y = -1;
132     ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
133     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n",
134        ERROR_INVALID_PARAMETER, GetLastError());
135 }
136
137 static void testCursorInfo(HANDLE hCon)
138 {
139     BOOL ret;
140     CONSOLE_CURSOR_INFO info;
141
142     SetLastError(0xdeadbeef);
143     ret = GetConsoleCursorInfo(NULL, NULL);
144     ok(!ret, "Expected failure\n");
145     ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n",
146        ERROR_INVALID_HANDLE, GetLastError());
147
148     SetLastError(0xdeadbeef);
149     info.dwSize = -1;
150     ret = GetConsoleCursorInfo(NULL, &info);
151     ok(!ret, "Expected failure\n");
152     ok(info.dwSize == -1, "Expected no change for dwSize\n");
153     ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n",
154        ERROR_INVALID_HANDLE, GetLastError());
155
156     /* Test the correct call first to distinguish between win9x and the rest */
157     SetLastError(0xdeadbeef);
158     ret = GetConsoleCursorInfo(hCon, &info);
159     ok(ret, "Expected success\n");
160     ok(info.dwSize == 25 ||
161        info.dwSize == 12 /* win9x */,
162        "Expected 12 or 25, got %d\n", info.dwSize);
163     ok(info.bVisible, "Expected the cursor to be visible\n");
164     ok(GetLastError() == 0xdeadbeef, "GetLastError: expecting %u got %u\n",
165        0xdeadbeef, GetLastError());
166
167     /* Don't test NULL CONSOLE_CURSOR_INFO, it crashes on win9x and win7 */
168 }
169
170 static void testEmptyWrite(HANDLE hCon)
171 {
172     COORD               c;
173     DWORD               len;
174     const char*         mytest = "";
175
176     c.X = c.Y = 0;
177     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
178
179     len = -1;
180     ok(WriteConsole(hCon, NULL, 0, &len, NULL) != 0 && len == 0, "WriteConsole\n");
181     okCURSOR(hCon, c);
182
183     /* Passing a NULL lpBuffer with sufficiently large non-zero length succeeds
184      * on native Windows and result in memory-like contents being written to
185      * the console. Calling WriteConsoleW like this will crash on Wine. */
186     if (0)
187     {
188         len = -1;
189         ok(!WriteConsole(hCon, NULL, 16, &len, NULL) && len == -1, "WriteConsole\n");
190         okCURSOR(hCon, c);
191
192         /* Cursor advances for this call. */
193         len = -1;
194         ok(WriteConsole(hCon, NULL, 128, &len, NULL) != 0 && len == 128, "WriteConsole\n");
195     }
196
197     len = -1;
198     ok(WriteConsole(hCon, mytest, 0, &len, NULL) != 0 && len == 0, "WriteConsole\n");
199     okCURSOR(hCon, c);
200
201     /* WriteConsole does not halt on a null terminator and is happy to write
202      * memory contents beyond the actual size of the buffer. */
203     len = -1;
204     ok(WriteConsole(hCon, mytest, 16, &len, NULL) != 0 && len == 16, "WriteConsole\n");
205     c.X += 16;
206     okCURSOR(hCon, c);
207 }
208
209 static void testWriteSimple(HANDLE hCon)
210 {
211     COORD               c;
212     DWORD               len;
213     const char*         mytest = "abcdefg";
214     const int   mylen = strlen(mytest);
215
216     /* single line write */
217     c.X = c.Y = 0;
218     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
219
220     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
221     c.Y = 0;
222     for (c.X = 0; c.X < mylen; c.X++)
223     {
224         okCHAR(hCon, c, mytest[c.X], TEST_ATTRIB);
225     }
226
227     okCURSOR(hCon, c);
228     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
229 }
230
231 static void testWriteNotWrappedNotProcessed(HANDLE hCon, COORD sbSize)
232 {
233     COORD               c;
234     DWORD               len, mode;
235     const char*         mytest = "123";
236     const int           mylen = strlen(mytest);
237     int                 ret;
238     int                 p;
239
240     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode & ~(ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT)),
241        "clearing wrap at EOL & processed output\n");
242
243     /* write line, wrapping disabled, buffer exceeds sb width */
244     c.X = sbSize.X - 3; c.Y = 0;
245     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
246
247     ret = WriteConsole(hCon, mytest, mylen, &len, NULL);
248     ok(ret != 0 && len == mylen, "Couldn't write, ret = %d, len = %d\n", ret, len);
249     c.Y = 0;
250     for (p = mylen - 3; p < mylen; p++)
251     {
252         c.X = sbSize.X - 3 + p % 3;
253         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
254     }
255
256     c.X = 0; c.Y = 1;
257     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
258
259     p = sbSize.X - 3 + mylen % 3;
260     c.X = p; c.Y = 0;
261
262     /* write line, wrapping disabled, strings end on end of line */
263     c.X = sbSize.X - mylen; c.Y = 0;
264     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
265
266     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
267 }
268
269 static void testWriteNotWrappedProcessed(HANDLE hCon, COORD sbSize)
270 {
271     COORD               c;
272     DWORD               len, mode;
273     const char*         mytest = "abcd\nf\tg";
274     const int   mylen = strlen(mytest);
275     const int   mylen2 = strchr(mytest, '\n') - mytest;
276     int                 p;
277     WORD                attr;
278
279     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, (mode | ENABLE_PROCESSED_OUTPUT) & ~ENABLE_WRAP_AT_EOL_OUTPUT),
280        "clearing wrap at EOL & setting processed output\n");
281
282     /* write line, wrapping disabled, buffer exceeds sb width */
283     c.X = sbSize.X - 5; c.Y = 0;
284     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-5\n");
285
286     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
287     c.Y = 0;
288     for (c.X = sbSize.X - 5; c.X < sbSize.X - 1; c.X++)
289     {
290         okCHAR(hCon, c, mytest[c.X - sbSize.X + 5], TEST_ATTRIB);
291     }
292
293     ReadConsoleOutputAttribute(hCon, &attr, 1, c, &len);
294     /* Win9x and WinMe change the attribs for '\n' up to 'f' */
295     if (attr == TEST_ATTRIB)
296     {
297         win_skip("Win9x/WinMe don't respect ~ENABLE_WRAP_AT_EOL_OUTPUT\n");
298         return;
299     }
300
301     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
302
303     c.X = 0; c.Y++;
304     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
305     for (c.X = 1; c.X < 8; c.X++)
306         okCHAR(hCon, c, ' ', TEST_ATTRIB);
307     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
308     c.X++;
309     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
310
311     okCURSOR(hCon, c);
312
313     /* write line, wrapping disabled, strings end on end of line */
314     c.X = sbSize.X - 4; c.Y = 0;
315     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-4\n");
316
317     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
318     c.Y = 0;
319     for (c.X = sbSize.X - 4; c.X < sbSize.X; c.X++)
320     {
321         okCHAR(hCon, c, mytest[c.X - sbSize.X + 4], TEST_ATTRIB);
322     }
323     c.X = 0; c.Y++;
324     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
325     for (c.X = 1; c.X < 8; c.X++)
326         okCHAR(hCon, c, ' ', TEST_ATTRIB);
327     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
328     c.X++;
329     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
330
331     okCURSOR(hCon, c);
332
333     /* write line, wrapping disabled, strings end after end of line */
334     c.X = sbSize.X - 3; c.Y = 0;
335     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-4\n");
336
337     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
338     c.Y = 0;
339     for (p = mylen2 - 3; p < mylen2; p++)
340     {
341         c.X = sbSize.X - 3 + p % 3;
342         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
343     }
344     c.X = 0; c.Y = 1;
345     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
346     for (c.X = 1; c.X < 8; c.X++)
347         okCHAR(hCon, c, ' ', TEST_ATTRIB);
348     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
349     c.X++;
350     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
351
352     okCURSOR(hCon, c);
353 }
354
355 static void testWriteWrappedNotProcessed(HANDLE hCon, COORD sbSize)
356 {
357     COORD               c;
358     DWORD               len, mode;
359     const char*         mytest = "abcd\nf\tg";
360     const int   mylen = strlen(mytest);
361     int                 p;
362
363     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon,(mode | ENABLE_WRAP_AT_EOL_OUTPUT) & ~(ENABLE_PROCESSED_OUTPUT)),
364        "setting wrap at EOL & clearing processed output\n");
365
366     /* write line, wrapping enabled, buffer doesn't exceed sb width */
367     c.X = sbSize.X - 9; c.Y = 0;
368     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-9\n");
369
370     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
371     c.Y = 0;
372     for (p = 0; p < mylen; p++)
373     {
374         c.X = sbSize.X - 9 + p;
375         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
376     }
377     c.X = sbSize.X - 9 + mylen;
378     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
379     c.X = 0; c.Y = 1;
380     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
381
382     /* write line, wrapping enabled, buffer does exceed sb width */
383     c.X = sbSize.X - 3; c.Y = 0;
384     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
385
386     c.Y = 1;
387     c.X = mylen - 3;
388     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
389 }
390
391 static void testWriteWrappedProcessed(HANDLE hCon, COORD sbSize)
392 {
393     COORD               c;
394     DWORD               len, mode;
395     const char*         mytest = "abcd\nf\tg";
396     const int   mylen = strlen(mytest);
397     int                 p;
398     WORD                attr;
399
400     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode | (ENABLE_WRAP_AT_EOL_OUTPUT|ENABLE_PROCESSED_OUTPUT)),
401        "setting wrap at EOL & processed output\n");
402
403     /* write line, wrapping enabled, buffer doesn't exceed sb width */
404     c.X = sbSize.X - 9; c.Y = 0;
405     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-9\n");
406
407     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
408     for (p = 0; p < 4; p++)
409     {
410         c.X = sbSize.X - 9 + p;
411         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
412     }
413     c.X = sbSize.X - 9 + p;
414     ReadConsoleOutputAttribute(hCon, &attr, 1, c, &len);
415     if (attr == TEST_ATTRIB)
416         win_skip("Win9x/WinMe changes attribs for '\\n' up to 'f'\n");
417     else
418         okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
419     c.X = 0; c.Y++;
420     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
421     for (c.X = 1; c.X < 8; c.X++)
422         okCHAR(hCon, c, ' ', TEST_ATTRIB);
423     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
424     c.X++;
425     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
426     okCURSOR(hCon, c);
427
428     /* write line, wrapping enabled, buffer does exceed sb width */
429     c.X = sbSize.X - 3; c.Y = 2;
430     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
431
432     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
433     for (p = 0; p < 3; p++)
434     {
435         c.X = sbSize.X - 3 + p;
436         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
437     }
438     c.X = 0; c.Y++;
439     okCHAR(hCon, c, mytest[3], TEST_ATTRIB);
440     c.X++;
441     ReadConsoleOutputAttribute(hCon, &attr, 1, c, &len);
442     if (attr == TEST_ATTRIB)
443         win_skip("Win9x/WinMe changes attribs for '\\n' up to 'f'\n");
444     else
445         okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
446
447     c.X = 0; c.Y++;
448     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
449     for (c.X = 1; c.X < 8; c.X++)
450         okCHAR(hCon, c, ' ', TEST_ATTRIB);
451     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
452     c.X++;
453     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
454     okCURSOR(hCon, c);
455 }
456
457 static void testWrite(HANDLE hCon, COORD sbSize)
458 {
459     /* FIXME: should in fact insure that the sb is at least 10 character wide */
460     ok(SetConsoleTextAttribute(hCon, TEST_ATTRIB), "Setting default text color\n");
461     resetContent(hCon, sbSize, FALSE);
462     testEmptyWrite(hCon);
463     resetContent(hCon, sbSize, FALSE);
464     testWriteSimple(hCon);
465     resetContent(hCon, sbSize, FALSE);
466     testWriteNotWrappedNotProcessed(hCon, sbSize);
467     resetContent(hCon, sbSize, FALSE);
468     testWriteNotWrappedProcessed(hCon, sbSize);
469     resetContent(hCon, sbSize, FALSE);
470     testWriteWrappedNotProcessed(hCon, sbSize);
471     resetContent(hCon, sbSize, FALSE);
472     testWriteWrappedProcessed(hCon, sbSize);
473 }
474
475 static void testScroll(HANDLE hCon, COORD sbSize)
476 {
477     SMALL_RECT  scroll, clip;
478     COORD       dst, c, tc;
479     CHAR_INFO   ci;
480     BOOL ret;
481
482 #define W 11
483 #define H 7
484
485 #define IN_SRECT(r,c) ((r).Left <= (c).X && (c).X <= (r).Right && (r).Top <= (c).Y && (c).Y <= (r).Bottom)
486 #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)
487
488     /* no clipping, src & dst rect don't overlap */
489     resetContent(hCon, sbSize, TRUE);
490
491     scroll.Left = 0;
492     scroll.Right = W - 1;
493     scroll.Top = 0;
494     scroll.Bottom = H - 1;
495     dst.X = W + 3;
496     dst.Y = H + 3;
497     ci.Char.UnicodeChar = '#';
498     ci.Attributes = TEST_ATTRIB;
499
500     clip.Left = 0;
501     clip.Right = sbSize.X - 1;
502     clip.Top = 0;
503     clip.Bottom = sbSize.Y - 1;
504
505     ok(ScrollConsoleScreenBuffer(hCon, &scroll, NULL, dst, &ci), "Scrolling SB\n");
506
507     for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
508     {
509         for (c.X = 0; c.X < sbSize.X; c.X++)
510         {
511             if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
512             {
513                 tc.X = c.X - dst.X;
514                 tc.Y = c.Y - dst.Y;
515                 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
516             }
517             else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
518                 okCHAR(hCon, c, '#', TEST_ATTRIB);
519             else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
520         }
521     }
522
523     /* no clipping, src & dst rect do overlap */
524     resetContent(hCon, sbSize, TRUE);
525
526     scroll.Left = 0;
527     scroll.Right = W - 1;
528     scroll.Top = 0;
529     scroll.Bottom = H - 1;
530     dst.X = W /2;
531     dst.Y = H / 2;
532     ci.Char.UnicodeChar = '#';
533     ci.Attributes = TEST_ATTRIB;
534
535     clip.Left = 0;
536     clip.Right = sbSize.X - 1;
537     clip.Top = 0;
538     clip.Bottom = sbSize.Y - 1;
539
540     ok(ScrollConsoleScreenBuffer(hCon, &scroll, NULL, dst, &ci), "Scrolling SB\n");
541
542     for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
543     {
544         for (c.X = 0; c.X < sbSize.X; c.X++)
545         {
546             if (dst.X <= c.X && c.X < dst.X + W && dst.Y <= c.Y && c.Y < dst.Y + H)
547             {
548                 tc.X = c.X - dst.X;
549                 tc.Y = c.Y - dst.Y;
550                 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
551             }
552             else if (c.X < W && c.Y < H) okCHAR(hCon, c, '#', TEST_ATTRIB);
553             else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
554         }
555     }
556
557     /* clipping, src & dst rect don't overlap */
558     resetContent(hCon, sbSize, TRUE);
559
560     scroll.Left = 0;
561     scroll.Right = W - 1;
562     scroll.Top = 0;
563     scroll.Bottom = H - 1;
564     dst.X = W + 3;
565     dst.Y = H + 3;
566     ci.Char.UnicodeChar = '#';
567     ci.Attributes = TEST_ATTRIB;
568
569     clip.Left = W / 2;
570     clip.Right = min(W + W / 2, sbSize.X - 1);
571     clip.Top = H / 2;
572     clip.Bottom = min(H + H / 2, sbSize.Y - 1);
573
574     SetLastError(0xdeadbeef);
575     ret = ScrollConsoleScreenBuffer(hCon, &scroll, &clip, dst, &ci);
576     if (ret)
577     {
578         for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
579         {
580             for (c.X = 0; c.X < sbSize.X; c.X++)
581             {
582                 if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
583                 {
584                     tc.X = c.X - dst.X;
585                     tc.Y = c.Y - dst.Y;
586                     okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
587                 }
588                 else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
589                     okCHAR(hCon, c, '#', TEST_ATTRIB);
590                 else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
591             }
592         }
593     }
594     else
595     {
596         /* Win9x will fail, Only accept ERROR_NOT_ENOUGH_MEMORY */
597         ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY,
598             "Expected ERROR_NOT_ENOUGH_MEMORY, got %u\n", GetLastError());
599     }
600
601     /* clipping, src & dst rect do overlap */
602     resetContent(hCon, sbSize, TRUE);
603
604     scroll.Left = 0;
605     scroll.Right = W - 1;
606     scroll.Top = 0;
607     scroll.Bottom = H - 1;
608     dst.X = W / 2 - 3;
609     dst.Y = H / 2 - 3;
610     ci.Char.UnicodeChar = '#';
611     ci.Attributes = TEST_ATTRIB;
612
613     clip.Left = W / 2;
614     clip.Right = min(W + W / 2, sbSize.X - 1);
615     clip.Top = H / 2;
616     clip.Bottom = min(H + H / 2, sbSize.Y - 1);
617
618     ok(ScrollConsoleScreenBuffer(hCon, &scroll, &clip, dst, &ci), "Scrolling SB\n");
619
620     for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
621     {
622         for (c.X = 0; c.X < sbSize.X; c.X++)
623         {
624             if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
625             {
626                 tc.X = c.X - dst.X;
627                 tc.Y = c.Y - dst.Y;
628                 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
629             }
630             else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
631                 okCHAR(hCon, c, '#', TEST_ATTRIB);
632             else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
633         }
634     }
635 }
636
637 static int mch_count;
638 /* we need the event as Wine console event generation isn't synchronous
639  * (ie GenerateConsoleCtrlEvent returns before all ctrl-handlers in all
640  * processes have been called).
641  */
642 static HANDLE mch_event;
643 static BOOL WINAPI mch(DWORD event)
644 {
645     mch_count++;
646     SetEvent(mch_event);
647     return TRUE;
648 }
649
650 static void testCtrlHandler(void)
651 {
652     ok(!SetConsoleCtrlHandler(mch, FALSE), "Shouldn't succeed\n");
653     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %u\n", GetLastError());
654     ok(SetConsoleCtrlHandler(mch, TRUE), "Couldn't set handler\n");
655     /* wine requires the event for the test, as we cannot insure, so far, that event
656      * are processed synchronously in GenerateConsoleCtrlEvent()
657      */
658     mch_event = CreateEventA(NULL, TRUE, FALSE, NULL);
659     mch_count = 0;
660     ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n");
661     /* FIXME: it isn't synchronous on wine but it can still happen before we test */
662     if (0) ok(mch_count == 1, "Event isn't synchronous\n");
663     ok(WaitForSingleObject(mch_event, 3000) == WAIT_OBJECT_0, "event sending didn't work\n");
664     CloseHandle(mch_event);
665
666     /* Turning off ctrl-c handling doesn't work on win9x such way ... */
667     ok(SetConsoleCtrlHandler(NULL, TRUE), "Couldn't turn off ctrl-c handling\n");
668     mch_event = CreateEventA(NULL, TRUE, FALSE, NULL);
669     mch_count = 0;
670     if(!(GetVersion() & 0x80000000))
671         /* ... and next line leads to an unhandled exception on 9x.  Avoid it on 9x. */
672         ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n");
673     ok(WaitForSingleObject(mch_event, 3000) == WAIT_TIMEOUT && mch_count == 0, "Event shouldn't have been sent\n");
674     CloseHandle(mch_event);
675     ok(SetConsoleCtrlHandler(mch, FALSE), "Couldn't remove handler\n");
676     ok(!SetConsoleCtrlHandler(mch, FALSE), "Shouldn't succeed\n");
677     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %u\n", GetLastError());
678 }
679
680 /*
681  * Test console screen buffer:
682  * 1) Try to set invalid handle.
683  * 2) Try to set non-console handles.
684  * 3) Use CONOUT$ file as active SB.
685  * 4) Test cursor.
686  * 5) Test output codepage to show it is not a property of SB.
687  * 6) Test switching to old SB if we close all handles to current SB - works
688  * in Windows, TODO in wine.
689  *
690  * What is not tested but should be:
691  * 1) ScreenBufferInfo
692  */
693 static void testScreenBuffer(HANDLE hConOut)
694 {
695     HANDLE hConOutRW, hConOutRO, hConOutWT;
696     HANDLE hFileOutRW, hFileOutRO, hFileOutWT;
697     HANDLE hConOutNew;
698     char test_str1[] = "Test for SB1";
699     char test_str2[] = "Test for SB2";
700     char test_cp866[] = {0xe2, 0xa5, 0xe1, 0xe2, 0};
701     char test_cp1251[] = {0xf2, 0xe5, 0xf1, 0xf2, 0};
702     WCHAR test_unicode[] = {0x0442, 0x0435, 0x0441, 0x0442, 0};
703     WCHAR str_wbuf[20];
704     char str_buf[20];
705     DWORD len;
706     COORD c;
707     BOOL ret;
708     DWORD oldcp;
709
710     if (!IsValidCodePage(866))
711     {
712         skip("Codepage 866 not available\n");
713         return;
714     }
715
716     /* In the beginning set output codepage to 866 */
717     oldcp = GetConsoleOutputCP();
718     SetLastError(0xdeadbeef);
719     ret = SetConsoleOutputCP(866);
720     if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
721     {
722         win_skip("SetConsoleOutputCP is not implemented\n");
723         return;
724     }
725     ok(ret, "Cannot set output codepage to 866\n");
726
727     hConOutRW = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
728                          FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
729                          CONSOLE_TEXTMODE_BUFFER, NULL);
730     ok(hConOutRW != INVALID_HANDLE_VALUE,
731        "Cannot create a new screen buffer for ReadWrite\n");
732     hConOutRO = CreateConsoleScreenBuffer(GENERIC_READ,
733                          FILE_SHARE_READ, NULL,
734                          CONSOLE_TEXTMODE_BUFFER, NULL);
735     ok(hConOutRO != INVALID_HANDLE_VALUE,
736        "Cannot create a new screen buffer for ReadOnly\n");
737     hConOutWT = CreateConsoleScreenBuffer(GENERIC_WRITE,
738                          FILE_SHARE_WRITE, NULL,
739                          CONSOLE_TEXTMODE_BUFFER, NULL);
740     ok(hConOutWT != INVALID_HANDLE_VALUE,
741        "Cannot create a new screen buffer for WriteOnly\n");
742
743     hFileOutRW = CreateFileA("NUL", GENERIC_READ | GENERIC_WRITE,
744                              FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
745                              OPEN_EXISTING, 0, NULL);
746     ok(hFileOutRW != INVALID_HANDLE_VALUE, "Cannot open NUL for ReadWrite\n");
747     hFileOutRO = CreateFileA("NUL", GENERIC_READ, FILE_SHARE_READ,
748                              NULL, OPEN_EXISTING, 0, NULL);
749     ok(hFileOutRO != INVALID_HANDLE_VALUE, "Cannot open NUL for ReadOnly\n");
750     hFileOutWT = CreateFileA("NUL", GENERIC_WRITE, FILE_SHARE_WRITE,
751                              NULL, OPEN_EXISTING, 0, NULL);
752     ok(hFileOutWT != INVALID_HANDLE_VALUE, "Cannot open NUL for WriteOnly\n");
753
754     /* Trying to set invalid handle */
755     SetLastError(0);
756     ok(!SetConsoleActiveScreenBuffer(INVALID_HANDLE_VALUE),
757        "Shouldn't succeed\n");
758     ok(GetLastError() == ERROR_INVALID_HANDLE,
759        "GetLastError: expecting %u got %u\n",
760        ERROR_INVALID_HANDLE, GetLastError());
761
762     /* Trying to set non-console handles */
763     SetLastError(0);
764     ok(!SetConsoleActiveScreenBuffer(hFileOutRW), "Shouldn't succeed\n");
765     ok(GetLastError() == ERROR_INVALID_HANDLE,
766        "GetLastError: expecting %u got %u\n",
767        ERROR_INVALID_HANDLE, GetLastError());
768
769     SetLastError(0);
770     ok(!SetConsoleActiveScreenBuffer(hFileOutRO), "Shouldn't succeed\n");
771     ok(GetLastError() == ERROR_INVALID_HANDLE,
772        "GetLastError: expecting %u got %u\n",
773        ERROR_INVALID_HANDLE, GetLastError());
774
775     SetLastError(0);
776     ok(!SetConsoleActiveScreenBuffer(hFileOutWT), "Shouldn't succeed\n");
777     ok(GetLastError() == ERROR_INVALID_HANDLE,
778        "GetLastError: expecting %u got %u\n",
779        ERROR_INVALID_HANDLE, GetLastError());
780
781     CloseHandle(hFileOutRW);
782     CloseHandle(hFileOutRO);
783     CloseHandle(hFileOutWT);
784
785     /* Trying to set SB handles with various access modes */
786     SetLastError(0);
787     ok(!SetConsoleActiveScreenBuffer(hConOutRO), "Shouldn't succeed\n");
788     ok(GetLastError() == ERROR_INVALID_HANDLE,
789        "GetLastError: expecting %u got %u\n",
790        ERROR_INVALID_HANDLE, GetLastError());
791
792     ok(SetConsoleActiveScreenBuffer(hConOutWT), "Couldn't set new WriteOnly SB\n");
793
794     ok(SetConsoleActiveScreenBuffer(hConOutRW), "Couldn't set new ReadWrite SB\n");
795
796     CloseHandle(hConOutWT);
797     CloseHandle(hConOutRO);
798
799     /* Now we have two ReadWrite SB, active must be hConOutRW */
800     /* Open current SB via CONOUT$ */
801     hConOutNew = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0,
802                              NULL, OPEN_EXISTING, 0, 0);
803     ok(hConOutNew != INVALID_HANDLE_VALUE, "CONOUT$ is not opened\n");
804
805
806     /* test cursor */
807     c.X = c.Y = 10;
808     SetConsoleCursorPosition(hConOut, c);
809     c.X = c.Y = 5;
810     SetConsoleCursorPosition(hConOutRW, c);
811     okCURSOR(hConOutNew, c);
812     c.X = c.Y = 10;
813     okCURSOR(hConOut, c);
814
815
816     c.X = c.Y = 0;
817
818     /* Write using hConOutNew... */
819     SetConsoleCursorPosition(hConOutNew, c);
820     ret = WriteConsoleA(hConOutNew, test_str2, lstrlenA(test_str2), &len, NULL);
821     ok (ret && len == lstrlenA(test_str2), "WriteConsoleA failed\n");
822     /* ... and read it back via hConOutRW */
823     ret = ReadConsoleOutputCharacterA(hConOutRW, str_buf, lstrlenA(test_str2), c, &len);
824     ok(ret && len == lstrlenA(test_str2), "ReadConsoleOutputCharacterA failed\n");
825     str_buf[lstrlenA(test_str2)] = 0;
826     ok(!lstrcmpA(str_buf, test_str2), "got '%s' expected '%s'\n", str_buf, test_str2);
827
828
829     /* Now test output codepage handling. Current is 866 as we set earlier. */
830     SetConsoleCursorPosition(hConOutRW, c);
831     ret = WriteConsoleA(hConOutRW, test_cp866, lstrlenA(test_cp866), &len, NULL);
832     ok(ret && len == lstrlenA(test_cp866), "WriteConsoleA failed\n");
833     ret = ReadConsoleOutputCharacterW(hConOutRW, str_wbuf, lstrlenA(test_cp866), c, &len);
834     ok(ret && len == lstrlenA(test_cp866), "ReadConsoleOutputCharacterW failed\n");
835     str_wbuf[lstrlenA(test_cp866)] = 0;
836     ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n");
837
838     /*
839      * cp866 is OK, let's switch to cp1251.
840      * We expect that this codepage will be used in every SB - active and not.
841      */
842     ok(SetConsoleOutputCP(1251), "Cannot set output cp to 1251\n");
843     SetConsoleCursorPosition(hConOutRW, c);
844     ret = WriteConsoleA(hConOutRW, test_cp1251, lstrlenA(test_cp1251), &len, NULL);
845     ok(ret && len == lstrlenA(test_cp1251), "WriteConsoleA failed\n");
846     ret = ReadConsoleOutputCharacterW(hConOutRW, str_wbuf, lstrlenA(test_cp1251), c, &len);
847     ok(ret && len == lstrlenA(test_cp1251), "ReadConsoleOutputCharacterW failed\n");
848     str_wbuf[lstrlenA(test_cp1251)] = 0;
849     ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n");
850
851     /* Check what has happened to hConOut. */
852     SetConsoleCursorPosition(hConOut, c);
853     ret = WriteConsoleA(hConOut, test_cp1251, lstrlenA(test_cp1251), &len, NULL);
854     ok(ret && len == lstrlenA(test_cp1251), "WriteConsoleA failed\n");
855     ret = ReadConsoleOutputCharacterW(hConOut, str_wbuf, lstrlenA(test_cp1251), c, &len);
856     ok(ret && len == lstrlenA(test_cp1251), "ReadConsoleOutputCharacterW failed\n");
857     str_wbuf[lstrlenA(test_cp1251)] = 0;
858     ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n");
859
860     /* Close all handles of current console SB */
861     CloseHandle(hConOutNew);
862     CloseHandle(hConOutRW);
863
864     /* Now active SB should be hConOut */
865     hConOutNew = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0,
866                              NULL, OPEN_EXISTING, 0, 0);
867     ok(hConOutNew != INVALID_HANDLE_VALUE, "CONOUT$ is not opened\n");
868
869     /* Write using hConOutNew... */
870     SetConsoleCursorPosition(hConOutNew, c);
871     ret = WriteConsoleA(hConOutNew, test_str1, lstrlenA(test_str1), &len, NULL);
872     ok (ret && len == lstrlenA(test_str1), "WriteConsoleA failed\n");
873     /* ... and read it back via hConOut */
874     ret = ReadConsoleOutputCharacterA(hConOut, str_buf, lstrlenA(test_str1), c, &len);
875     ok(ret && len == lstrlenA(test_str1), "ReadConsoleOutputCharacterA failed\n");
876     str_buf[lstrlenA(test_str1)] = 0;
877     todo_wine ok(!lstrcmpA(str_buf, test_str1), "got '%s' expected '%s'\n", str_buf, test_str1);
878     CloseHandle(hConOutNew);
879
880     /* This is not really needed under Windows */
881     SetConsoleActiveScreenBuffer(hConOut);
882
883     /* restore codepage */
884     SetConsoleOutputCP(oldcp);
885 }
886
887 static void test_GetSetConsoleInputExeName(void)
888 {
889     BOOL ret;
890     DWORD error;
891     char buffer[MAX_PATH], module[MAX_PATH], *p;
892     static char input_exe[MAX_PATH] = "winetest.exe";
893
894     SetLastError(0xdeadbeef);
895     ret = pGetConsoleInputExeNameA(0, NULL);
896     error = GetLastError();
897     ok(ret, "GetConsoleInputExeNameA failed\n");
898     ok(error == ERROR_BUFFER_OVERFLOW, "got %u expected ERROR_BUFFER_OVERFLOW\n", error);
899
900     SetLastError(0xdeadbeef);
901     ret = pGetConsoleInputExeNameA(0, buffer);
902     error = GetLastError();
903     ok(ret, "GetConsoleInputExeNameA failed\n");
904     ok(error == ERROR_BUFFER_OVERFLOW, "got %u expected ERROR_BUFFER_OVERFLOW\n", error);
905
906     GetModuleFileNameA(GetModuleHandle(NULL), module, sizeof(module));
907     p = strrchr(module, '\\') + 1;
908
909     ret = pGetConsoleInputExeNameA(sizeof(buffer)/sizeof(buffer[0]), buffer);
910     ok(ret, "GetConsoleInputExeNameA failed\n");
911     todo_wine ok(!lstrcmpA(buffer, p), "got %s expected %s\n", buffer, p);
912
913     SetLastError(0xdeadbeef);
914     ret = pSetConsoleInputExeNameA(NULL);
915     error = GetLastError();
916     ok(!ret, "SetConsoleInputExeNameA failed\n");
917     ok(error == ERROR_INVALID_PARAMETER, "got %u expected ERROR_INVALID_PARAMETER\n", error);
918
919     SetLastError(0xdeadbeef);
920     ret = pSetConsoleInputExeNameA("");
921     error = GetLastError();
922     ok(!ret, "SetConsoleInputExeNameA failed\n");
923     ok(error == ERROR_INVALID_PARAMETER, "got %u expected ERROR_INVALID_PARAMETER\n", error);
924
925     ret = pSetConsoleInputExeNameA(input_exe);
926     ok(ret, "SetConsoleInputExeNameA failed\n");
927
928     ret = pGetConsoleInputExeNameA(sizeof(buffer)/sizeof(buffer[0]), buffer);
929     ok(ret, "GetConsoleInputExeNameA failed\n");
930     ok(!lstrcmpA(buffer, input_exe), "got %s expected %s\n", buffer, input_exe);
931 }
932
933 static void test_GetConsoleProcessList(void)
934 {
935     DWORD ret, *list = NULL;
936
937     if (!pGetConsoleProcessList)
938     {
939         win_skip("GetConsoleProcessList is not available\n");
940         return;
941     }
942
943     SetLastError(0xdeadbeef);
944     ret = pGetConsoleProcessList(NULL, 0);
945     ok(ret == 0, "Expected failure\n");
946     ok(GetLastError() == ERROR_INVALID_PARAMETER,
947        "Expected ERROR_INVALID_PARAMETER, got %d\n",
948        GetLastError());
949
950     SetLastError(0xdeadbeef);
951     ret = pGetConsoleProcessList(NULL, 1);
952     ok(ret == 0, "Expected failure\n");
953     ok(GetLastError() == ERROR_INVALID_PARAMETER,
954        "Expected ERROR_INVALID_PARAMETER, got %d\n",
955        GetLastError());
956
957     /* We should only have 1 process but only for these specific unit tests as
958      * we created our own console. An AttachConsole(ATTACH_PARENT_PROCESS) would
959      * give us two processes for example.
960      */
961     list = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD));
962
963     SetLastError(0xdeadbeef);
964     ret = pGetConsoleProcessList(list, 0);
965     ok(ret == 0, "Expected failure\n");
966     ok(GetLastError() == ERROR_INVALID_PARAMETER,
967        "Expected ERROR_INVALID_PARAMETER, got %d\n",
968        GetLastError());
969
970     SetLastError(0xdeadbeef);
971     ret = pGetConsoleProcessList(list, 1);
972     todo_wine
973     ok(ret == 1, "Expected 1, got %d\n", ret);
974
975     HeapFree(GetProcessHeap(), 0, list);
976
977     list = HeapAlloc(GetProcessHeap(), 0, ret * sizeof(DWORD));
978
979     SetLastError(0xdeadbeef);
980     ret = pGetConsoleProcessList(list, ret);
981     todo_wine
982     ok(ret == 1, "Expected 1, got %d\n", ret);
983
984     if (ret == 1)
985     {
986         DWORD pid = GetCurrentProcessId();
987         ok(list[0] == pid, "Expected %d, got %d\n", pid, list[0]);
988     }
989
990     HeapFree(GetProcessHeap(), 0, list);
991 }
992
993 static void test_OpenConsoleW(void)
994 {
995     static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
996     static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
997     static const WCHAR emptyW[] = {0};
998     static const WCHAR invalidW[] = {'I','N','V','A','L','I','D',0};
999
1000     static const struct
1001     {
1002         LPCWSTR name;
1003         DWORD access;
1004         BOOL inherit;
1005         DWORD creation;
1006         DWORD gle;
1007     } invalid_table[] = {
1008         {NULL,     0,                            FALSE,      0,                 ERROR_INVALID_PARAMETER},
1009         {NULL,     0xdeadbeef,                   0xdeadbeef, 0xdeadbeef,        ERROR_INVALID_PARAMETER},
1010         {NULL,     0,                            FALSE,      OPEN_ALWAYS,       ERROR_INVALID_PARAMETER},
1011         {NULL,     GENERIC_READ | GENERIC_WRITE, FALSE,      0,                 ERROR_INVALID_PARAMETER},
1012         {NULL,     GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_ALWAYS,       ERROR_INVALID_PARAMETER},
1013         {NULL,     GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_EXISTING,     ERROR_INVALID_PARAMETER},
1014         {emptyW,   0,                            FALSE,      0,                 ERROR_INVALID_PARAMETER},
1015         {emptyW,   0xdeadbeef,                   0xdeadbeef, 0xdeadbeef,        ERROR_INVALID_PARAMETER},
1016         {emptyW,   0,                            FALSE,      OPEN_ALWAYS,       ERROR_INVALID_PARAMETER},
1017         {emptyW,   GENERIC_READ | GENERIC_WRITE, FALSE,      0,                 ERROR_INVALID_PARAMETER},
1018         {emptyW,   GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_ALWAYS,       ERROR_INVALID_PARAMETER},
1019         {emptyW,   GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_EXISTING,     ERROR_INVALID_PARAMETER},
1020         {invalidW, 0,                            FALSE,      0,                 ERROR_INVALID_PARAMETER},
1021         {invalidW, 0xdeadbeef,                   0xdeadbeef, 0xdeadbeef,        ERROR_INVALID_PARAMETER},
1022         {invalidW, 0,                            FALSE,      OPEN_ALWAYS,       ERROR_INVALID_PARAMETER},
1023         {invalidW, GENERIC_READ | GENERIC_WRITE, FALSE,      0,                 ERROR_INVALID_PARAMETER},
1024         {invalidW, GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_ALWAYS,       ERROR_INVALID_PARAMETER},
1025         {invalidW, GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_EXISTING,     ERROR_INVALID_PARAMETER},
1026         {coninW,   0,                            FALSE,      0,                 ERROR_SHARING_VIOLATION},
1027         {coninW,   0xdeadbeef,                   0xdeadbeef, 0xdeadbeef,        ERROR_INVALID_PARAMETER},
1028         {coninW,   0,                            FALSE,      OPEN_ALWAYS,       ERROR_INVALID_PARAMETER},
1029         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      0,                 ERROR_SHARING_VIOLATION},
1030         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      CREATE_NEW,        ERROR_SHARING_VIOLATION},
1031         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      CREATE_ALWAYS,     ERROR_SHARING_VIOLATION},
1032         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_ALWAYS,       ERROR_INVALID_PARAMETER},
1033         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      TRUNCATE_EXISTING, ERROR_INVALID_PARAMETER},
1034         {conoutW,  0,                            FALSE,      0,                 ERROR_SHARING_VIOLATION},
1035         {conoutW,  0xdeadbeef,                   0xdeadbeef, 0xdeadbeef,        ERROR_INVALID_PARAMETER},
1036         {conoutW,  0,                            FALSE,      OPEN_ALWAYS,       ERROR_INVALID_PARAMETER},
1037         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      0,                 ERROR_SHARING_VIOLATION},
1038         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      CREATE_NEW,        ERROR_SHARING_VIOLATION},
1039         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      CREATE_ALWAYS,     ERROR_SHARING_VIOLATION},
1040         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_ALWAYS,       ERROR_INVALID_PARAMETER},
1041         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      TRUNCATE_EXISTING, ERROR_INVALID_PARAMETER},
1042     };
1043
1044     int index;
1045     HANDLE ret;
1046
1047     if (!pOpenConsoleW)
1048     {
1049         win_skip("OpenConsoleW is not available\n");
1050         return;
1051     }
1052
1053     for (index = 0; index < sizeof(invalid_table)/sizeof(invalid_table[0]); index++)
1054     {
1055         SetLastError(0xdeadbeef);
1056         ret = pOpenConsoleW(invalid_table[index].name, invalid_table[index].access,
1057                             invalid_table[index].inherit, invalid_table[index].creation);
1058         ok(ret == INVALID_HANDLE_VALUE,
1059            "Expected OpenConsoleW to return INVALID_HANDLE_VALUE for index %d, got %p\n",
1060            index, ret);
1061         ok(GetLastError() == invalid_table[index].gle,
1062            "Expected GetLastError() to return %u for index %d, got %u\n",
1063            invalid_table[index].gle, index, GetLastError());
1064     }
1065
1066     /* OpenConsoleW should not touch the last error on success. */
1067     SetLastError(0xdeadbeef);
1068     ret = pOpenConsoleW(coninW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING);
1069     ok(ret != INVALID_HANDLE_VALUE,
1070        "Expected OpenConsoleW to return a valid handle\n");
1071     ok(GetLastError() == 0xdeadbeef,
1072        "Expected the last error to be untouched, got %u\n", GetLastError());
1073     if (ret != INVALID_HANDLE_VALUE)
1074         CloseHandle(ret);
1075
1076     SetLastError(0xdeadbeef);
1077     ret = pOpenConsoleW(conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING);
1078     ok(ret != INVALID_HANDLE_VALUE,
1079        "Expected OpenConsoleW to return a valid handle\n");
1080     ok(GetLastError() == 0xdeadbeef,
1081        "Expected the last error to be untouched, got %u\n", GetLastError());
1082     if (ret != INVALID_HANDLE_VALUE)
1083         CloseHandle(ret);
1084 }
1085
1086 START_TEST(console)
1087 {
1088     HANDLE hConIn, hConOut;
1089     BOOL ret;
1090     CONSOLE_SCREEN_BUFFER_INFO  sbi;
1091
1092     init_function_pointers();
1093
1094     /* be sure we have a clean console (and that's our own)
1095      * FIXME: this will make the test fail (currently) if we don't run
1096      * under X11
1097      * Another solution would be to rerun the test under wineconsole with
1098      * the curses backend
1099      */
1100
1101     /* first, we detach and open a fresh console to play with */
1102     FreeConsole();
1103     ok(AllocConsole(), "Couldn't alloc console\n");
1104     hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
1105     hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
1106
1107     /* now verify everything's ok */
1108     ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n");
1109     ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n");
1110
1111     ret = GetConsoleScreenBufferInfo(hConOut, &sbi);
1112     ok(ret, "Getting sb info\n");
1113     if (!ret) return;
1114
1115     /* Non interactive tests */
1116     testCursor(hConOut, sbi.dwSize);
1117     /* test parameters (FIXME: test functionality) */
1118     testCursorInfo(hConOut);
1119     /* will test wrapped (on/off) & processed (on/off) strings output */
1120     testWrite(hConOut, sbi.dwSize);
1121     /* will test line scrolling at the bottom of the screen */
1122     /* testBottomScroll(); */
1123     /* will test all the scrolling operations */
1124     testScroll(hConOut, sbi.dwSize);
1125     /* will test sb creation / modification / codepage handling */
1126     testScreenBuffer(hConOut);
1127     testCtrlHandler();
1128     /* still to be done: access rights & access on objects */
1129
1130     if (!pGetConsoleInputExeNameA || !pSetConsoleInputExeNameA)
1131         win_skip("GetConsoleInputExeNameA and/or SetConsoleInputExeNameA is not available\n");
1132     else
1133         test_GetSetConsoleInputExeName();
1134
1135     test_GetConsoleProcessList();
1136     test_OpenConsoleW();
1137 }