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 "precomp.h"
23 
24 static BOOL (WINAPI *pGetConsoleInputExeNameA)(DWORD, LPSTR);
25 static DWORD (WINAPI *pGetConsoleProcessList)(LPDWORD, DWORD);
26 static HANDLE (WINAPI *pOpenConsoleW)(LPCWSTR,DWORD,BOOL,DWORD);
27 static BOOL (WINAPI *pSetConsoleInputExeNameA)(LPCSTR);
28 static BOOL (WINAPI *pVerifyConsoleIoHandle)(HANDLE handle);
29 
30 /* DEFAULT_ATTRIB is used for all initial filling of the console.
31  * all modifications are made with TEST_ATTRIB so that we could check
32  * what has to be modified or not
33  */
34 #define TEST_ATTRIB    (BACKGROUND_BLUE | FOREGROUND_GREEN)
35 #define DEFAULT_ATTRIB (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED)
36 /* when filling the screen with non-blank chars, this macro defines
37  * what character should be at position 'c'
38  */
39 #define CONTENT(c)    ('A' + (((c).Y * 17 + (c).X) % 23))
40 
41 #define	okCURSOR(hCon, c) do { \
42   CONSOLE_SCREEN_BUFFER_INFO __sbi; \
43   BOOL expect = GetConsoleScreenBufferInfo((hCon), &__sbi) && \
44                 __sbi.dwCursorPosition.X == (c).X && __sbi.dwCursorPosition.Y == (c).Y; \
45   ok(expect, "Expected cursor at (%d,%d), got (%d,%d)\n", \
46      (c).X, (c).Y, __sbi.dwCursorPosition.X, __sbi.dwCursorPosition.Y); \
47 } while (0)
48 
49 #define okCHAR(hCon, c, ch, attr) do { \
50   char __ch; WORD __attr; DWORD __len; BOOL expect; \
51   expect = ReadConsoleOutputCharacterA((hCon), &__ch, 1, (c), &__len) == 1 && __len == 1 && __ch == (ch); \
52   ok(expect, "At (%d,%d): expecting char '%c'/%02x got '%c'/%02x\n", (c).X, (c).Y, (ch), (ch), __ch, __ch); \
53   expect = ReadConsoleOutputAttribute((hCon), &__attr, 1, (c), &__len) == 1 && __len == 1 && __attr == (attr); \
54   ok(expect, "At (%d,%d): expecting attr %04x got %04x\n", (c).X, (c).Y, (attr), __attr); \
55 } while (0)
56 
57 static void init_function_pointers(void)
58 {
59     HMODULE hKernel32;
60 
61 #define KERNEL32_GET_PROC(func)                                     \
62     p##func = (void *)GetProcAddress(hKernel32, #func);             \
63     if(!p##func) trace("GetProcAddress(hKernel32, '%s') failed\n", #func);
64 
65     hKernel32 = GetModuleHandleA("kernel32.dll");
66     KERNEL32_GET_PROC(GetConsoleInputExeNameA);
67     KERNEL32_GET_PROC(GetConsoleProcessList);
68     KERNEL32_GET_PROC(OpenConsoleW);
69     KERNEL32_GET_PROC(SetConsoleInputExeNameA);
70     KERNEL32_GET_PROC(VerifyConsoleIoHandle);
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     static const char	emptybuf[16];
173     COORD		c;
174     DWORD		len;
175 
176     c.X = c.Y = 0;
177     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
178 
179     len = -1;
180     ok(WriteConsoleA(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(!WriteConsoleA(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(WriteConsoleA(hCon, NULL, 128, &len, NULL) != 0 && len == 128, "WriteConsole\n");
195     }
196 
197     len = -1;
198     ok(WriteConsoleA(hCon, emptybuf, 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(WriteConsoleA(hCon, emptybuf, 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(WriteConsoleA(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 = WriteConsoleA(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(WriteConsoleA(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(WriteConsoleA(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(WriteConsoleA(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(WriteConsoleA(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(WriteConsoleA(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(WriteConsoleA(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(WriteConsoleA(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 ensure that the sb is at least 10 characters 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(ScrollConsoleScreenBufferA(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(ScrollConsoleScreenBufferA(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 = ScrollConsoleScreenBufferA(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(ScrollConsoleScreenBufferA(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 ensure, so far, that
656      * events 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, error;
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     /* trying to write non-console handle */
782     SetLastError(0xdeadbeef);
783     ret = WriteConsoleA(hFileOutRW, test_str1, lstrlenA(test_str1), &len, NULL);
784     error = GetLastError();
785     ok(!ret, "Shouldn't succeed\n");
786     ok(error == ERROR_INVALID_HANDLE || error == ERROR_INVALID_FUNCTION,
787        "GetLastError: got %u\n", error);
788 
789     SetLastError(0xdeadbeef);
790     ret = WriteConsoleA(hFileOutRO, test_str1, lstrlenA(test_str1), &len, NULL);
791     error = GetLastError();
792     ok(!ret, "Shouldn't succeed\n");
793     ok(error == ERROR_INVALID_HANDLE || error == ERROR_INVALID_FUNCTION,
794        "GetLastError: got %u\n", error);
795 
796     SetLastError(0xdeadbeef);
797     ret = WriteConsoleA(hFileOutWT, test_str1, lstrlenA(test_str1), &len, NULL);
798     error = GetLastError();
799     ok(!ret, "Shouldn't succeed\n");
800     todo_wine ok(error == ERROR_INVALID_HANDLE || error == ERROR_INVALID_FUNCTION,
801        "GetLastError: got %u\n", error);
802 
803     CloseHandle(hFileOutRW);
804     CloseHandle(hFileOutRO);
805     CloseHandle(hFileOutWT);
806 
807     /* Trying to set SB handles with various access modes */
808     SetLastError(0);
809     ok(!SetConsoleActiveScreenBuffer(hConOutRO), "Shouldn't succeed\n");
810     ok(GetLastError() == ERROR_INVALID_HANDLE,
811        "GetLastError: expecting %u got %u\n",
812        ERROR_INVALID_HANDLE, GetLastError());
813 
814     ok(SetConsoleActiveScreenBuffer(hConOutWT), "Couldn't set new WriteOnly SB\n");
815 
816     ok(SetConsoleActiveScreenBuffer(hConOutRW), "Couldn't set new ReadWrite SB\n");
817 
818     CloseHandle(hConOutWT);
819     CloseHandle(hConOutRO);
820 
821     /* Now we have two ReadWrite SB, active must be hConOutRW */
822     /* Open current SB via CONOUT$ */
823     hConOutNew = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0,
824                              NULL, OPEN_EXISTING, 0, 0);
825     ok(hConOutNew != INVALID_HANDLE_VALUE, "CONOUT$ is not opened\n");
826 
827 
828     /* test cursor */
829     c.X = c.Y = 10;
830     SetConsoleCursorPosition(hConOut, c);
831     c.X = c.Y = 5;
832     SetConsoleCursorPosition(hConOutRW, c);
833     okCURSOR(hConOutNew, c);
834     c.X = c.Y = 10;
835     okCURSOR(hConOut, c);
836 
837 
838     c.X = c.Y = 0;
839 
840     /* Write using hConOutNew... */
841     SetConsoleCursorPosition(hConOutNew, c);
842     ret = WriteConsoleA(hConOutNew, test_str2, lstrlenA(test_str2), &len, NULL);
843     ok (ret && len == lstrlenA(test_str2), "WriteConsoleA failed\n");
844     /* ... and read it back via hConOutRW */
845     ret = ReadConsoleOutputCharacterA(hConOutRW, str_buf, lstrlenA(test_str2), c, &len);
846     ok(ret && len == lstrlenA(test_str2), "ReadConsoleOutputCharacterA failed\n");
847     str_buf[lstrlenA(test_str2)] = 0;
848     ok(!lstrcmpA(str_buf, test_str2), "got '%s' expected '%s'\n", str_buf, test_str2);
849 
850 
851     /* Now test output codepage handling. Current is 866 as we set earlier. */
852     SetConsoleCursorPosition(hConOutRW, c);
853     ret = WriteConsoleA(hConOutRW, test_cp866, lstrlenA(test_cp866), &len, NULL);
854     ok(ret && len == lstrlenA(test_cp866), "WriteConsoleA failed\n");
855     ret = ReadConsoleOutputCharacterW(hConOutRW, str_wbuf, lstrlenA(test_cp866), c, &len);
856     ok(ret && len == lstrlenA(test_cp866), "ReadConsoleOutputCharacterW failed\n");
857     str_wbuf[lstrlenA(test_cp866)] = 0;
858     ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n");
859 
860     /*
861      * cp866 is OK, let's switch to cp1251.
862      * We expect that this codepage will be used in every SB - active and not.
863      */
864     ok(SetConsoleOutputCP(1251), "Cannot set output cp to 1251\n");
865     SetConsoleCursorPosition(hConOutRW, c);
866     ret = WriteConsoleA(hConOutRW, test_cp1251, lstrlenA(test_cp1251), &len, NULL);
867     ok(ret && len == lstrlenA(test_cp1251), "WriteConsoleA failed\n");
868     ret = ReadConsoleOutputCharacterW(hConOutRW, str_wbuf, lstrlenA(test_cp1251), c, &len);
869     ok(ret && len == lstrlenA(test_cp1251), "ReadConsoleOutputCharacterW failed\n");
870     str_wbuf[lstrlenA(test_cp1251)] = 0;
871     ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n");
872 
873     /* Check what has happened to hConOut. */
874     SetConsoleCursorPosition(hConOut, c);
875     ret = WriteConsoleA(hConOut, test_cp1251, lstrlenA(test_cp1251), &len, NULL);
876     ok(ret && len == lstrlenA(test_cp1251), "WriteConsoleA failed\n");
877     ret = ReadConsoleOutputCharacterW(hConOut, str_wbuf, lstrlenA(test_cp1251), c, &len);
878     ok(ret && len == lstrlenA(test_cp1251), "ReadConsoleOutputCharacterW failed\n");
879     str_wbuf[lstrlenA(test_cp1251)] = 0;
880     ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n");
881 
882     /* Close all handles of current console SB */
883     CloseHandle(hConOutNew);
884     CloseHandle(hConOutRW);
885 
886     /* Now active SB should be hConOut */
887     hConOutNew = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0,
888                              NULL, OPEN_EXISTING, 0, 0);
889     ok(hConOutNew != INVALID_HANDLE_VALUE, "CONOUT$ is not opened\n");
890 
891     /* Write using hConOutNew... */
892     SetConsoleCursorPosition(hConOutNew, c);
893     ret = WriteConsoleA(hConOutNew, test_str1, lstrlenA(test_str1), &len, NULL);
894     ok (ret && len == lstrlenA(test_str1), "WriteConsoleA failed\n");
895     /* ... and read it back via hConOut */
896     ret = ReadConsoleOutputCharacterA(hConOut, str_buf, lstrlenA(test_str1), c, &len);
897     ok(ret && len == lstrlenA(test_str1), "ReadConsoleOutputCharacterA failed\n");
898     str_buf[lstrlenA(test_str1)] = 0;
899     todo_wine ok(!lstrcmpA(str_buf, test_str1), "got '%s' expected '%s'\n", str_buf, test_str1);
900     CloseHandle(hConOutNew);
901 
902     /* This is not really needed under Windows */
903     SetConsoleActiveScreenBuffer(hConOut);
904 
905     /* restore codepage */
906     SetConsoleOutputCP(oldcp);
907 }
908 
909 static void CALLBACK signaled_function(void *p, BOOLEAN timeout)
910 {
911     HANDLE event = p;
912     SetEvent(event);
913     ok(!timeout, "wait shouldn't have timed out\n");
914 }
915 
916 static void testWaitForConsoleInput(HANDLE input_handle)
917 {
918     HANDLE wait_handle;
919     HANDLE complete_event;
920     INPUT_RECORD record;
921     DWORD events_written;
922     DWORD wait_ret;
923     BOOL ret;
924 
925     complete_event = CreateEventW(NULL, FALSE, FALSE, NULL);
926 
927     /* Test success case */
928     ret = RegisterWaitForSingleObject(&wait_handle, input_handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
929     ok(ret == TRUE, "Expected RegisterWaitForSingleObject to return TRUE, got %d\n", ret);
930     /* give worker thread a chance to start up */
931     Sleep(100);
932     record.EventType = KEY_EVENT;
933     record.Event.KeyEvent.bKeyDown = 1;
934     record.Event.KeyEvent.wRepeatCount = 1;
935     record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
936     record.Event.KeyEvent.wVirtualScanCode = VK_RETURN;
937     record.Event.KeyEvent.uChar.UnicodeChar = '\r';
938     record.Event.KeyEvent.dwControlKeyState = 0;
939     ret = WriteConsoleInputW(input_handle, &record, 1, &events_written);
940     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
941     wait_ret = WaitForSingleObject(complete_event, INFINITE);
942     ok(wait_ret == WAIT_OBJECT_0, "Expected the handle to be signaled\n");
943     ret = UnregisterWait(wait_handle);
944     /* If the callback is still running, this fails with ERROR_IO_PENDING, but
945        that's ok and expected. */
946     ok(ret != 0 || GetLastError() == ERROR_IO_PENDING,
947         "UnregisterWait failed with error %d\n", GetLastError());
948 
949     /* Test timeout case */
950     FlushConsoleInputBuffer(input_handle);
951     ret = RegisterWaitForSingleObject(&wait_handle, input_handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
952     wait_ret = WaitForSingleObject(complete_event, 100);
953     ok(wait_ret == WAIT_TIMEOUT, "Expected the wait to time out\n");
954     ret = UnregisterWait(wait_handle);
955     ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
956 
957     /* Clean up */
958     CloseHandle(complete_event);
959 }
960 
961 static void test_GetSetConsoleInputExeName(void)
962 {
963     BOOL ret;
964     DWORD error;
965     char buffer[MAX_PATH], module[MAX_PATH], *p;
966     static char input_exe[MAX_PATH] = "winetest.exe";
967 
968     SetLastError(0xdeadbeef);
969     ret = pGetConsoleInputExeNameA(0, NULL);
970     error = GetLastError();
971     ok(ret, "GetConsoleInputExeNameA failed\n");
972     ok(error == ERROR_BUFFER_OVERFLOW, "got %u expected ERROR_BUFFER_OVERFLOW\n", error);
973 
974     SetLastError(0xdeadbeef);
975     ret = pGetConsoleInputExeNameA(0, buffer);
976     error = GetLastError();
977     ok(ret, "GetConsoleInputExeNameA failed\n");
978     ok(error == ERROR_BUFFER_OVERFLOW, "got %u expected ERROR_BUFFER_OVERFLOW\n", error);
979 
980     GetModuleFileNameA(GetModuleHandleA(NULL), module, sizeof(module));
981     p = strrchr(module, '\\') + 1;
982 
983     ret = pGetConsoleInputExeNameA(sizeof(buffer)/sizeof(buffer[0]), buffer);
984     ok(ret, "GetConsoleInputExeNameA failed\n");
985     todo_wine ok(!lstrcmpA(buffer, p), "got %s expected %s\n", buffer, p);
986 
987     SetLastError(0xdeadbeef);
988     ret = pSetConsoleInputExeNameA(NULL);
989     error = GetLastError();
990     ok(!ret, "SetConsoleInputExeNameA failed\n");
991     ok(error == ERROR_INVALID_PARAMETER, "got %u expected ERROR_INVALID_PARAMETER\n", error);
992 
993     SetLastError(0xdeadbeef);
994     ret = pSetConsoleInputExeNameA("");
995     error = GetLastError();
996     ok(!ret, "SetConsoleInputExeNameA failed\n");
997     ok(error == ERROR_INVALID_PARAMETER, "got %u expected ERROR_INVALID_PARAMETER\n", error);
998 
999     ret = pSetConsoleInputExeNameA(input_exe);
1000     ok(ret, "SetConsoleInputExeNameA failed\n");
1001 
1002     ret = pGetConsoleInputExeNameA(sizeof(buffer)/sizeof(buffer[0]), buffer);
1003     ok(ret, "GetConsoleInputExeNameA failed\n");
1004     ok(!lstrcmpA(buffer, input_exe), "got %s expected %s\n", buffer, input_exe);
1005 }
1006 
1007 static void test_GetConsoleProcessList(void)
1008 {
1009     DWORD ret, *list = NULL;
1010 
1011     if (!pGetConsoleProcessList)
1012     {
1013         win_skip("GetConsoleProcessList is not available\n");
1014         return;
1015     }
1016 
1017     SetLastError(0xdeadbeef);
1018     ret = pGetConsoleProcessList(NULL, 0);
1019     ok(ret == 0, "Expected failure\n");
1020     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1021        "Expected ERROR_INVALID_PARAMETER, got %d\n",
1022        GetLastError());
1023 
1024     SetLastError(0xdeadbeef);
1025     ret = pGetConsoleProcessList(NULL, 1);
1026     ok(ret == 0, "Expected failure\n");
1027     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1028        "Expected ERROR_INVALID_PARAMETER, got %d\n",
1029        GetLastError());
1030 
1031     /* We should only have 1 process but only for these specific unit tests as
1032      * we created our own console. An AttachConsole(ATTACH_PARENT_PROCESS) would
1033      * give us two processes for example.
1034      */
1035     list = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD));
1036 
1037     SetLastError(0xdeadbeef);
1038     ret = pGetConsoleProcessList(list, 0);
1039     ok(ret == 0, "Expected failure\n");
1040     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1041        "Expected ERROR_INVALID_PARAMETER, got %d\n",
1042        GetLastError());
1043 
1044     SetLastError(0xdeadbeef);
1045     ret = pGetConsoleProcessList(list, 1);
1046     todo_wine
1047     ok(ret == 1, "Expected 1, got %d\n", ret);
1048 
1049     HeapFree(GetProcessHeap(), 0, list);
1050 
1051     list = HeapAlloc(GetProcessHeap(), 0, ret * sizeof(DWORD));
1052 
1053     SetLastError(0xdeadbeef);
1054     ret = pGetConsoleProcessList(list, ret);
1055     todo_wine
1056     ok(ret == 1, "Expected 1, got %d\n", ret);
1057 
1058     if (ret == 1)
1059     {
1060         DWORD pid = GetCurrentProcessId();
1061         ok(list[0] == pid, "Expected %d, got %d\n", pid, list[0]);
1062     }
1063 
1064     HeapFree(GetProcessHeap(), 0, list);
1065 }
1066 
1067 static void test_OpenCON(void)
1068 {
1069     static const WCHAR conW[] = {'C','O','N',0};
1070     static const DWORD accesses[] = {CREATE_NEW, CREATE_ALWAYS, OPEN_EXISTING,
1071                                      OPEN_ALWAYS, TRUNCATE_EXISTING};
1072     unsigned            i;
1073     HANDLE              h;
1074 
1075     for (i = 0; i < sizeof(accesses) / sizeof(accesses[0]); i++)
1076     {
1077         h = CreateFileW(conW, GENERIC_WRITE, 0, NULL, accesses[i], 0, NULL);
1078         ok(h != INVALID_HANDLE_VALUE || broken(accesses[i] == TRUNCATE_EXISTING /* Win8 */),
1079            "Expected to open the CON device on write (%x)\n", accesses[i]);
1080         CloseHandle(h);
1081 
1082         h = CreateFileW(conW, GENERIC_READ, 0, NULL, accesses[i], 0, NULL);
1083         /* Windows versions differ here:
1084          * MSDN states in CreateFile that TRUNCATE_EXISTING requires GENERIC_WRITE
1085          * NT, XP, Vista comply, but Win7 doesn't and allows opening CON with TRUNCATE_EXISTING
1086          * So don't test when disposition is TRUNCATE_EXISTING
1087          */
1088         ok(h != INVALID_HANDLE_VALUE || broken(accesses[i] == TRUNCATE_EXISTING /* Win7+ */),
1089            "Expected to open the CON device on read (%x)\n", accesses[i]);
1090         CloseHandle(h);
1091         h = CreateFileW(conW, GENERIC_READ|GENERIC_WRITE, 0, NULL, accesses[i], 0, NULL);
1092         ok(h == INVALID_HANDLE_VALUE, "Expected not to open the CON device on read-write (%x)\n", accesses[i]);
1093         ok(GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_INVALID_PARAMETER,
1094            "Unexpected error %x\n", GetLastError());
1095     }
1096 }
1097 
1098 static void test_OpenConsoleW(void)
1099 {
1100     static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
1101     static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
1102     static const WCHAR emptyW[] = {0};
1103     static const WCHAR invalidW[] = {'I','N','V','A','L','I','D',0};
1104     DWORD gle;
1105 
1106     static const struct
1107     {
1108         LPCWSTR name;
1109         DWORD access;
1110         BOOL inherit;
1111         DWORD creation;
1112         DWORD gle, gle2;
1113     } invalid_table[] = {
1114         {NULL,     0,                            FALSE,      0,                 ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1115         {NULL,     0,                            FALSE,      0xdeadbeef,        ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1116         {NULL,     0xdeadbeef,                   FALSE,      0,                 ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1117         {NULL,     0xdeadbeef,                   TRUE,       0xdeadbeef,        ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1118         {NULL,     0,                            FALSE,      OPEN_ALWAYS,       ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1119         {NULL,     GENERIC_READ | GENERIC_WRITE, FALSE,      0,                 ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1120         {NULL,     GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_ALWAYS,       ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1121         {NULL,     GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_EXISTING,     ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1122         {emptyW,   0,                            FALSE,      0,                 ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1123         {emptyW,   0,                            FALSE,      0xdeadbeef,        ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1124         {emptyW,   0xdeadbeef,                   FALSE,      0,                 ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1125         {emptyW,   0xdeadbeef,                   TRUE,       0xdeadbeef,        ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1126         {emptyW,   0,                            FALSE,      OPEN_ALWAYS,       ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1127         {emptyW,   GENERIC_READ | GENERIC_WRITE, FALSE,      0,                 ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1128         {emptyW,   GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_ALWAYS,       ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1129         {emptyW,   GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_EXISTING,     ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1130         {invalidW, 0,                            FALSE,      0,                 ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1131         {invalidW, 0,                            FALSE,      0xdeadbeef,        ERROR_INVALID_PARAMETER, 0},
1132         {invalidW, 0xdeadbeef,                   FALSE,      0,                 ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1133         {invalidW, 0xdeadbeef,                   TRUE,       0xdeadbeef,        ERROR_INVALID_PARAMETER, 0},
1134         {invalidW, 0,                            FALSE,      OPEN_ALWAYS,       ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1135         {invalidW, GENERIC_READ | GENERIC_WRITE, FALSE,      0,                 ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1136         {invalidW, GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_ALWAYS,       ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1137         {invalidW, GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_EXISTING,     ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1138         {coninW,   0,                            FALSE,      0xdeadbeef,        ERROR_INVALID_PARAMETER, 0},
1139         {coninW,   0xdeadbeef,                   FALSE,      0,                 ERROR_INVALID_PARAMETER, ERROR_ACCESS_DENIED},
1140         {coninW,   0xdeadbeef,                   TRUE,       0xdeadbeef,        ERROR_INVALID_PARAMETER, 0},
1141         {conoutW,  0,                            FALSE,      0xdeadbeef,        ERROR_INVALID_PARAMETER, 0},
1142         {conoutW,  0xceadbeef,                   FALSE,      0,                 ERROR_INVALID_PARAMETER, ERROR_ACCESS_DENIED},
1143         {conoutW,  0xdeadbeef,                   TRUE,       0xdeadbeef,        ERROR_INVALID_PARAMETER, 0},
1144     };
1145     static const struct
1146     {
1147         LPCWSTR name;
1148         DWORD access;
1149         BOOL inherit;
1150         DWORD creation;
1151     } valid_table[] = {
1152         {coninW,   0,                            FALSE,      0                },
1153         {coninW,   0,                            TRUE,       0                },
1154         {coninW,   GENERIC_EXECUTE,              TRUE,       0                },
1155         {coninW,   GENERIC_ALL,                  TRUE,       0                },
1156         {coninW,   0,                            FALSE,      OPEN_ALWAYS      },
1157         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      0                },
1158         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      CREATE_NEW       },
1159         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      CREATE_ALWAYS    },
1160         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_ALWAYS      },
1161         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      TRUNCATE_EXISTING},
1162         {conoutW,  0,                            FALSE,      0                },
1163         {conoutW,  0,                            FALSE,      OPEN_ALWAYS      },
1164         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      0                },
1165         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      CREATE_NEW,      },
1166         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      CREATE_ALWAYS    },
1167         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_ALWAYS      },
1168         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      TRUNCATE_EXISTING},
1169     };
1170 
1171     int index;
1172     HANDLE ret;
1173 
1174     if (!pOpenConsoleW)
1175     {
1176         win_skip("OpenConsoleW is not available\n");
1177         return;
1178     }
1179 
1180     for (index = 0; index < sizeof(invalid_table)/sizeof(invalid_table[0]); index++)
1181     {
1182         SetLastError(0xdeadbeef);
1183         ret = pOpenConsoleW(invalid_table[index].name, invalid_table[index].access,
1184                             invalid_table[index].inherit, invalid_table[index].creation);
1185         gle = GetLastError();
1186         ok(ret == INVALID_HANDLE_VALUE,
1187            "Expected OpenConsoleW to return INVALID_HANDLE_VALUE for index %d, got %p\n",
1188            index, ret);
1189         ok(gle == invalid_table[index].gle || (gle != 0 && gle == invalid_table[index].gle2),
1190            "Expected GetLastError() to return %u/%u for index %d, got %u\n",
1191            invalid_table[index].gle, invalid_table[index].gle2, index, gle);
1192     }
1193 
1194     for (index = 0; index < sizeof(valid_table)/sizeof(valid_table[0]); index++)
1195     {
1196         ret = pOpenConsoleW(valid_table[index].name, valid_table[index].access,
1197                             valid_table[index].inherit, valid_table[index].creation);
1198         todo_wine
1199         ok(ret != INVALID_HANDLE_VALUE || broken(ret == INVALID_HANDLE_VALUE /* until Win7 */),
1200            "Expected OpenConsoleW to succeed for index %d, got %p\n", index, ret);
1201         if (ret != INVALID_HANDLE_VALUE)
1202             CloseHandle(ret);
1203     }
1204 
1205     ret = pOpenConsoleW(coninW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING);
1206     ok(ret != INVALID_HANDLE_VALUE, "Expected OpenConsoleW to return a valid handle\n");
1207     if (ret != INVALID_HANDLE_VALUE)
1208         CloseHandle(ret);
1209 
1210     ret = pOpenConsoleW(conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING);
1211     ok(ret != INVALID_HANDLE_VALUE, "Expected OpenConsoleW to return a valid handle\n");
1212     if (ret != INVALID_HANDLE_VALUE)
1213         CloseHandle(ret);
1214 }
1215 
1216 static void test_CreateFileW(void)
1217 {
1218     static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
1219     static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
1220 
1221     static const struct
1222     {
1223         LPCWSTR name;
1224         DWORD access;
1225         BOOL inherit;
1226         DWORD creation;
1227         DWORD gle;
1228         BOOL is_broken;
1229     } cf_table[] = {
1230         {coninW,   0,                            FALSE,      0,                 ERROR_INVALID_PARAMETER,        TRUE},
1231         {coninW,   0,                            FALSE,      OPEN_ALWAYS,       0,                              FALSE},
1232         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      0,                 ERROR_INVALID_PARAMETER,        TRUE},
1233         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      CREATE_NEW,        0,                              FALSE},
1234         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      CREATE_ALWAYS,     0,                              FALSE},
1235         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_ALWAYS,       0,                              FALSE},
1236         {conoutW,  0,                            FALSE,      0,                 ERROR_INVALID_PARAMETER,        TRUE},
1237         {conoutW,  0,                            FALSE,      OPEN_ALWAYS,       0,                              FALSE},
1238         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      0,                 ERROR_INVALID_PARAMETER,        TRUE},
1239         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      CREATE_NEW,        0,                              FALSE},
1240         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      CREATE_ALWAYS,     0,                              FALSE},
1241         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_ALWAYS,       0,                              FALSE},
1242         /* TRUNCATE_EXISTING is forbidden starting with Windows 8 */
1243     };
1244 
1245     int index;
1246     HANDLE ret;
1247     SECURITY_ATTRIBUTES sa;
1248 
1249     for (index = 0; index < sizeof(cf_table)/sizeof(cf_table[0]); index++)
1250     {
1251         SetLastError(0xdeadbeef);
1252 
1253         sa.nLength = sizeof(sa);
1254         sa.lpSecurityDescriptor = NULL;
1255         sa.bInheritHandle = cf_table[index].inherit;
1256 
1257         ret = CreateFileW(cf_table[index].name, cf_table[index].access,
1258                           FILE_SHARE_READ|FILE_SHARE_WRITE, &sa,
1259                           cf_table[index].creation, FILE_ATTRIBUTE_NORMAL, NULL);
1260         if (ret == INVALID_HANDLE_VALUE)
1261         {
1262             ok(cf_table[index].gle,
1263                "Expected CreateFileW not to return INVALID_HANDLE_VALUE for index %d\n", index);
1264             ok(GetLastError() == cf_table[index].gle,
1265                 "Expected GetLastError() to return %u for index %d, got %u\n",
1266                 cf_table[index].gle, index, GetLastError());
1267         }
1268         else
1269         {
1270             ok(!cf_table[index].gle || broken(cf_table[index].is_broken) /* Win7 */,
1271                "Expected CreateFileW to succeed for index %d\n", index);
1272             CloseHandle(ret);
1273         }
1274     }
1275 }
1276 
1277 static void test_VerifyConsoleIoHandle( HANDLE handle )
1278 {
1279     BOOL ret;
1280     DWORD error;
1281 
1282     if (!pVerifyConsoleIoHandle)
1283     {
1284         win_skip("VerifyConsoleIoHandle is not available\n");
1285         return;
1286     }
1287 
1288     /* invalid handle */
1289     SetLastError(0xdeadbeef);
1290     ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee0);
1291     error = GetLastError();
1292     ok(!ret, "expected VerifyConsoleIoHandle to fail\n");
1293     ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error);
1294 
1295     /* invalid handle + 1 */
1296     SetLastError(0xdeadbeef);
1297     ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee1);
1298     error = GetLastError();
1299     ok(!ret, "expected VerifyConsoleIoHandle to fail\n");
1300     ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error);
1301 
1302     /* invalid handle + 2 */
1303     SetLastError(0xdeadbeef);
1304     ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee2);
1305     error = GetLastError();
1306     ok(!ret, "expected VerifyConsoleIoHandle to fail\n");
1307     ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error);
1308 
1309     /* invalid handle + 3 */
1310     SetLastError(0xdeadbeef);
1311     ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee3);
1312     error = GetLastError();
1313     ok(!ret, "expected VerifyConsoleIoHandle to fail\n");
1314     ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error);
1315 
1316     /* valid handle */
1317     SetLastError(0xdeadbeef);
1318     ret = pVerifyConsoleIoHandle(handle);
1319     error = GetLastError();
1320     ok(ret ||
1321        broken(!ret), /* Windows 8 and 10 */
1322        "expected VerifyConsoleIoHandle to succeed\n");
1323     ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error);
1324 }
1325 
1326 static void test_GetSetStdHandle(void)
1327 {
1328     HANDLE handle;
1329     DWORD error;
1330     BOOL ret;
1331 
1332     /* get invalid std handle */
1333     SetLastError(0xdeadbeef);
1334     handle = GetStdHandle(42);
1335     error = GetLastError();
1336     ok(error == ERROR_INVALID_HANDLE || broken(error == ERROR_INVALID_FUNCTION)/* Win9x */,
1337        "wrong GetLastError() %d\n", error);
1338     ok(handle == INVALID_HANDLE_VALUE, "expected INVALID_HANDLE_VALUE\n");
1339 
1340     /* get valid */
1341     SetLastError(0xdeadbeef);
1342     handle = GetStdHandle(STD_INPUT_HANDLE);
1343     error = GetLastError();
1344     ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error);
1345 
1346     /* set invalid std handle */
1347     SetLastError(0xdeadbeef);
1348     ret = SetStdHandle(42, handle);
1349     error = GetLastError();
1350     ok(!ret, "expected SetStdHandle to fail\n");
1351     ok(error == ERROR_INVALID_HANDLE || broken(error == ERROR_INVALID_FUNCTION)/* Win9x */,
1352        "wrong GetLastError() %d\n", error);
1353 
1354     /* set valid (restore old value) */
1355     SetLastError(0xdeadbeef);
1356     ret = SetStdHandle(STD_INPUT_HANDLE, handle);
1357     error = GetLastError();
1358     ok(ret, "expected SetStdHandle to succeed\n");
1359     ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error);
1360 }
1361 
1362 static void test_GetNumberOfConsoleInputEvents(HANDLE input_handle)
1363 {
1364     DWORD count;
1365     BOOL ret;
1366     int i;
1367 
1368     const struct
1369     {
1370         HANDLE handle;
1371         LPDWORD nrofevents;
1372         DWORD last_error;
1373     } invalid_table[] =
1374     {
1375         {NULL,                 NULL,   ERROR_INVALID_HANDLE},
1376         {NULL,                 &count, ERROR_INVALID_HANDLE},
1377         {INVALID_HANDLE_VALUE, NULL,   ERROR_INVALID_HANDLE},
1378         {INVALID_HANDLE_VALUE, &count, ERROR_INVALID_HANDLE},
1379     };
1380 
1381     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
1382     {
1383         SetLastError(0xdeadbeef);
1384         if (invalid_table[i].nrofevents) count = 0xdeadbeef;
1385         ret = GetNumberOfConsoleInputEvents(invalid_table[i].handle,
1386                                             invalid_table[i].nrofevents);
1387         ok(!ret, "[%d] Expected GetNumberOfConsoleInputEvents to return FALSE, got %d\n", i, ret);
1388         if (invalid_table[i].nrofevents)
1389         {
1390             ok(count == 0xdeadbeef,
1391                "[%d] Expected output count to be unmodified, got %u\n", i, count);
1392         }
1393         ok(GetLastError() == invalid_table[i].last_error,
1394            "[%d] Expected last error to be %u, got %u\n",
1395            i, invalid_table[i].last_error, GetLastError());
1396     }
1397 
1398     /* Test crashes on Windows 7. */
1399     if (0)
1400     {
1401         SetLastError(0xdeadbeef);
1402         ret = GetNumberOfConsoleInputEvents(input_handle, NULL);
1403         ok(!ret, "Expected GetNumberOfConsoleInputEvents to return FALSE, got %d\n", ret);
1404         ok(GetLastError() == ERROR_INVALID_ACCESS,
1405            "Expected last error to be ERROR_INVALID_ACCESS, got %u\n",
1406            GetLastError());
1407     }
1408 
1409     count = 0xdeadbeef;
1410     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1411     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1412     ok(count != 0xdeadbeef, "Expected output count to initialized\n");
1413 }
1414 
1415 static void test_WriteConsoleInputA(HANDLE input_handle)
1416 {
1417     INPUT_RECORD event;
1418     INPUT_RECORD event_list[5];
1419     MOUSE_EVENT_RECORD mouse_event = { {0, 0}, 0, 0, MOUSE_MOVED };
1420     KEY_EVENT_RECORD key_event;
1421     DWORD count, console_mode, gle;
1422     BOOL ret;
1423     int i;
1424 
1425     const struct
1426     {
1427         HANDLE handle;
1428         const INPUT_RECORD *buffer;
1429         DWORD count;
1430         LPDWORD written;
1431         DWORD gle, gle2;
1432         int win_crash;
1433     } invalid_table[] =
1434     {
1435         {NULL, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1436         {NULL, NULL, 0, &count,ERROR_INVALID_HANDLE},
1437         {NULL, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1438         {NULL, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
1439         {NULL, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1440         {NULL, &event, 0, &count, ERROR_INVALID_HANDLE},
1441         {NULL, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1442         {NULL, &event, 1, &count, ERROR_INVALID_HANDLE},
1443         {INVALID_HANDLE_VALUE, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1444         {INVALID_HANDLE_VALUE, NULL, 0, &count, ERROR_INVALID_HANDLE},
1445         {INVALID_HANDLE_VALUE, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1446         {INVALID_HANDLE_VALUE, NULL, 1, &count, ERROR_INVALID_HANDLE, ERROR_INVALID_ACCESS},
1447         {INVALID_HANDLE_VALUE, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1448         {INVALID_HANDLE_VALUE, &event, 0, &count, ERROR_INVALID_HANDLE},
1449         {INVALID_HANDLE_VALUE, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1450         {INVALID_HANDLE_VALUE, &event, 1, &count, ERROR_INVALID_HANDLE},
1451         {input_handle, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1452         {input_handle, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1453         {input_handle, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
1454         {input_handle, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1455         {input_handle, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1456     };
1457 
1458     /* Suppress external sources of input events for the duration of the test. */
1459     ret = GetConsoleMode(input_handle, &console_mode);
1460     ok(ret == TRUE, "Expected GetConsoleMode to return TRUE, got %d\n", ret);
1461     if (!ret)
1462     {
1463         skip("GetConsoleMode failed with last error %u\n", GetLastError());
1464         return;
1465     }
1466 
1467     ret = SetConsoleMode(input_handle, console_mode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
1468     ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret);
1469     if (!ret)
1470     {
1471         skip("SetConsoleMode failed with last error %u\n", GetLastError());
1472         return;
1473     }
1474 
1475     /* Discard any events queued before the tests. */
1476     ret = FlushConsoleInputBuffer(input_handle);
1477     ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1478 
1479     event.EventType = MOUSE_EVENT;
1480     event.Event.MouseEvent = mouse_event;
1481 
1482     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
1483     {
1484         if (invalid_table[i].win_crash)
1485             continue;
1486 
1487         SetLastError(0xdeadbeef);
1488         if (invalid_table[i].written) count = 0xdeadbeef;
1489         ret = WriteConsoleInputA(invalid_table[i].handle,
1490                                  invalid_table[i].buffer,
1491                                  invalid_table[i].count,
1492                                  invalid_table[i].written);
1493         ok(!ret, "[%d] Expected WriteConsoleInputA to return FALSE, got %d\n", i, ret);
1494         gle = GetLastError();
1495         ok(gle == invalid_table[i].gle || (gle != 0 && gle == invalid_table[i].gle2),
1496            "[%d] Expected last error to be %u or %u, got %u\n",
1497            i, invalid_table[i].gle, invalid_table[i].gle2, gle);
1498     }
1499 
1500     count = 0xdeadbeef;
1501     ret = WriteConsoleInputA(input_handle, NULL, 0, &count);
1502     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1503     ok(count == 0, "Expected count to be 0, got %u\n", count);
1504 
1505     count = 0xdeadbeef;
1506     ret = WriteConsoleInputA(input_handle, &event, 0, &count);
1507     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1508     ok(count == 0, "Expected count to be 0, got %u\n", count);
1509 
1510     count = 0xdeadbeef;
1511     ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1512     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1513     ok(count == 1, "Expected count to be 1, got %u\n", count);
1514 
1515     ret = FlushConsoleInputBuffer(input_handle);
1516     ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1517 
1518     /* Writing a single mouse event doesn't seem to affect the count if an adjacent mouse event is already queued. */
1519     event.EventType = MOUSE_EVENT;
1520     event.Event.MouseEvent = mouse_event;
1521 
1522     ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1523     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1524     ok(count == 1, "Expected count to be 1, got %u\n", count);
1525 
1526     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1527     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1528     ok(count == 1, "Expected count to be 1, got %u\n", count);
1529 
1530     ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1531     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1532     ok(count == 1, "Expected count to be 1, got %u\n", count);
1533 
1534     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1535     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1536     todo_wine
1537     ok(count == 1, "Expected count to be 1, got %u\n", count);
1538 
1539     ret = FlushConsoleInputBuffer(input_handle);
1540     ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1541 
1542     for (i = 0; i < sizeof(event_list)/sizeof(event_list[0]); i++)
1543     {
1544         event_list[i].EventType = MOUSE_EVENT;
1545         event_list[i].Event.MouseEvent = mouse_event;
1546     }
1547 
1548     /* Writing consecutive chunks of mouse events appears to work. */
1549     ret = WriteConsoleInputA(input_handle, event_list, sizeof(event_list)/sizeof(event_list[0]), &count);
1550     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1551     ok(count == sizeof(event_list)/sizeof(event_list[0]),
1552        "Expected count to be event list length, got %u\n", count);
1553 
1554     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1555     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1556     ok(count == sizeof(event_list)/sizeof(event_list[0]),
1557        "Expected count to be event list length, got %u\n", count);
1558 
1559     ret = WriteConsoleInputA(input_handle, event_list, sizeof(event_list)/sizeof(event_list[0]), &count);
1560     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1561     ok(count == sizeof(event_list)/sizeof(event_list[0]),
1562        "Expected count to be event list length, got %u\n", count);
1563 
1564     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1565     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1566     ok(count == 2*sizeof(event_list)/sizeof(event_list[0]),
1567        "Expected count to be twice event list length, got %u\n", count);
1568 
1569     /* Again, writing a single mouse event with adjacent mouse events queued doesn't appear to affect the count. */
1570     ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1571     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1572     ok(count == 1, "Expected count to be 1, got %u\n", count);
1573 
1574     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1575     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1576     todo_wine
1577     ok(count == 2*sizeof(event_list)/sizeof(event_list[0]),
1578        "Expected count to be twice event list length, got %u\n", count);
1579 
1580     ret = FlushConsoleInputBuffer(input_handle);
1581     ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1582 
1583     key_event.bKeyDown = FALSE;
1584     key_event.wRepeatCount = 0;
1585     key_event.wVirtualKeyCode = VK_SPACE;
1586     key_event.wVirtualScanCode = VK_SPACE;
1587     key_event.uChar.AsciiChar = ' ';
1588     key_event.dwControlKeyState = 0;
1589 
1590     event.EventType = KEY_EVENT;
1591     event.Event.KeyEvent = key_event;
1592 
1593     /* Key events don't exhibit the same behavior as mouse events. */
1594     ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1595     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1596     ok(count == 1, "Expected count to be 1, got %u\n", count);
1597 
1598     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1599     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1600     ok(count == 1, "Expected count to be 1, got %u\n", count);
1601 
1602     ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1603     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1604     ok(count == 1, "Expected count to be 1, got %u\n", count);
1605 
1606     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1607     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1608     ok(count == 2, "Expected count to be 2, got %u\n", count);
1609 
1610     ret = FlushConsoleInputBuffer(input_handle);
1611     ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1612 
1613     /* Try interleaving mouse and key events. */
1614     event.EventType = MOUSE_EVENT;
1615     event.Event.MouseEvent = mouse_event;
1616 
1617     ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1618     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1619     ok(count == 1, "Expected count to be 1, got %u\n", count);
1620 
1621     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1622     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1623     ok(count == 1, "Expected count to be 1, got %u\n", count);
1624 
1625     event.EventType = KEY_EVENT;
1626     event.Event.KeyEvent = key_event;
1627 
1628     ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1629     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1630     ok(count == 1, "Expected count to be 1, got %u\n", count);
1631 
1632     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1633     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1634     ok(count == 2, "Expected count to be 2, got %u\n", count);
1635 
1636     event.EventType = MOUSE_EVENT;
1637     event.Event.MouseEvent = mouse_event;
1638 
1639     ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1640     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1641     ok(count == 1, "Expected count to be 1, got %u\n", count);
1642 
1643     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1644     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1645     ok(count == 3, "Expected count to be 3, got %u\n", count);
1646 
1647     /* Restore the old console mode. */
1648     ret = SetConsoleMode(input_handle, console_mode);
1649     ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret);
1650 }
1651 
1652 static void test_WriteConsoleInputW(HANDLE input_handle)
1653 {
1654     INPUT_RECORD event;
1655     INPUT_RECORD event_list[5];
1656     MOUSE_EVENT_RECORD mouse_event = { {0, 0}, 0, 0, MOUSE_MOVED };
1657     KEY_EVENT_RECORD key_event;
1658     DWORD count, console_mode, gle;
1659     BOOL ret;
1660     int i;
1661 
1662     const struct
1663     {
1664         HANDLE handle;
1665         const INPUT_RECORD *buffer;
1666         DWORD count;
1667         LPDWORD written;
1668         DWORD gle, gle2;
1669         int win_crash;
1670     } invalid_table[] =
1671     {
1672         {NULL, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1673         {NULL, NULL, 0, &count, ERROR_INVALID_HANDLE},
1674         {NULL, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1675         {NULL, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
1676         {NULL, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1677         {NULL, &event, 0, &count, ERROR_INVALID_HANDLE},
1678         {NULL, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1679         {NULL, &event, 1, &count, ERROR_INVALID_HANDLE},
1680         {INVALID_HANDLE_VALUE, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1681         {INVALID_HANDLE_VALUE, NULL, 0, &count, ERROR_INVALID_HANDLE},
1682         {INVALID_HANDLE_VALUE, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1683         {INVALID_HANDLE_VALUE, NULL, 1, &count, ERROR_INVALID_HANDLE, ERROR_INVALID_ACCESS},
1684         {INVALID_HANDLE_VALUE, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1685         {INVALID_HANDLE_VALUE, &event, 0, &count, ERROR_INVALID_HANDLE},
1686         {INVALID_HANDLE_VALUE, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1687         {INVALID_HANDLE_VALUE, &event, 1, &count, ERROR_INVALID_HANDLE},
1688         {input_handle, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1689         {input_handle, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1690         {input_handle, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
1691         {input_handle, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1692         {input_handle, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1693     };
1694 
1695     /* Suppress external sources of input events for the duration of the test. */
1696     ret = GetConsoleMode(input_handle, &console_mode);
1697     ok(ret == TRUE, "Expected GetConsoleMode to return TRUE, got %d\n", ret);
1698     if (!ret)
1699     {
1700         skip("GetConsoleMode failed with last error %u\n", GetLastError());
1701         return;
1702     }
1703 
1704     ret = SetConsoleMode(input_handle, console_mode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
1705     ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret);
1706     if (!ret)
1707     {
1708         skip("SetConsoleMode failed with last error %u\n", GetLastError());
1709         return;
1710     }
1711 
1712     /* Discard any events queued before the tests. */
1713     ret = FlushConsoleInputBuffer(input_handle);
1714     ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1715 
1716     event.EventType = MOUSE_EVENT;
1717     event.Event.MouseEvent = mouse_event;
1718 
1719     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
1720     {
1721         if (invalid_table[i].win_crash)
1722             continue;
1723 
1724         SetLastError(0xdeadbeef);
1725         if (invalid_table[i].written) count = 0xdeadbeef;
1726         ret = WriteConsoleInputW(invalid_table[i].handle,
1727                                  invalid_table[i].buffer,
1728                                  invalid_table[i].count,
1729                                  invalid_table[i].written);
1730         ok(!ret, "[%d] Expected WriteConsoleInputW to return FALSE, got %d\n", i, ret);
1731         gle = GetLastError();
1732         ok(gle == invalid_table[i].gle || (gle != 0 && gle == invalid_table[i].gle2),
1733            "[%d] Expected last error to be %u or %u, got %u\n",
1734            i, invalid_table[i].gle, invalid_table[i].gle2, gle);
1735     }
1736 
1737     count = 0xdeadbeef;
1738     ret = WriteConsoleInputW(input_handle, NULL, 0, &count);
1739     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1740     ok(count == 0, "Expected count to be 0, got %u\n", count);
1741 
1742     count = 0xdeadbeef;
1743     ret = WriteConsoleInputW(input_handle, &event, 0, &count);
1744     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1745     ok(count == 0, "Expected count to be 0, got %u\n", count);
1746 
1747     count = 0xdeadbeef;
1748     ret = WriteConsoleInputW(input_handle, &event, 1, &count);
1749     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1750     ok(count == 1, "Expected count to be 1, got %u\n", count);
1751 
1752     ret = FlushConsoleInputBuffer(input_handle);
1753     ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1754 
1755     /* Writing a single mouse event doesn't seem to affect the count if an adjacent mouse event is already queued. */
1756     event.EventType = MOUSE_EVENT;
1757     event.Event.MouseEvent = mouse_event;
1758 
1759     ret = WriteConsoleInputW(input_handle, &event, 1, &count);
1760     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1761     ok(count == 1, "Expected count to be 1, got %u\n", count);
1762 
1763     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1764     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1765     ok(count == 1, "Expected count to be 1, got %u\n", count);
1766 
1767     ret = WriteConsoleInputW(input_handle, &event, 1, &count);
1768     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1769     ok(count == 1, "Expected count to be 1, got %u\n", count);
1770 
1771     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1772     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1773     todo_wine
1774     ok(count == 1, "Expected count to be 1, got %u\n", count);
1775 
1776     ret = FlushConsoleInputBuffer(input_handle);
1777     ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1778 
1779     for (i = 0; i < sizeof(event_list)/sizeof(event_list[0]); i++)
1780     {
1781         event_list[i].EventType = MOUSE_EVENT;
1782         event_list[i].Event.MouseEvent = mouse_event;
1783     }
1784 
1785     /* Writing consecutive chunks of mouse events appears to work. */
1786     ret = WriteConsoleInputW(input_handle, event_list, sizeof(event_list)/sizeof(event_list[0]), &count);
1787     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1788     ok(count == sizeof(event_list)/sizeof(event_list[0]),
1789        "Expected count to be event list length, got %u\n", count);
1790 
1791     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1792     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1793     ok(count == sizeof(event_list)/sizeof(event_list[0]),
1794        "Expected count to be event list length, got %u\n", count);
1795 
1796     ret = WriteConsoleInputW(input_handle, event_list, sizeof(event_list)/sizeof(event_list[0]), &count);
1797     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1798     ok(count == sizeof(event_list)/sizeof(event_list[0]),
1799        "Expected count to be event list length, got %u\n", count);
1800 
1801     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1802     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1803     ok(count == 2*sizeof(event_list)/sizeof(event_list[0]),
1804        "Expected count to be twice event list length, got %u\n", count);
1805 
1806     /* Again, writing a single mouse event with adjacent mouse events queued doesn't appear to affect the count. */
1807     ret = WriteConsoleInputW(input_handle, &event, 1, &count);
1808     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1809     ok(count == 1, "Expected count to be 1, got %u\n", count);
1810 
1811     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1812     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1813     todo_wine
1814     ok(count == 2*sizeof(event_list)/sizeof(event_list[0]),
1815        "Expected count to be twice event list length, got %u\n", count);
1816 
1817     ret = FlushConsoleInputBuffer(input_handle);
1818     ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1819 
1820     key_event.bKeyDown = FALSE;
1821     key_event.wRepeatCount = 0;
1822     key_event.wVirtualKeyCode = VK_SPACE;
1823     key_event.wVirtualScanCode = VK_SPACE;
1824     key_event.uChar.UnicodeChar = ' ';
1825     key_event.dwControlKeyState = 0;
1826 
1827     event.EventType = KEY_EVENT;
1828     event.Event.KeyEvent = key_event;
1829 
1830     /* Key events don't exhibit the same behavior as mouse events. */
1831     ret = WriteConsoleInputW(input_handle, &event, 1, &count);
1832     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1833     ok(count == 1, "Expected count to be 1, got %u\n", count);
1834 
1835     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1836     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1837     ok(count == 1, "Expected count to be 1, got %u\n", count);
1838 
1839     ret = WriteConsoleInputW(input_handle, &event, 1, &count);
1840     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1841     ok(count == 1, "Expected count to be 1, got %u\n", count);
1842 
1843     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1844     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1845     ok(count == 2, "Expected count to be 2, got %u\n", count);
1846 
1847     ret = FlushConsoleInputBuffer(input_handle);
1848     ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1849 
1850     /* Try interleaving mouse and key events. */
1851     event.EventType = MOUSE_EVENT;
1852     event.Event.MouseEvent = mouse_event;
1853 
1854     ret = WriteConsoleInputW(input_handle, &event, 1, &count);
1855     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1856     ok(count == 1, "Expected count to be 1, got %u\n", count);
1857 
1858     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1859     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1860     ok(count == 1, "Expected count to be 1, got %u\n", count);
1861 
1862     event.EventType = KEY_EVENT;
1863     event.Event.KeyEvent = key_event;
1864 
1865     ret = WriteConsoleInputW(input_handle, &event, 1, &count);
1866     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1867     ok(count == 1, "Expected count to be 1, got %u\n", count);
1868 
1869     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1870     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1871     ok(count == 2, "Expected count to be 2, got %u\n", count);
1872 
1873     event.EventType = MOUSE_EVENT;
1874     event.Event.MouseEvent = mouse_event;
1875 
1876     ret = WriteConsoleInputW(input_handle, &event, 1, &count);
1877     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1878     ok(count == 1, "Expected count to be 1, got %u\n", count);
1879 
1880     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1881     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1882     ok(count == 3, "Expected count to be 3, got %u\n", count);
1883 
1884     /* Restore the old console mode. */
1885     ret = SetConsoleMode(input_handle, console_mode);
1886     ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret);
1887 }
1888 
1889 static void test_WriteConsoleOutputCharacterA(HANDLE output_handle)
1890 {
1891     static const char output[] = {'a', 0};
1892 
1893     COORD origin = {0, 0};
1894     DWORD count;
1895     BOOL ret;
1896     int i;
1897 
1898     const struct
1899     {
1900         HANDLE hConsoleOutput;
1901         LPCSTR str;
1902         DWORD length;
1903         COORD coord;
1904         LPDWORD lpNumCharsWritten;
1905         DWORD expected_count;
1906         DWORD last_error;
1907         int win7_crash;
1908     } invalid_table[] =
1909     {
1910         {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1911         {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
1912         {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1913         {NULL, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1914         {NULL, output, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1915         {NULL, output, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
1916         {NULL, output, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1917         {NULL, output, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
1918         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1919         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
1920         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1921         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1922         {INVALID_HANDLE_VALUE, output, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1923         {INVALID_HANDLE_VALUE, output, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
1924         {INVALID_HANDLE_VALUE, output, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1925         {INVALID_HANDLE_VALUE, output, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
1926         {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1927         {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1928         {output_handle, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1929         {output_handle, output, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1930         {output_handle, output, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1931     };
1932 
1933     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
1934     {
1935         if (invalid_table[i].win7_crash)
1936             continue;
1937 
1938         SetLastError(0xdeadbeef);
1939         if (invalid_table[i].lpNumCharsWritten) count = 0xdeadbeef;
1940         ret = WriteConsoleOutputCharacterA(invalid_table[i].hConsoleOutput,
1941                                            invalid_table[i].str,
1942                                            invalid_table[i].length,
1943                                            invalid_table[i].coord,
1944                                            invalid_table[i].lpNumCharsWritten);
1945         ok(!ret, "[%d] Expected WriteConsoleOutputCharacterA to return FALSE, got %d\n", i, ret);
1946         if (invalid_table[i].lpNumCharsWritten)
1947         {
1948             ok(count == invalid_table[i].expected_count,
1949                "[%d] Expected count to be %u, got %u\n",
1950                i, invalid_table[i].expected_count, count);
1951         }
1952         ok(GetLastError() == invalid_table[i].last_error,
1953            "[%d] Expected last error to be %u, got %u\n",
1954            i, invalid_table[i].last_error, GetLastError());
1955     }
1956 
1957     count = 0xdeadbeef;
1958     ret = WriteConsoleOutputCharacterA(output_handle, NULL, 0, origin, &count);
1959     ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret);
1960     ok(count == 0, "Expected count to be 0, got %u\n", count);
1961 
1962     count = 0xdeadbeef;
1963     ret = WriteConsoleOutputCharacterA(output_handle, output, 0, origin, &count);
1964     ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret);
1965     ok(count == 0, "Expected count to be 0, got %u\n", count);
1966 
1967     count = 0xdeadbeef;
1968     ret = WriteConsoleOutputCharacterA(output_handle, output, 1, origin, &count);
1969     ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret);
1970     ok(count == 1, "Expected count to be 1, got %u\n", count);
1971 }
1972 
1973 static void test_WriteConsoleOutputCharacterW(HANDLE output_handle)
1974 {
1975     static const WCHAR outputW[] = {'a',0};
1976 
1977     COORD origin = {0, 0};
1978     DWORD count;
1979     BOOL ret;
1980     int i;
1981 
1982     const struct
1983     {
1984         HANDLE hConsoleOutput;
1985         LPCWSTR str;
1986         DWORD length;
1987         COORD coord;
1988         LPDWORD lpNumCharsWritten;
1989         DWORD expected_count;
1990         DWORD last_error;
1991         int win7_crash;
1992     } invalid_table[] =
1993     {
1994         {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1995         {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
1996         {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1997         {NULL, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1998         {NULL, outputW, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1999         {NULL, outputW, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2000         {NULL, outputW, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2001         {NULL, outputW, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2002         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2003         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2004         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2005         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2006         {INVALID_HANDLE_VALUE, outputW, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2007         {INVALID_HANDLE_VALUE, outputW, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2008         {INVALID_HANDLE_VALUE, outputW, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2009         {INVALID_HANDLE_VALUE, outputW, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2010         {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2011         {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2012         {output_handle, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2013         {output_handle, outputW, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2014         {output_handle, outputW, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2015     };
2016 
2017     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
2018     {
2019         if (invalid_table[i].win7_crash)
2020             continue;
2021 
2022         SetLastError(0xdeadbeef);
2023         if (invalid_table[i].lpNumCharsWritten) count = 0xdeadbeef;
2024         ret = WriteConsoleOutputCharacterW(invalid_table[i].hConsoleOutput,
2025                                            invalid_table[i].str,
2026                                            invalid_table[i].length,
2027                                            invalid_table[i].coord,
2028                                            invalid_table[i].lpNumCharsWritten);
2029         ok(!ret, "[%d] Expected WriteConsoleOutputCharacterW to return FALSE, got %d\n", i, ret);
2030         if (invalid_table[i].lpNumCharsWritten)
2031         {
2032             ok(count == invalid_table[i].expected_count,
2033                "[%d] Expected count to be %u, got %u\n",
2034                i, invalid_table[i].expected_count, count);
2035         }
2036         ok(GetLastError() == invalid_table[i].last_error,
2037            "[%d] Expected last error to be %u, got %u\n",
2038            i, invalid_table[i].last_error, GetLastError());
2039     }
2040 
2041     count = 0xdeadbeef;
2042     ret = WriteConsoleOutputCharacterW(output_handle, NULL, 0, origin, &count);
2043     ok(ret == TRUE, "Expected WriteConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2044     ok(count == 0, "Expected count to be 0, got %u\n", count);
2045 
2046     count = 0xdeadbeef;
2047     ret = WriteConsoleOutputCharacterW(output_handle, outputW, 0, origin, &count);
2048     ok(ret == TRUE, "Expected WriteConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2049     ok(count == 0, "Expected count to be 0, got %u\n", count);
2050 
2051     count = 0xdeadbeef;
2052     ret = WriteConsoleOutputCharacterW(output_handle, outputW, 1, origin, &count);
2053     ok(ret == TRUE, "Expected WriteConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2054     ok(count == 1, "Expected count to be 1, got %u\n", count);
2055 }
2056 
2057 static void test_WriteConsoleOutputAttribute(HANDLE output_handle)
2058 {
2059     WORD attr = FOREGROUND_BLUE;
2060     COORD origin = {0, 0};
2061     DWORD count;
2062     BOOL ret;
2063     int i;
2064 
2065     const struct
2066     {
2067         HANDLE hConsoleOutput;
2068         const WORD *attr;
2069         DWORD length;
2070         COORD coord;
2071         LPDWORD lpNumAttrsWritten;
2072         DWORD expected_count;
2073         DWORD last_error;
2074         int win7_crash;
2075     } invalid_table[] =
2076     {
2077         {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2078         {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2079         {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2080         {NULL, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2081         {NULL, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2082         {NULL, &attr, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2083         {NULL, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2084         {NULL, &attr, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2085         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2086         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2087         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2088         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2089         {INVALID_HANDLE_VALUE, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2090         {INVALID_HANDLE_VALUE, &attr, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2091         {INVALID_HANDLE_VALUE, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2092         {INVALID_HANDLE_VALUE, &attr, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2093         {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2094         {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2095         {output_handle, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2096         {output_handle, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2097         {output_handle, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2098     };
2099 
2100     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
2101     {
2102         if (invalid_table[i].win7_crash)
2103             continue;
2104 
2105         SetLastError(0xdeadbeef);
2106         if (invalid_table[i].lpNumAttrsWritten) count = 0xdeadbeef;
2107         ret = WriteConsoleOutputAttribute(invalid_table[i].hConsoleOutput,
2108                                           invalid_table[i].attr,
2109                                           invalid_table[i].length,
2110                                           invalid_table[i].coord,
2111                                           invalid_table[i].lpNumAttrsWritten);
2112         ok(!ret, "[%d] Expected WriteConsoleOutputAttribute to return FALSE, got %d\n", i, ret);
2113         if (invalid_table[i].lpNumAttrsWritten)
2114         {
2115             ok(count == invalid_table[i].expected_count,
2116                "[%d] Expected count to be %u, got %u\n",
2117                i, invalid_table[i].expected_count, count);
2118         }
2119         ok(GetLastError() == invalid_table[i].last_error,
2120            "[%d] Expected last error to be %u, got %u\n",
2121            i, invalid_table[i].last_error, GetLastError());
2122     }
2123 
2124     count = 0xdeadbeef;
2125     ret = WriteConsoleOutputAttribute(output_handle, NULL, 0, origin, &count);
2126     ok(ret == TRUE, "Expected WriteConsoleOutputAttribute to return TRUE, got %d\n", ret);
2127     ok(count == 0, "Expected count to be 0, got %u\n", count);
2128 
2129     count = 0xdeadbeef;
2130     ret = WriteConsoleOutputAttribute(output_handle, &attr, 0, origin, &count);
2131     ok(ret == TRUE, "Expected WriteConsoleOutputAttribute to return TRUE, got %d\n", ret);
2132     ok(count == 0, "Expected count to be 0, got %u\n", count);
2133 
2134     count = 0xdeadbeef;
2135     ret = WriteConsoleOutputAttribute(output_handle, &attr, 1, origin, &count);
2136     ok(ret == TRUE, "Expected WriteConsoleOutputAttribute to return TRUE, got %d\n", ret);
2137     ok(count == 1, "Expected count to be 1, got %u\n", count);
2138 }
2139 
2140 static void test_FillConsoleOutputCharacterA(HANDLE output_handle)
2141 {
2142     COORD origin = {0, 0};
2143     DWORD count;
2144     BOOL ret;
2145     int i;
2146 
2147     const struct
2148     {
2149         HANDLE hConsoleOutput;
2150         CHAR ch;
2151         DWORD length;
2152         COORD coord;
2153         LPDWORD lpNumCharsWritten;
2154         DWORD last_error;
2155         int win7_crash;
2156     } invalid_table[] =
2157     {
2158         {NULL, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2159         {NULL, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2160         {NULL, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2161         {NULL, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2162         {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2163         {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2164         {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2165         {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2166         {output_handle, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2167         {output_handle, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2168     };
2169 
2170     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
2171     {
2172         if (invalid_table[i].win7_crash)
2173             continue;
2174 
2175         SetLastError(0xdeadbeef);
2176         if (invalid_table[i].lpNumCharsWritten) count = 0xdeadbeef;
2177         ret = FillConsoleOutputCharacterA(invalid_table[i].hConsoleOutput,
2178                                           invalid_table[i].ch,
2179                                           invalid_table[i].length,
2180                                           invalid_table[i].coord,
2181                                           invalid_table[i].lpNumCharsWritten);
2182         ok(!ret, "[%d] Expected FillConsoleOutputCharacterA to return FALSE, got %d\n", i, ret);
2183         ok(GetLastError() == invalid_table[i].last_error,
2184            "[%d] Expected last error to be %u, got %u\n",
2185            i, invalid_table[i].last_error, GetLastError());
2186     }
2187 
2188     count = 0xdeadbeef;
2189     ret = FillConsoleOutputCharacterA(output_handle, 'a', 0, origin, &count);
2190     ok(ret == TRUE, "Expected FillConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2191     ok(count == 0, "Expected count to be 0, got %u\n", count);
2192 
2193     count = 0xdeadbeef;
2194     ret = FillConsoleOutputCharacterA(output_handle, 'a', 1, origin, &count);
2195     ok(ret == TRUE, "Expected FillConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2196     ok(count == 1, "Expected count to be 1, got %u\n", count);
2197 }
2198 
2199 static void test_FillConsoleOutputCharacterW(HANDLE output_handle)
2200 {
2201     COORD origin = {0, 0};
2202     DWORD count;
2203     BOOL ret;
2204     int i;
2205 
2206     const struct
2207     {
2208         HANDLE hConsoleOutput;
2209         WCHAR ch;
2210         DWORD length;
2211         COORD coord;
2212         LPDWORD lpNumCharsWritten;
2213         DWORD last_error;
2214         int win7_crash;
2215     } invalid_table[] =
2216     {
2217         {NULL, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2218         {NULL, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2219         {NULL, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2220         {NULL, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2221         {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2222         {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2223         {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2224         {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2225         {output_handle, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2226         {output_handle, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2227     };
2228 
2229     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
2230     {
2231         if (invalid_table[i].win7_crash)
2232             continue;
2233 
2234         SetLastError(0xdeadbeef);
2235         if (invalid_table[i].lpNumCharsWritten) count = 0xdeadbeef;
2236         ret = FillConsoleOutputCharacterW(invalid_table[i].hConsoleOutput,
2237                                           invalid_table[i].ch,
2238                                           invalid_table[i].length,
2239                                           invalid_table[i].coord,
2240                                           invalid_table[i].lpNumCharsWritten);
2241         ok(!ret, "[%d] Expected FillConsoleOutputCharacterW to return FALSE, got %d\n", i, ret);
2242         ok(GetLastError() == invalid_table[i].last_error,
2243            "[%d] Expected last error to be %u, got %u\n",
2244            i, invalid_table[i].last_error, GetLastError());
2245     }
2246 
2247     count = 0xdeadbeef;
2248     ret = FillConsoleOutputCharacterW(output_handle, 'a', 0, origin, &count);
2249     ok(ret == TRUE, "Expected FillConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2250     ok(count == 0, "Expected count to be 0, got %u\n", count);
2251 
2252     count = 0xdeadbeef;
2253     ret = FillConsoleOutputCharacterW(output_handle, 'a', 1, origin, &count);
2254     ok(ret == TRUE, "Expected FillConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2255     ok(count == 1, "Expected count to be 1, got %u\n", count);
2256 }
2257 
2258 static void test_FillConsoleOutputAttribute(HANDLE output_handle)
2259 {
2260     COORD origin = {0, 0};
2261     DWORD count;
2262     BOOL ret;
2263     int i;
2264 
2265     const struct
2266     {
2267         HANDLE hConsoleOutput;
2268         WORD attr;
2269         DWORD length;
2270         COORD coord;
2271         LPDWORD lpNumAttrsWritten;
2272         DWORD last_error;
2273         int win7_crash;
2274     } invalid_table[] =
2275     {
2276         {NULL, FOREGROUND_BLUE, 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2277         {NULL, FOREGROUND_BLUE, 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2278         {NULL, FOREGROUND_BLUE, 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2279         {NULL, FOREGROUND_BLUE, 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2280         {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2281         {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2282         {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2283         {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2284         {output_handle, FOREGROUND_BLUE, 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2285         {output_handle, FOREGROUND_BLUE, 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2286     };
2287 
2288     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
2289     {
2290         if (invalid_table[i].win7_crash)
2291             continue;
2292 
2293         SetLastError(0xdeadbeef);
2294         if (invalid_table[i].lpNumAttrsWritten) count = 0xdeadbeef;
2295         ret = FillConsoleOutputAttribute(invalid_table[i].hConsoleOutput,
2296                                          invalid_table[i].attr,
2297                                          invalid_table[i].length,
2298                                          invalid_table[i].coord,
2299                                          invalid_table[i].lpNumAttrsWritten);
2300         ok(!ret, "[%d] Expected FillConsoleOutputAttribute to return FALSE, got %d\n", i, ret);
2301         ok(GetLastError() == invalid_table[i].last_error,
2302            "[%d] Expected last error to be %u, got %u\n",
2303            i, invalid_table[i].last_error, GetLastError());
2304     }
2305 
2306     count = 0xdeadbeef;
2307     ret = FillConsoleOutputAttribute(output_handle, FOREGROUND_BLUE, 0, origin, &count);
2308     ok(ret == TRUE, "Expected FillConsoleOutputAttribute to return TRUE, got %d\n", ret);
2309     ok(count == 0, "Expected count to be 0, got %u\n", count);
2310 
2311     count = 0xdeadbeef;
2312     ret = FillConsoleOutputAttribute(output_handle, FOREGROUND_BLUE, 1, origin, &count);
2313     ok(ret == TRUE, "Expected FillConsoleOutputAttribute to return TRUE, got %d\n", ret);
2314     ok(count == 1, "Expected count to be 1, got %u\n", count);
2315 
2316     count = 0xdeadbeef;
2317     ret = FillConsoleOutputAttribute(output_handle, ~0, 1, origin, &count);
2318     ok(ret == TRUE, "Expected FillConsoleOutputAttribute to return TRUE, got %d\n", ret);
2319     ok(count == 1, "Expected count to be 1, got %u\n", count);
2320 }
2321 
2322 static void test_ReadConsoleOutputCharacterA(HANDLE output_handle)
2323 {
2324     CHAR read;
2325     COORD origin = {0, 0};
2326     DWORD count;
2327     BOOL ret;
2328     int i;
2329 
2330     const struct
2331     {
2332         HANDLE hConsoleOutput;
2333         LPSTR lpstr;
2334         DWORD length;
2335         COORD coord;
2336         LPDWORD read_count;
2337         DWORD expected_count;
2338         DWORD last_error;
2339         int win7_crash;
2340     } invalid_table[] =
2341     {
2342         {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2343         {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2344         {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2345         {NULL, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
2346         {NULL, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2347         {NULL, &read, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2348         {NULL, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2349         {NULL, &read, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2350         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2351         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2352         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2353         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
2354         {INVALID_HANDLE_VALUE, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2355         {INVALID_HANDLE_VALUE, &read, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2356         {INVALID_HANDLE_VALUE, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2357         {INVALID_HANDLE_VALUE, &read, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2358         {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2359         {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2360         {output_handle, NULL, 1, {0, 0}, &count, 1, ERROR_INVALID_ACCESS, 1},
2361         {output_handle, NULL, 10, {0, 0}, &count, 10, ERROR_INVALID_ACCESS, 1},
2362         {output_handle, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2363         {output_handle, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2364     };
2365 
2366     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
2367     {
2368         if (invalid_table[i].win7_crash)
2369             continue;
2370 
2371         SetLastError(0xdeadbeef);
2372         if (invalid_table[i].read_count) count = 0xdeadbeef;
2373         ret = ReadConsoleOutputCharacterA(invalid_table[i].hConsoleOutput,
2374                                           invalid_table[i].lpstr,
2375                                           invalid_table[i].length,
2376                                           invalid_table[i].coord,
2377                                           invalid_table[i].read_count);
2378         ok(!ret, "[%d] Expected ReadConsoleOutputCharacterA to return FALSE, got %d\n", i, ret);
2379         if (invalid_table[i].read_count)
2380         {
2381             ok(count == invalid_table[i].expected_count,
2382                "[%d] Expected count to be %u, got %u\n",
2383                i, invalid_table[i].expected_count, count);
2384         }
2385         ok(GetLastError() == invalid_table[i].last_error,
2386            "[%d] Expected last error to be %u, got %u\n",
2387            i, invalid_table[i].last_error, GetLastError());
2388     }
2389 
2390     count = 0xdeadbeef;
2391     ret = ReadConsoleOutputCharacterA(output_handle, NULL, 0, origin, &count);
2392     ok(ret == TRUE, "Expected ReadConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2393     ok(count == 0, "Expected count to be 0, got %u\n", count);
2394 
2395     count = 0xdeadbeef;
2396     ret = ReadConsoleOutputCharacterA(output_handle, &read, 0, origin, &count);
2397     ok(ret == TRUE, "Expected ReadConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2398     ok(count == 0, "Expected count to be 0, got %u\n", count);
2399 
2400     count = 0xdeadbeef;
2401     ret = ReadConsoleOutputCharacterA(output_handle, &read, 1, origin, &count);
2402     ok(ret == TRUE, "Expected ReadConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2403     ok(count == 1, "Expected count to be 1, got %u\n", count);
2404 }
2405 
2406 static void test_ReadConsoleOutputCharacterW(HANDLE output_handle)
2407 {
2408     WCHAR read;
2409     COORD origin = {0, 0};
2410     DWORD count;
2411     BOOL ret;
2412     int i;
2413 
2414     const struct
2415     {
2416         HANDLE hConsoleOutput;
2417         LPWSTR buffer;
2418         DWORD length;
2419         COORD coord;
2420         LPDWORD read_count;
2421         DWORD expected_count;
2422         DWORD last_error;
2423         int win7_crash;
2424     } invalid_table[] =
2425     {
2426         {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2427         {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2428         {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2429         {NULL, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
2430         {NULL, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2431         {NULL, &read, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2432         {NULL, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2433         {NULL, &read, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2434         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2435         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2436         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2437         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
2438         {INVALID_HANDLE_VALUE, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2439         {INVALID_HANDLE_VALUE, &read, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2440         {INVALID_HANDLE_VALUE, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2441         {INVALID_HANDLE_VALUE, &read, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2442         {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2443         {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2444         {output_handle, NULL, 1, {0, 0}, &count, 1, ERROR_INVALID_ACCESS, 1},
2445         {output_handle, NULL, 10, {0, 0}, &count, 10, ERROR_INVALID_ACCESS, 1},
2446         {output_handle, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2447         {output_handle, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2448     };
2449 
2450     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
2451     {
2452         if (invalid_table[i].win7_crash)
2453             continue;
2454 
2455         SetLastError(0xdeadbeef);
2456         if (invalid_table[i].read_count) count = 0xdeadbeef;
2457         ret = ReadConsoleOutputCharacterW(invalid_table[i].hConsoleOutput,
2458                                           invalid_table[i].buffer,
2459                                           invalid_table[i].length,
2460                                           invalid_table[i].coord,
2461                                           invalid_table[i].read_count);
2462         ok(!ret, "[%d] Expected ReadConsoleOutputCharacterW to return FALSE, got %d\n", i, ret);
2463         if (invalid_table[i].read_count)
2464         {
2465             ok(count == invalid_table[i].expected_count,
2466                "[%d] Expected count to be %u, got %u\n",
2467                i, invalid_table[i].expected_count, count);
2468         }
2469         ok(GetLastError() == invalid_table[i].last_error,
2470            "[%d] Expected last error to be %u, got %u\n",
2471            i, invalid_table[i].last_error, GetLastError());
2472     }
2473 
2474     count = 0xdeadbeef;
2475     ret = ReadConsoleOutputCharacterW(output_handle, NULL, 0, origin, &count);
2476     ok(ret == TRUE, "Expected ReadConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2477     ok(count == 0, "Expected count to be 0, got %u\n", count);
2478 
2479     count = 0xdeadbeef;
2480     ret = ReadConsoleOutputCharacterW(output_handle, &read, 0, origin, &count);
2481     ok(ret == TRUE, "Expected ReadConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2482     ok(count == 0, "Expected count to be 0, got %u\n", count);
2483 
2484     count = 0xdeadbeef;
2485     ret = ReadConsoleOutputCharacterW(output_handle, &read, 1, origin, &count);
2486     ok(ret == TRUE, "Expected ReadConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2487     ok(count == 1, "Expected count to be 1, got %u\n", count);
2488 }
2489 
2490 static void test_ReadConsoleOutputAttribute(HANDLE output_handle)
2491 {
2492     WORD attr;
2493     COORD origin = {0, 0};
2494     DWORD count;
2495     BOOL ret;
2496     int i;
2497 
2498     const struct
2499     {
2500         HANDLE hConsoleOutput;
2501         LPWORD lpAttribute;
2502         DWORD length;
2503         COORD coord;
2504         LPDWORD read_count;
2505         DWORD expected_count;
2506         DWORD last_error;
2507         int win7_crash;
2508     } invalid_table[] =
2509     {
2510         {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2511         {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2512         {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2513         {NULL, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
2514         {NULL, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2515         {NULL, &attr, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2516         {NULL, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2517         {NULL, &attr, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2518         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2519         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2520         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2521         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
2522         {INVALID_HANDLE_VALUE, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2523         {INVALID_HANDLE_VALUE, &attr, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2524         {INVALID_HANDLE_VALUE, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2525         {INVALID_HANDLE_VALUE, &attr, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2526         {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2527         {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2528         {output_handle, NULL, 1, {0, 0}, &count, 1, ERROR_INVALID_ACCESS, 1},
2529         {output_handle, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2530         {output_handle, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2531     };
2532 
2533     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
2534     {
2535         if (invalid_table[i].win7_crash)
2536             continue;
2537 
2538         SetLastError(0xdeadbeef);
2539         if (invalid_table[i].read_count) count = 0xdeadbeef;
2540         ret = ReadConsoleOutputAttribute(invalid_table[i].hConsoleOutput,
2541                                          invalid_table[i].lpAttribute,
2542                                          invalid_table[i].length,
2543                                          invalid_table[i].coord,
2544                                          invalid_table[i].read_count);
2545         ok(!ret, "[%d] Expected ReadConsoleOutputAttribute to return FALSE, got %d\n", i, ret);
2546         if (invalid_table[i].read_count)
2547         {
2548             ok(count == invalid_table[i].expected_count,
2549                "[%d] Expected count to be %u, got %u\n",
2550                i, invalid_table[i].expected_count, count);
2551         }
2552         ok(GetLastError() == invalid_table[i].last_error,
2553            "[%d] Expected last error to be %u, got %u\n",
2554            i, invalid_table[i].last_error, GetLastError());
2555     }
2556 
2557     count = 0xdeadbeef;
2558     ret = ReadConsoleOutputAttribute(output_handle, NULL, 0, origin, &count);
2559     ok(ret == TRUE, "Expected ReadConsoleOutputAttribute to return TRUE, got %d\n", ret);
2560     ok(count == 0, "Expected count to be 0, got %u\n", count);
2561 
2562     count = 0xdeadbeef;
2563     ret = ReadConsoleOutputAttribute(output_handle, &attr, 0, origin, &count);
2564     ok(ret == TRUE, "Expected ReadConsoleOutputAttribute to return TRUE, got %d\n", ret);
2565     ok(count == 0, "Expected count to be 0, got %u\n", count);
2566 
2567     count = 0xdeadbeef;
2568     ret = ReadConsoleOutputAttribute(output_handle, &attr, 1, origin, &count);
2569     ok(ret == TRUE, "Expected ReadConsoleOutputAttribute to return TRUE, got %d\n", ret);
2570     ok(count == 1, "Expected count to be 1, got %u\n", count);
2571 }
2572 
2573 static void test_ReadConsole(void)
2574 {
2575     HANDLE std_input;
2576     DWORD ret, bytes;
2577     char buf[1024];
2578 
2579     std_input = GetStdHandle(STD_INPUT_HANDLE);
2580 
2581     SetLastError(0xdeadbeef);
2582     ret = GetFileSize(std_input, NULL);
2583     ok(ret == INVALID_FILE_SIZE, "expected INVALID_FILE_SIZE, got %#x\n", ret);
2584     ok(GetLastError() == ERROR_INVALID_HANDLE ||
2585        GetLastError() == ERROR_INVALID_FUNCTION, /* Win 8, 10 */
2586        "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
2587 
2588     bytes = 0xdeadbeef;
2589     SetLastError(0xdeadbeef);
2590     ret = ReadFile(std_input, buf, -128, &bytes, NULL);
2591     ok(!ret, "expected 0, got %u\n", ret);
2592     ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
2593        GetLastError() == ERROR_NOACCESS, /* Win 8, 10 */
2594        "expected ERROR_NOT_ENOUGH_MEMORY, got %d\n", GetLastError());
2595     ok(!bytes, "expected 0, got %u\n", bytes);
2596 
2597     bytes = 0xdeadbeef;
2598     SetLastError(0xdeadbeef);
2599     ret = ReadConsoleA(std_input, buf, -128, &bytes, NULL);
2600     ok(!ret, "expected 0, got %u\n", ret);
2601     ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
2602        GetLastError() == ERROR_NOACCESS, /* Win 8, 10 */
2603        "expected ERROR_NOT_ENOUGH_MEMORY, got %d\n", GetLastError());
2604     ok(bytes == 0xdeadbeef, "expected 0xdeadbeef, got %#x\n", bytes);
2605 
2606     bytes = 0xdeadbeef;
2607     SetLastError(0xdeadbeef);
2608     ret = ReadConsoleW(std_input, buf, -128, &bytes, NULL);
2609     ok(!ret, "expected 0, got %u\n", ret);
2610     ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
2611        GetLastError() == ERROR_NOACCESS, /* Win 8, 10 */
2612        "expected ERROR_NOT_ENOUGH_MEMORY, got %d\n", GetLastError());
2613     ok(bytes == 0xdeadbeef, "expected 0xdeadbeef, got %#x\n", bytes);
2614 }
2615 
2616 static void test_GetCurrentConsoleFont(HANDLE std_output)
2617 {
2618     BOOL ret;
2619     CONSOLE_FONT_INFO cfi;
2620     CONSOLE_SCREEN_BUFFER_INFO csbi;
2621     short int width, height;
2622     COORD c;
2623 
2624     memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
2625     SetLastError(0xdeadbeef);
2626     ret = GetCurrentConsoleFont(NULL, FALSE, &cfi);
2627     ok(!ret, "got %d, expected 0\n", ret);
2628     ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2629     ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
2630     ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
2631 
2632     memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
2633     SetLastError(0xdeadbeef);
2634     ret = GetCurrentConsoleFont(NULL, TRUE, &cfi);
2635     ok(!ret, "got %d, expected 0\n", ret);
2636     ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2637     ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
2638     ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
2639 
2640     memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
2641     SetLastError(0xdeadbeef);
2642     ret = GetCurrentConsoleFont(GetStdHandle(STD_INPUT_HANDLE), FALSE, &cfi);
2643     ok(!ret, "got %d, expected 0\n", ret);
2644     ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2645     ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
2646     ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
2647 
2648     memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
2649     SetLastError(0xdeadbeef);
2650     ret = GetCurrentConsoleFont(GetStdHandle(STD_INPUT_HANDLE), TRUE, &cfi);
2651     ok(!ret, "got %d, expected 0\n", ret);
2652     ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2653     ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
2654     ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
2655 
2656     memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
2657     SetLastError(0xdeadbeef);
2658     ret = GetCurrentConsoleFont(std_output, FALSE, &cfi);
2659     ok(ret, "got %d, expected non-zero\n", ret);
2660     ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
2661     GetConsoleScreenBufferInfo(std_output, &csbi);
2662     width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
2663     height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
2664     c = GetConsoleFontSize(std_output, cfi.nFont);
2665     ok(cfi.dwFontSize.X == width || cfi.dwFontSize.X == c.X /* Vista and higher */,
2666         "got %d, expected %d\n", cfi.dwFontSize.X, width);
2667     ok(cfi.dwFontSize.Y == height || cfi.dwFontSize.Y == c.Y /* Vista and higher */,
2668         "got %d, expected %d\n", cfi.dwFontSize.Y, height);
2669 
2670     memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
2671     SetLastError(0xdeadbeef);
2672     ret = GetCurrentConsoleFont(std_output, TRUE, &cfi);
2673     ok(ret, "got %d, expected non-zero\n", ret);
2674     ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
2675     ok(cfi.dwFontSize.X == csbi.dwMaximumWindowSize.X,
2676        "got %d, expected %d\n", cfi.dwFontSize.X, csbi.dwMaximumWindowSize.X);
2677     ok(cfi.dwFontSize.Y == csbi.dwMaximumWindowSize.Y,
2678        "got %d, expected %d\n", cfi.dwFontSize.Y, csbi.dwMaximumWindowSize.Y);
2679 }
2680 
2681 static void test_GetConsoleFontSize(HANDLE std_output)
2682 {
2683     COORD c;
2684     DWORD index = 0;
2685     CONSOLE_FONT_INFO cfi;
2686     RECT r;
2687     CONSOLE_SCREEN_BUFFER_INFO csbi;
2688     LONG font_width, font_height;
2689     HMODULE hmod;
2690     DWORD (WINAPI *pGetNumberOfConsoleFonts)(void);
2691 
2692     memset(&c, 10, sizeof(COORD));
2693     SetLastError(0xdeadbeef);
2694     c = GetConsoleFontSize(NULL, index);
2695     ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2696     ok(!c.X, "got %d, expected 0\n", c.X);
2697     ok(!c.Y, "got %d, expected 0\n", c.Y);
2698 
2699     memset(&c, 10, sizeof(COORD));
2700     SetLastError(0xdeadbeef);
2701     c = GetConsoleFontSize(GetStdHandle(STD_INPUT_HANDLE), index);
2702     ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2703     ok(!c.X, "got %d, expected 0\n", c.X);
2704     ok(!c.Y, "got %d, expected 0\n", c.Y);
2705 
2706     GetCurrentConsoleFont(std_output, FALSE, &cfi);
2707     memset(&c, 10, sizeof(COORD));
2708     SetLastError(0xdeadbeef);
2709     c = GetConsoleFontSize(std_output, cfi.nFont);
2710     ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
2711     GetClientRect(GetConsoleWindow(), &r);
2712     GetConsoleScreenBufferInfo(std_output, &csbi);
2713     font_width = (r.right - r.left + 1) / csbi.srWindow.Right;
2714     font_height = (r.bottom - r.top + 1) / csbi.srWindow.Bottom;
2715     ok(c.X == font_width, "got %d, expected %d\n", c.X, font_width);
2716     ok(c.Y == font_height, "got %d, expected %d\n", c.Y, font_height);
2717 
2718     hmod = GetModuleHandleA("kernel32.dll");
2719     pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts");
2720     if (!pGetNumberOfConsoleFonts)
2721     {
2722         win_skip("GetNumberOfConsoleFonts is not available\n");
2723         return;
2724     }
2725     index = pGetNumberOfConsoleFonts();
2726 
2727     memset(&c, 10, sizeof(COORD));
2728     SetLastError(0xdeadbeef);
2729     c = GetConsoleFontSize(std_output, index);
2730     ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError());
2731     ok(!c.X, "got %d, expected 0\n", c.X);
2732     ok(!c.Y, "got %d, expected 0\n", c.Y);
2733 }
2734 
2735 static void test_GetLargestConsoleWindowSize(HANDLE std_output)
2736 {
2737     COORD c, font;
2738     RECT r;
2739     LONG workarea_w, workarea_h, maxcon_w, maxcon_h;
2740     CONSOLE_SCREEN_BUFFER_INFO sbi;
2741     CONSOLE_FONT_INFO cfi;
2742     DWORD index, i;
2743     HMODULE hmod;
2744     BOOL ret;
2745     DWORD (WINAPI *pGetNumberOfConsoleFonts)(void);
2746     BOOL (WINAPI *pSetConsoleFont)(HANDLE, DWORD);
2747 
2748     memset(&c, 10, sizeof(COORD));
2749     SetLastError(0xdeadbeef);
2750     c = GetLargestConsoleWindowSize(NULL);
2751     ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2752     ok(!c.X, "got %d, expected 0\n", c.X);
2753     ok(!c.Y, "got %d, expected 0\n", c.Y);
2754 
2755     memset(&c, 10, sizeof(COORD));
2756     SetLastError(0xdeadbeef);
2757     c = GetLargestConsoleWindowSize(GetStdHandle(STD_INPUT_HANDLE));
2758     ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2759     ok(!c.X, "got %d, expected 0\n", c.X);
2760     ok(!c.Y, "got %d, expected 0\n", c.Y);
2761 
2762     SystemParametersInfoW(SPI_GETWORKAREA, 0, &r, 0);
2763     workarea_w = r.right - r.left;
2764     workarea_h = r.bottom - r.top - GetSystemMetrics(SM_CYCAPTION);
2765 
2766     GetCurrentConsoleFont(std_output, FALSE, &cfi);
2767     index = cfi.nFont; /* save current font index */
2768 
2769     hmod = GetModuleHandleA("kernel32.dll");
2770     pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts");
2771     if (!pGetNumberOfConsoleFonts)
2772     {
2773         win_skip("GetNumberOfConsoleFonts is not available\n");
2774         return;
2775     }
2776     pSetConsoleFont = (void *)GetProcAddress(hmod, "SetConsoleFont");
2777     if (!pSetConsoleFont)
2778     {
2779         win_skip("SetConsoleFont is not available\n");
2780         return;
2781     }
2782 
2783     for (i = 0; i < pGetNumberOfConsoleFonts(); i++)
2784     {
2785         pSetConsoleFont(std_output, i);
2786         memset(&c, 10, sizeof(COORD));
2787         SetLastError(0xdeadbeef);
2788         c = GetLargestConsoleWindowSize(std_output);
2789         ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
2790         GetCurrentConsoleFont(std_output, FALSE, &cfi);
2791         font = GetConsoleFontSize(std_output, cfi.nFont);
2792         maxcon_w = workarea_w / font.X;
2793         maxcon_h = workarea_h / font.Y;
2794         ok(c.X == maxcon_w || c.X == maxcon_w - 1 /* Win10 */, "got %d, expected %d\n", c.X, maxcon_w);
2795         ok(c.Y == maxcon_h || c.Y == maxcon_h - 1 /* Win10 */, "got %d, expected %d\n", c.Y, maxcon_h);
2796 
2797         ret = GetConsoleScreenBufferInfo(std_output, &sbi);
2798         ok(ret, "GetConsoleScreenBufferInfo failed %u\n", GetLastError());
2799         ok(sbi.dwMaximumWindowSize.X == min(c.X, sbi.dwSize.X), "got %d, expected %d\n",
2800            sbi.dwMaximumWindowSize.X, min(c.X, sbi.dwSize.X));
2801         ok(sbi.dwMaximumWindowSize.Y == min(c.Y, sbi.dwSize.Y), "got %d, expected %d\n",
2802            sbi.dwMaximumWindowSize.Y, min(c.Y, sbi.dwSize.Y));
2803     }
2804     pSetConsoleFont(std_output, index); /* restore original font size */
2805 }
2806 
2807 static void test_GetConsoleFontInfo(HANDLE std_output)
2808 {
2809     HANDLE hmod;
2810     BOOL (WINAPI *pGetConsoleFontInfo)(HANDLE, BOOL, DWORD, CONSOLE_FONT_INFO *);
2811     DWORD (WINAPI *pGetNumberOfConsoleFonts)(void);
2812     DWORD num_fonts, index, i;
2813     int memsize, win_width, win_height, tmp_w, tmp_h;
2814     CONSOLE_FONT_INFO *cfi;
2815     BOOL ret;
2816     CONSOLE_SCREEN_BUFFER_INFO csbi;
2817     COORD orig_sb_size, tmp_sb_size, orig_font, tmp_font;
2818 
2819     hmod = GetModuleHandleA("kernel32.dll");
2820     pGetConsoleFontInfo = (void *)GetProcAddress(hmod, "GetConsoleFontInfo");
2821     if (!pGetConsoleFontInfo)
2822     {
2823         win_skip("GetConsoleFontInfo is not available\n");
2824         return;
2825     }
2826 
2827     pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts");
2828     if (!pGetNumberOfConsoleFonts)
2829     {
2830         win_skip("GetNumberOfConsoleFonts is not available\n");
2831         return;
2832     }
2833 
2834     num_fonts = pGetNumberOfConsoleFonts();
2835     memsize = num_fonts * sizeof(CONSOLE_FONT_INFO);
2836     cfi = HeapAlloc(GetProcessHeap(), 0, memsize);
2837     memset(cfi, 0, memsize);
2838 
2839     GetConsoleScreenBufferInfo(std_output, &csbi);
2840     orig_sb_size = csbi.dwSize;
2841     tmp_sb_size.X = csbi.dwSize.X + 3;
2842     tmp_sb_size.Y = csbi.dwSize.Y + 5;
2843     SetConsoleScreenBufferSize(std_output, tmp_sb_size);
2844 
2845     SetLastError(0xdeadbeef);
2846     ret = pGetConsoleFontInfo(NULL, FALSE, 0, cfi);
2847     ok(!ret, "got %d, expected zero\n", ret);
2848     todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2849 
2850     SetLastError(0xdeadbeef);
2851     ret = pGetConsoleFontInfo(GetStdHandle(STD_INPUT_HANDLE), FALSE, 0, cfi);
2852     ok(!ret, "got %d, expected zero\n", ret);
2853     todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2854 
2855     SetLastError(0xdeadbeef);
2856     ret = pGetConsoleFontInfo(std_output, FALSE, 0, cfi);
2857     ok(!ret, "got %d, expected zero\n", ret);
2858     todo_wine ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
2859 
2860     GetConsoleScreenBufferInfo(std_output, &csbi);
2861     win_width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
2862     win_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
2863 
2864     GetCurrentConsoleFont(std_output, FALSE, &cfi[0]);
2865     index = cfi[0].nFont;
2866     orig_font = GetConsoleFontSize(std_output, index);
2867 
2868     memset(cfi, 0, memsize);
2869     ret = pGetConsoleFontInfo(std_output, FALSE, num_fonts, cfi);
2870     todo_wine ok(ret, "got %d, expected non-zero\n", ret);
2871 
2872     todo_wine ok(cfi[index].dwFontSize.X == win_width, "got %d, expected %d\n",
2873                  cfi[index].dwFontSize.X, win_width);
2874     todo_wine ok(cfi[index].dwFontSize.Y == win_height, "got %d, expected %d\n",
2875                  cfi[index].dwFontSize.Y, win_height);
2876 
2877     for (i = 0; i < num_fonts; i++)
2878     {
2879         ok(cfi[i].nFont == i, "element out of order, got nFont %d, expected %d\n", cfi[i].nFont, i);
2880         tmp_font = GetConsoleFontSize(std_output, cfi[i].nFont);
2881         tmp_w = (double)orig_font.X / tmp_font.X * win_width;
2882         tmp_h = (double)orig_font.Y / tmp_font.Y * win_height;
2883         todo_wine ok(cfi[i].dwFontSize.X == tmp_w, "got %d, expected %d\n", cfi[i].dwFontSize.X, tmp_w);
2884         todo_wine ok(cfi[i].dwFontSize.Y == tmp_h, "got %d, expected %d\n", cfi[i].dwFontSize.Y, tmp_h);
2885     }
2886 
2887     SetLastError(0xdeadbeef);
2888     ret = pGetConsoleFontInfo(NULL, TRUE, 0, cfi);
2889     ok(!ret, "got %d, expected zero\n", ret);
2890     todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2891 
2892     SetLastError(0xdeadbeef);
2893     ret = pGetConsoleFontInfo(GetStdHandle(STD_INPUT_HANDLE), TRUE, 0, cfi);
2894     ok(!ret, "got %d, expected zero\n", ret);
2895     todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2896 
2897     SetLastError(0xdeadbeef);
2898     ret = pGetConsoleFontInfo(std_output, TRUE, 0, cfi);
2899     ok(!ret, "got %d, expected zero\n", ret);
2900     todo_wine ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
2901 
2902     memset(cfi, 0, memsize);
2903     ret = pGetConsoleFontInfo(std_output, TRUE, num_fonts, cfi);
2904     todo_wine ok(ret, "got %d, expected non-zero\n", ret);
2905 
2906     todo_wine ok(cfi[index].dwFontSize.X == csbi.dwMaximumWindowSize.X, "got %d, expected %d\n",
2907                  cfi[index].dwFontSize.X, csbi.dwMaximumWindowSize.X);
2908     todo_wine ok(cfi[index].dwFontSize.Y == csbi.dwMaximumWindowSize.Y, "got %d, expected %d\n",
2909                  cfi[index].dwFontSize.Y, csbi.dwMaximumWindowSize.Y);
2910 
2911     for (i = 0; i < num_fonts; i++)
2912     {
2913         ok(cfi[i].nFont == i, "element out of order, got nFont %d, expected %d\n", cfi[i].nFont, i);
2914         tmp_font = GetConsoleFontSize(std_output, cfi[i].nFont);
2915         tmp_w = (double)orig_font.X / tmp_font.X * csbi.dwMaximumWindowSize.X;
2916         tmp_h = (double)orig_font.Y / tmp_font.Y * csbi.dwMaximumWindowSize.Y;
2917         todo_wine ok(cfi[i].dwFontSize.X == tmp_w, "got %d, expected %d\n", cfi[i].dwFontSize.X, tmp_w);
2918         todo_wine ok(cfi[i].dwFontSize.Y == tmp_h, "got %d, expected %d\n", cfi[i].dwFontSize.Y, tmp_h);
2919      }
2920 
2921     HeapFree(GetProcessHeap(), 0, cfi);
2922     SetConsoleScreenBufferSize(std_output, orig_sb_size);
2923 }
2924 
2925 static void test_SetConsoleFont(HANDLE std_output)
2926 {
2927     HANDLE hmod;
2928     BOOL (WINAPI *pSetConsoleFont)(HANDLE, DWORD);
2929     BOOL ret;
2930     DWORD (WINAPI *pGetNumberOfConsoleFonts)(void);
2931     DWORD num_fonts;
2932 
2933     hmod = GetModuleHandleA("kernel32.dll");
2934     pSetConsoleFont = (void *)GetProcAddress(hmod, "SetConsoleFont");
2935     if (!pSetConsoleFont)
2936     {
2937         win_skip("SetConsoleFont is not available\n");
2938         return;
2939     }
2940 
2941     SetLastError(0xdeadbeef);
2942     ret = pSetConsoleFont(NULL, 0);
2943     ok(!ret, "got %d, expected zero\n", ret);
2944     todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2945 
2946     SetLastError(0xdeadbeef);
2947     ret = pSetConsoleFont(GetStdHandle(STD_INPUT_HANDLE), 0);
2948     ok(!ret, "got %d, expected zero\n", ret);
2949     todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2950 
2951     pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts");
2952     if (!pGetNumberOfConsoleFonts)
2953     {
2954         win_skip("GetNumberOfConsoleFonts is not available\n");
2955         return;
2956     }
2957 
2958     num_fonts = pGetNumberOfConsoleFonts();
2959 
2960     SetLastError(0xdeadbeef);
2961     ret = pSetConsoleFont(std_output, num_fonts);
2962     ok(!ret, "got %d, expected zero\n", ret);
2963     todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError());
2964 }
2965 
2966 static void test_GetConsoleScreenBufferInfoEx(HANDLE std_output)
2967 {
2968     HANDLE hmod;
2969     BOOL (WINAPI *pGetConsoleScreenBufferInfoEx)(HANDLE, CONSOLE_SCREEN_BUFFER_INFOEX *);
2970     CONSOLE_SCREEN_BUFFER_INFOEX csbix;
2971     BOOL ret;
2972     HANDLE std_input = GetStdHandle(STD_INPUT_HANDLE);
2973 
2974     hmod = GetModuleHandleA("kernel32.dll");
2975     pGetConsoleScreenBufferInfoEx = (void *)GetProcAddress(hmod, "GetConsoleScreenBufferInfoEx");
2976     if (!pGetConsoleScreenBufferInfoEx)
2977     {
2978         win_skip("GetConsoleScreenBufferInfoEx is not available\n");
2979         return;
2980     }
2981 
2982     SetLastError(0xdeadbeef);
2983     ret = pGetConsoleScreenBufferInfoEx(NULL, &csbix);
2984     ok(!ret, "got %d, expected zero\n", ret);
2985     ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError());
2986 
2987     SetLastError(0xdeadbeef);
2988     ret = pGetConsoleScreenBufferInfoEx(std_input, &csbix);
2989     ok(!ret, "got %d, expected zero\n", ret);
2990     ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError());
2991 
2992     SetLastError(0xdeadbeef);
2993     ret = pGetConsoleScreenBufferInfoEx(std_output, &csbix);
2994     ok(!ret, "got %d, expected zero\n", ret);
2995     ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError());
2996 
2997     csbix.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
2998 
2999     SetLastError(0xdeadbeef);
3000     ret = pGetConsoleScreenBufferInfoEx(NULL, &csbix);
3001     ok(!ret, "got %d, expected zero\n", ret);
3002     ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3003 
3004     SetLastError(0xdeadbeef);
3005     ret = pGetConsoleScreenBufferInfoEx(std_input, &csbix);
3006     ok(!ret, "got %d, expected zero\n", ret);
3007     ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3008 
3009     SetLastError(0xdeadbeef);
3010     ret = pGetConsoleScreenBufferInfoEx(std_output, &csbix);
3011     ok(ret, "got %d, expected non-zero\n", ret);
3012     ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
3013 }
3014 
3015 START_TEST(console)
3016 {
3017     static const char font_name[] = "Lucida Console";
3018     HANDLE hConIn, hConOut;
3019     BOOL ret;
3020     CONSOLE_SCREEN_BUFFER_INFO	sbi;
3021     LONG err;
3022     HKEY console_key;
3023     char old_font[LF_FACESIZE];
3024     BOOL delete = FALSE;
3025     DWORD size;
3026 
3027     init_function_pointers();
3028 
3029     /* be sure we have a clean console (and that's our own)
3030      * FIXME: this will make the test fail (currently) if we don't run
3031      * under X11
3032      * Another solution would be to rerun the test under wineconsole with
3033      * the curses backend
3034      */
3035 
3036     /* ReadConsoleOutputW doesn't retrieve characters from the output buffer
3037      * correctly for characters that don't have a glyph in the console font. So,
3038      * we first set the console font to Lucida Console (which has a wider
3039      * selection of glyphs available than the default raster fonts). We want
3040      * to be able to restore the original font afterwards, so don't change
3041      * if we can't read the original font.
3042      */
3043     err = RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
3044                         KEY_QUERY_VALUE | KEY_SET_VALUE, &console_key);
3045     if (err == ERROR_SUCCESS)
3046     {
3047         size = sizeof(old_font);
3048         err = RegQueryValueExA(console_key, "FaceName", NULL, NULL,
3049                                (LPBYTE) old_font, &size);
3050         if (err == ERROR_SUCCESS || err == ERROR_FILE_NOT_FOUND)
3051         {
3052             delete = (err == ERROR_FILE_NOT_FOUND);
3053             err = RegSetValueExA(console_key, "FaceName", 0, REG_SZ,
3054                                  (const BYTE *) font_name, sizeof(font_name));
3055             if (err != ERROR_SUCCESS)
3056                 trace("Unable to change default console font, error %d\n", err);
3057         }
3058         else
3059         {
3060             trace("Unable to query default console font, error %d\n", err);
3061             RegCloseKey(console_key);
3062             console_key = NULL;
3063         }
3064     }
3065     else
3066     {
3067         trace("Unable to open HKCU\\Console, error %d\n", err);
3068         console_key = NULL;
3069     }
3070 
3071     /* Now detach and open a fresh console to play with */
3072     FreeConsole();
3073     ok(AllocConsole(), "Couldn't alloc console\n");
3074 
3075     /* Restore default console font if needed */
3076     if (console_key != NULL)
3077     {
3078         if (delete)
3079             err = RegDeleteValueA(console_key, "FaceName");
3080         else
3081             err = RegSetValueExA(console_key, "FaceName", 0, REG_SZ,
3082                                  (const BYTE *) old_font, strlen(old_font) + 1);
3083         ok(err == ERROR_SUCCESS, "Unable to restore default console font, error %d\n", err);
3084     }
3085     hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
3086     hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
3087 
3088     /* now verify everything's ok */
3089     ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n");
3090     ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n");
3091 
3092     ret = GetConsoleScreenBufferInfo(hConOut, &sbi);
3093     ok(ret, "Getting sb info\n");
3094     if (!ret) return;
3095 
3096     /* Reduce the size of the buffer to the visible area plus 3 lines to speed
3097      * up the tests.
3098      */
3099     trace("Visible area: %dx%d - %dx%d Buffer size: %dx%d\n", sbi.srWindow.Left, sbi.srWindow.Top, sbi.srWindow.Right, sbi.srWindow.Bottom, sbi.dwSize.X, sbi.dwSize.Y);
3100     sbi.dwSize.Y = size = (sbi.srWindow.Bottom + 1) + 3;
3101     ret = SetConsoleScreenBufferSize(hConOut, sbi.dwSize);
3102     ok(ret, "Setting sb info\n");
3103     ret = GetConsoleScreenBufferInfo(hConOut, &sbi);
3104     ok(ret, "Getting sb info\n");
3105     ok(sbi.dwSize.Y == size, "Unexpected buffer size: %d instead of %d\n", sbi.dwSize.Y, size);
3106     if (!ret) return;
3107 
3108     test_ReadConsole();
3109     /* Non interactive tests */
3110     testCursor(hConOut, sbi.dwSize);
3111     /* test parameters (FIXME: test functionality) */
3112     testCursorInfo(hConOut);
3113     /* will test wrapped (on/off) & processed (on/off) strings output */
3114     testWrite(hConOut, sbi.dwSize);
3115     /* will test line scrolling at the bottom of the screen */
3116     /* testBottomScroll(); */
3117     /* will test all the scrolling operations */
3118     testScroll(hConOut, sbi.dwSize);
3119     /* will test sb creation / modification / codepage handling */
3120     testScreenBuffer(hConOut);
3121     /* Test waiting for a console handle */
3122     testWaitForConsoleInput(hConIn);
3123 
3124     /* clear duplicated console font table */
3125     CloseHandle(hConIn);
3126     CloseHandle(hConOut);
3127     FreeConsole();
3128     ok(AllocConsole(), "Couldn't alloc console\n");
3129     hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
3130     hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
3131     ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n");
3132     ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n");
3133 
3134     testCtrlHandler();
3135     /* still to be done: access rights & access on objects */
3136 
3137     if (!pGetConsoleInputExeNameA || !pSetConsoleInputExeNameA)
3138         win_skip("GetConsoleInputExeNameA and/or SetConsoleInputExeNameA is not available\n");
3139     else
3140         test_GetSetConsoleInputExeName();
3141 
3142     test_GetConsoleProcessList();
3143     test_OpenConsoleW();
3144     test_CreateFileW();
3145     test_OpenCON();
3146     test_VerifyConsoleIoHandle(hConOut);
3147     test_GetSetStdHandle();
3148     test_GetNumberOfConsoleInputEvents(hConIn);
3149     test_WriteConsoleInputA(hConIn);
3150     test_WriteConsoleInputW(hConIn);
3151     test_WriteConsoleOutputCharacterA(hConOut);
3152     test_WriteConsoleOutputCharacterW(hConOut);
3153     test_WriteConsoleOutputAttribute(hConOut);
3154     test_FillConsoleOutputCharacterA(hConOut);
3155     test_FillConsoleOutputCharacterW(hConOut);
3156     test_FillConsoleOutputAttribute(hConOut);
3157     test_ReadConsoleOutputCharacterA(hConOut);
3158     test_ReadConsoleOutputCharacterW(hConOut);
3159     test_ReadConsoleOutputAttribute(hConOut);
3160     test_GetCurrentConsoleFont(hConOut);
3161     test_GetConsoleFontSize(hConOut);
3162     test_GetLargestConsoleWindowSize(hConOut);
3163     test_GetConsoleFontInfo(hConOut);
3164     test_SetConsoleFont(hConOut);
3165     test_GetConsoleScreenBufferInfoEx(hConOut);
3166 }
3167