1 /*
2  * Unit tests for console API
3  *
4  * Copyright (c) 2003,2004 Eric Pouech
5  * Copyright (c) 2007 Kirill K. Smirnov
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include "wine/test.h"
23 #include <windows.h>
24 #include <stdio.h>
25 
26 static BOOL (WINAPI *pGetConsoleInputExeNameA)(DWORD, LPSTR);
27 static DWORD (WINAPI *pGetConsoleProcessList)(LPDWORD, DWORD);
28 static HANDLE (WINAPI *pOpenConsoleW)(LPCWSTR,DWORD,BOOL,DWORD);
29 static BOOL (WINAPI *pSetConsoleInputExeNameA)(LPCSTR);
30 static BOOL (WINAPI *pVerifyConsoleIoHandle)(HANDLE handle);
31 
32 /* DEFAULT_ATTRIB is used for all initial filling of the console.
33  * all modifications are made with TEST_ATTRIB so that we could check
34  * what has to be modified or not
35  */
36 #define TEST_ATTRIB    (BACKGROUND_BLUE | FOREGROUND_GREEN)
37 #define DEFAULT_ATTRIB (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED)
38 /* when filling the screen with non-blank chars, this macro defines
39  * what character should be at position 'c'
40  */
41 #define CONTENT(c)    ('A' + (((c).Y * 17 + (c).X) % 23))
42 
43 #define	okCURSOR(hCon, c) do { \
44   CONSOLE_SCREEN_BUFFER_INFO __sbi; \
45   BOOL expect = GetConsoleScreenBufferInfo((hCon), &__sbi) && \
46                 __sbi.dwCursorPosition.X == (c).X && __sbi.dwCursorPosition.Y == (c).Y; \
47   ok(expect, "Expected cursor at (%d,%d), got (%d,%d)\n", \
48      (c).X, (c).Y, __sbi.dwCursorPosition.X, __sbi.dwCursorPosition.Y); \
49 } while (0)
50 
51 #define okCHAR(hCon, c, ch, attr) do { \
52   char __ch; WORD __attr; DWORD __len; BOOL expect; \
53   expect = ReadConsoleOutputCharacterA((hCon), &__ch, 1, (c), &__len) == 1 && __len == 1 && __ch == (ch); \
54   ok(expect, "At (%d,%d): expecting char '%c'/%02x got '%c'/%02x\n", (c).X, (c).Y, (ch), (ch), __ch, __ch); \
55   expect = ReadConsoleOutputAttribute((hCon), &__attr, 1, (c), &__len) == 1 && __len == 1 && __attr == (attr); \
56   ok(expect, "At (%d,%d): expecting attr %04x got %04x\n", (c).X, (c).Y, (attr), __attr); \
57 } while (0)
58 
init_function_pointers(void)59 static void init_function_pointers(void)
60 {
61     HMODULE hKernel32;
62 
63 #define KERNEL32_GET_PROC(func)                                     \
64     p##func = (void *)GetProcAddress(hKernel32, #func);             \
65     if(!p##func) trace("GetProcAddress(hKernel32, '%s') failed\n", #func);
66 
67     hKernel32 = GetModuleHandleA("kernel32.dll");
68     KERNEL32_GET_PROC(GetConsoleInputExeNameA);
69     KERNEL32_GET_PROC(GetConsoleProcessList);
70     KERNEL32_GET_PROC(OpenConsoleW);
71     KERNEL32_GET_PROC(SetConsoleInputExeNameA);
72     KERNEL32_GET_PROC(VerifyConsoleIoHandle);
73 
74 #undef KERNEL32_GET_PROC
75 }
76 
77 /* FIXME: this could be optimized on a speed point of view */
resetContent(HANDLE hCon,COORD sbSize,BOOL content)78 static void resetContent(HANDLE hCon, COORD sbSize, BOOL content)
79 {
80     COORD       c;
81     WORD        attr = DEFAULT_ATTRIB;
82     char        ch;
83     DWORD       len;
84 
85     for (c.X = 0; c.X < sbSize.X; c.X++)
86     {
87         for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
88         {
89             ch = (content) ? CONTENT(c) : ' ';
90             WriteConsoleOutputAttribute(hCon, &attr, 1, c, &len);
91             WriteConsoleOutputCharacterA(hCon, &ch, 1, c, &len);
92         }
93     }
94 }
95 
testCursor(HANDLE hCon,COORD sbSize)96 static void testCursor(HANDLE hCon, COORD sbSize)
97 {
98     COORD		c;
99 
100     c.X = c.Y = 0;
101     ok(SetConsoleCursorPosition(0, c) == 0, "No handle\n");
102     ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n",
103        ERROR_INVALID_HANDLE, GetLastError());
104 
105     c.X = c.Y = 0;
106     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
107     okCURSOR(hCon, c);
108 
109     c.X = sbSize.X - 1;
110     c.Y = sbSize.Y - 1;
111     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in lower-right\n");
112     okCURSOR(hCon, c);
113 
114     c.X = sbSize.X;
115     c.Y = sbSize.Y - 1;
116     ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
117     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n",
118        ERROR_INVALID_PARAMETER, GetLastError());
119 
120     c.X = sbSize.X - 1;
121     c.Y = sbSize.Y;
122     ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
123     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n",
124        ERROR_INVALID_PARAMETER, GetLastError());
125 
126     c.X = -1;
127     c.Y = 0;
128     ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
129     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n",
130        ERROR_INVALID_PARAMETER, GetLastError());
131 
132     c.X = 0;
133     c.Y = -1;
134     ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
135     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n",
136        ERROR_INVALID_PARAMETER, GetLastError());
137 }
138 
testCursorInfo(HANDLE hCon)139 static void testCursorInfo(HANDLE hCon)
140 {
141     BOOL ret;
142     CONSOLE_CURSOR_INFO info;
143 
144     SetLastError(0xdeadbeef);
145     ret = GetConsoleCursorInfo(NULL, NULL);
146     ok(!ret, "Expected failure\n");
147     ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n",
148        ERROR_INVALID_HANDLE, GetLastError());
149 
150     SetLastError(0xdeadbeef);
151     info.dwSize = -1;
152     ret = GetConsoleCursorInfo(NULL, &info);
153     ok(!ret, "Expected failure\n");
154     ok(info.dwSize == -1, "Expected no change for dwSize\n");
155     ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n",
156        ERROR_INVALID_HANDLE, GetLastError());
157 
158     /* Test the correct call first to distinguish between win9x and the rest */
159     SetLastError(0xdeadbeef);
160     ret = GetConsoleCursorInfo(hCon, &info);
161     ok(ret, "Expected success\n");
162     ok(info.dwSize == 25 ||
163        info.dwSize == 12 /* win9x */,
164        "Expected 12 or 25, got %d\n", info.dwSize);
165     ok(info.bVisible, "Expected the cursor to be visible\n");
166     ok(GetLastError() == 0xdeadbeef, "GetLastError: expecting %u got %u\n",
167        0xdeadbeef, GetLastError());
168 
169     /* Don't test NULL CONSOLE_CURSOR_INFO, it crashes on win9x and win7 */
170 }
171 
testEmptyWrite(HANDLE hCon)172 static void testEmptyWrite(HANDLE hCon)
173 {
174     static const char	emptybuf[16];
175     COORD		c;
176     DWORD		len;
177 
178     c.X = c.Y = 0;
179     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
180 
181     len = -1;
182     ok(WriteConsoleA(hCon, NULL, 0, &len, NULL) != 0 && len == 0, "WriteConsole\n");
183     okCURSOR(hCon, c);
184 
185     /* Passing a NULL lpBuffer with sufficiently large non-zero length succeeds
186      * on native Windows and result in memory-like contents being written to
187      * the console. Calling WriteConsoleW like this will crash on Wine. */
188     if (0)
189     {
190         len = -1;
191         ok(!WriteConsoleA(hCon, NULL, 16, &len, NULL) && len == -1, "WriteConsole\n");
192         okCURSOR(hCon, c);
193 
194         /* Cursor advances for this call. */
195         len = -1;
196         ok(WriteConsoleA(hCon, NULL, 128, &len, NULL) != 0 && len == 128, "WriteConsole\n");
197     }
198 
199     len = -1;
200     ok(WriteConsoleA(hCon, emptybuf, 0, &len, NULL) != 0 && len == 0, "WriteConsole\n");
201     okCURSOR(hCon, c);
202 
203     /* WriteConsole does not halt on a null terminator and is happy to write
204      * memory contents beyond the actual size of the buffer. */
205     len = -1;
206     ok(WriteConsoleA(hCon, emptybuf, 16, &len, NULL) != 0 && len == 16, "WriteConsole\n");
207     c.X += 16;
208     okCURSOR(hCon, c);
209 }
210 
testWriteSimple(HANDLE hCon)211 static void testWriteSimple(HANDLE hCon)
212 {
213     COORD		c;
214     DWORD		len;
215     const char*		mytest = "abcdefg";
216     const int	mylen = strlen(mytest);
217 
218     /* single line write */
219     c.X = c.Y = 0;
220     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
221 
222     ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
223     c.Y = 0;
224     for (c.X = 0; c.X < mylen; c.X++)
225     {
226         okCHAR(hCon, c, mytest[c.X], TEST_ATTRIB);
227     }
228 
229     okCURSOR(hCon, c);
230     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
231 }
232 
testWriteNotWrappedNotProcessed(HANDLE hCon,COORD sbSize)233 static void testWriteNotWrappedNotProcessed(HANDLE hCon, COORD sbSize)
234 {
235     COORD		c;
236     DWORD		len, mode;
237     const char*         mytest = "123";
238     const int           mylen = strlen(mytest);
239     int                 ret;
240     int			p;
241 
242     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode & ~(ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT)),
243        "clearing wrap at EOL & processed output\n");
244 
245     /* write line, wrapping disabled, buffer exceeds sb width */
246     c.X = sbSize.X - 3; c.Y = 0;
247     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
248 
249     ret = WriteConsoleA(hCon, mytest, mylen, &len, NULL);
250     ok(ret != 0 && len == mylen, "Couldn't write, ret = %d, len = %d\n", ret, len);
251     c.Y = 0;
252     for (p = mylen - 3; p < mylen; p++)
253     {
254         c.X = sbSize.X - 3 + p % 3;
255         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
256     }
257 
258     c.X = 0; c.Y = 1;
259     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
260 
261     p = sbSize.X - 3 + mylen % 3;
262     c.X = p; c.Y = 0;
263 
264     /* write line, wrapping disabled, strings end on end of line */
265     c.X = sbSize.X - mylen; c.Y = 0;
266     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
267 
268     ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
269 }
270 
testWriteNotWrappedProcessed(HANDLE hCon,COORD sbSize)271 static void testWriteNotWrappedProcessed(HANDLE hCon, COORD sbSize)
272 {
273     COORD		c;
274     DWORD		len, mode;
275     const char*		mytest = "abcd\nf\tg";
276     const int	mylen = strlen(mytest);
277     const int	mylen2 = strchr(mytest, '\n') - mytest;
278     int			p;
279     WORD                attr;
280 
281     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, (mode | ENABLE_PROCESSED_OUTPUT) & ~ENABLE_WRAP_AT_EOL_OUTPUT),
282        "clearing wrap at EOL & setting processed output\n");
283 
284     /* write line, wrapping disabled, buffer exceeds sb width */
285     c.X = sbSize.X - 5; c.Y = 0;
286     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-5\n");
287 
288     ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
289     c.Y = 0;
290     for (c.X = sbSize.X - 5; c.X < sbSize.X - 1; c.X++)
291     {
292         okCHAR(hCon, c, mytest[c.X - sbSize.X + 5], TEST_ATTRIB);
293     }
294 
295     ReadConsoleOutputAttribute(hCon, &attr, 1, c, &len);
296     /* Win9x and WinMe change the attribs for '\n' up to 'f' */
297     if (attr == TEST_ATTRIB)
298     {
299         win_skip("Win9x/WinMe don't respect ~ENABLE_WRAP_AT_EOL_OUTPUT\n");
300         return;
301     }
302 
303     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
304 
305     c.X = 0; c.Y++;
306     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
307     for (c.X = 1; c.X < 8; c.X++)
308         okCHAR(hCon, c, ' ', TEST_ATTRIB);
309     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
310     c.X++;
311     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
312 
313     okCURSOR(hCon, c);
314 
315     /* write line, wrapping disabled, strings end on end of line */
316     c.X = sbSize.X - 4; c.Y = 0;
317     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-4\n");
318 
319     ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
320     c.Y = 0;
321     for (c.X = sbSize.X - 4; c.X < sbSize.X; c.X++)
322     {
323         okCHAR(hCon, c, mytest[c.X - sbSize.X + 4], TEST_ATTRIB);
324     }
325     c.X = 0; c.Y++;
326     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
327     for (c.X = 1; c.X < 8; c.X++)
328         okCHAR(hCon, c, ' ', TEST_ATTRIB);
329     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
330     c.X++;
331     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
332 
333     okCURSOR(hCon, c);
334 
335     /* write line, wrapping disabled, strings end after end of line */
336     c.X = sbSize.X - 3; c.Y = 0;
337     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-4\n");
338 
339     ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
340     c.Y = 0;
341     for (p = mylen2 - 3; p < mylen2; p++)
342     {
343         c.X = sbSize.X - 3 + p % 3;
344         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
345     }
346     c.X = 0; c.Y = 1;
347     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
348     for (c.X = 1; c.X < 8; c.X++)
349         okCHAR(hCon, c, ' ', TEST_ATTRIB);
350     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
351     c.X++;
352     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
353 
354     okCURSOR(hCon, c);
355 }
356 
testWriteWrappedNotProcessed(HANDLE hCon,COORD sbSize)357 static void testWriteWrappedNotProcessed(HANDLE hCon, COORD sbSize)
358 {
359     COORD		c;
360     DWORD		len, mode;
361     const char*		mytest = "abcd\nf\tg";
362     const int	mylen = strlen(mytest);
363     int			p;
364 
365     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon,(mode | ENABLE_WRAP_AT_EOL_OUTPUT) & ~(ENABLE_PROCESSED_OUTPUT)),
366        "setting wrap at EOL & clearing processed output\n");
367 
368     /* write line, wrapping enabled, buffer doesn't exceed sb width */
369     c.X = sbSize.X - 9; c.Y = 0;
370     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-9\n");
371 
372     ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
373     c.Y = 0;
374     for (p = 0; p < mylen; p++)
375     {
376         c.X = sbSize.X - 9 + p;
377         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
378     }
379     c.X = sbSize.X - 9 + mylen;
380     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
381     c.X = 0; c.Y = 1;
382     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
383 
384     /* write line, wrapping enabled, buffer does exceed sb width */
385     c.X = sbSize.X - 3; c.Y = 0;
386     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
387 
388     c.Y = 1;
389     c.X = mylen - 3;
390     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
391 }
392 
testWriteWrappedProcessed(HANDLE hCon,COORD sbSize)393 static void testWriteWrappedProcessed(HANDLE hCon, COORD sbSize)
394 {
395     COORD		c;
396     DWORD		len, mode;
397     const char*		mytest = "abcd\nf\tg";
398     const int	mylen = strlen(mytest);
399     int			p;
400     WORD                attr;
401 
402     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode | (ENABLE_WRAP_AT_EOL_OUTPUT|ENABLE_PROCESSED_OUTPUT)),
403        "setting wrap at EOL & processed output\n");
404 
405     /* write line, wrapping enabled, buffer doesn't exceed sb width */
406     c.X = sbSize.X - 9; c.Y = 0;
407     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-9\n");
408 
409     ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
410     for (p = 0; p < 4; p++)
411     {
412         c.X = sbSize.X - 9 + p;
413         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
414     }
415     c.X = sbSize.X - 9 + p;
416     ReadConsoleOutputAttribute(hCon, &attr, 1, c, &len);
417     if (attr == TEST_ATTRIB)
418         win_skip("Win9x/WinMe changes attribs for '\\n' up to 'f'\n");
419     else
420         okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
421     c.X = 0; c.Y++;
422     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
423     for (c.X = 1; c.X < 8; c.X++)
424         okCHAR(hCon, c, ' ', TEST_ATTRIB);
425     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
426     c.X++;
427     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
428     okCURSOR(hCon, c);
429 
430     /* write line, wrapping enabled, buffer does exceed sb width */
431     c.X = sbSize.X - 3; c.Y = 2;
432     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
433 
434     ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
435     for (p = 0; p < 3; p++)
436     {
437         c.X = sbSize.X - 3 + p;
438         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
439     }
440     c.X = 0; c.Y++;
441     okCHAR(hCon, c, mytest[3], TEST_ATTRIB);
442     c.X++;
443     ReadConsoleOutputAttribute(hCon, &attr, 1, c, &len);
444     if (attr == TEST_ATTRIB)
445         win_skip("Win9x/WinMe changes attribs for '\\n' up to 'f'\n");
446     else
447         okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
448 
449     c.X = 0; c.Y++;
450     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
451     for (c.X = 1; c.X < 8; c.X++)
452         okCHAR(hCon, c, ' ', TEST_ATTRIB);
453     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
454     c.X++;
455     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
456     okCURSOR(hCon, c);
457 }
458 
testWrite(HANDLE hCon,COORD sbSize)459 static void testWrite(HANDLE hCon, COORD sbSize)
460 {
461     /* FIXME: should in fact ensure that the sb is at least 10 characters wide */
462     ok(SetConsoleTextAttribute(hCon, TEST_ATTRIB), "Setting default text color\n");
463     resetContent(hCon, sbSize, FALSE);
464     testEmptyWrite(hCon);
465     resetContent(hCon, sbSize, FALSE);
466     testWriteSimple(hCon);
467     resetContent(hCon, sbSize, FALSE);
468     testWriteNotWrappedNotProcessed(hCon, sbSize);
469     resetContent(hCon, sbSize, FALSE);
470     testWriteNotWrappedProcessed(hCon, sbSize);
471     resetContent(hCon, sbSize, FALSE);
472     testWriteWrappedNotProcessed(hCon, sbSize);
473     resetContent(hCon, sbSize, FALSE);
474     testWriteWrappedProcessed(hCon, sbSize);
475 }
476 
testScroll(HANDLE hCon,COORD sbSize)477 static void testScroll(HANDLE hCon, COORD sbSize)
478 {
479     SMALL_RECT  scroll, clip;
480     COORD       dst, c, tc;
481     CHAR_INFO   ci;
482     BOOL ret;
483 
484 #define W 11
485 #define H 7
486 
487 #define IN_SRECT(r,c) ((r).Left <= (c).X && (c).X <= (r).Right && (r).Top <= (c).Y && (c).Y <= (r).Bottom)
488 #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)
489 
490     /* no clipping, src & dst rect don't overlap */
491     resetContent(hCon, sbSize, TRUE);
492 
493     scroll.Left = 0;
494     scroll.Right = W - 1;
495     scroll.Top = 0;
496     scroll.Bottom = H - 1;
497     dst.X = W + 3;
498     dst.Y = H + 3;
499     ci.Char.UnicodeChar = '#';
500     ci.Attributes = TEST_ATTRIB;
501 
502     clip.Left = 0;
503     clip.Right = sbSize.X - 1;
504     clip.Top = 0;
505     clip.Bottom = sbSize.Y - 1;
506 
507     ok(ScrollConsoleScreenBufferA(hCon, &scroll, NULL, dst, &ci), "Scrolling SB\n");
508 
509     for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
510     {
511         for (c.X = 0; c.X < sbSize.X; c.X++)
512         {
513             if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
514             {
515                 tc.X = c.X - dst.X;
516                 tc.Y = c.Y - dst.Y;
517                 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
518             }
519             else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
520                 okCHAR(hCon, c, '#', TEST_ATTRIB);
521             else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
522         }
523     }
524 
525     /* no clipping, src & dst rect do overlap */
526     resetContent(hCon, sbSize, TRUE);
527 
528     scroll.Left = 0;
529     scroll.Right = W - 1;
530     scroll.Top = 0;
531     scroll.Bottom = H - 1;
532     dst.X = W /2;
533     dst.Y = H / 2;
534     ci.Char.UnicodeChar = '#';
535     ci.Attributes = TEST_ATTRIB;
536 
537     clip.Left = 0;
538     clip.Right = sbSize.X - 1;
539     clip.Top = 0;
540     clip.Bottom = sbSize.Y - 1;
541 
542     ok(ScrollConsoleScreenBufferA(hCon, &scroll, NULL, dst, &ci), "Scrolling SB\n");
543 
544     for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
545     {
546         for (c.X = 0; c.X < sbSize.X; c.X++)
547         {
548             if (dst.X <= c.X && c.X < dst.X + W && dst.Y <= c.Y && c.Y < dst.Y + H)
549             {
550                 tc.X = c.X - dst.X;
551                 tc.Y = c.Y - dst.Y;
552                 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
553             }
554             else if (c.X < W && c.Y < H) okCHAR(hCon, c, '#', TEST_ATTRIB);
555             else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
556         }
557     }
558 
559     /* clipping, src & dst rect don't overlap */
560     resetContent(hCon, sbSize, TRUE);
561 
562     scroll.Left = 0;
563     scroll.Right = W - 1;
564     scroll.Top = 0;
565     scroll.Bottom = H - 1;
566     dst.X = W + 3;
567     dst.Y = H + 3;
568     ci.Char.UnicodeChar = '#';
569     ci.Attributes = TEST_ATTRIB;
570 
571     clip.Left = W / 2;
572     clip.Right = min(W + W / 2, sbSize.X - 1);
573     clip.Top = H / 2;
574     clip.Bottom = min(H + H / 2, sbSize.Y - 1);
575 
576     SetLastError(0xdeadbeef);
577     ret = ScrollConsoleScreenBufferA(hCon, &scroll, &clip, dst, &ci);
578     if (ret)
579     {
580         for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
581         {
582             for (c.X = 0; c.X < sbSize.X; c.X++)
583             {
584                 if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
585                 {
586                     tc.X = c.X - dst.X;
587                     tc.Y = c.Y - dst.Y;
588                     okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
589                 }
590                 else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
591                     okCHAR(hCon, c, '#', TEST_ATTRIB);
592                 else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
593             }
594         }
595     }
596     else
597     {
598         /* Win9x will fail, Only accept ERROR_NOT_ENOUGH_MEMORY */
599         ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY,
600             "Expected ERROR_NOT_ENOUGH_MEMORY, got %u\n", GetLastError());
601     }
602 
603     /* clipping, src & dst rect do overlap */
604     resetContent(hCon, sbSize, TRUE);
605 
606     scroll.Left = 0;
607     scroll.Right = W - 1;
608     scroll.Top = 0;
609     scroll.Bottom = H - 1;
610     dst.X = W / 2 - 3;
611     dst.Y = H / 2 - 3;
612     ci.Char.UnicodeChar = '#';
613     ci.Attributes = TEST_ATTRIB;
614 
615     clip.Left = W / 2;
616     clip.Right = min(W + W / 2, sbSize.X - 1);
617     clip.Top = H / 2;
618     clip.Bottom = min(H + H / 2, sbSize.Y - 1);
619 
620     ok(ScrollConsoleScreenBufferA(hCon, &scroll, &clip, dst, &ci), "Scrolling SB\n");
621 
622     for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
623     {
624         for (c.X = 0; c.X < sbSize.X; c.X++)
625         {
626             if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
627             {
628                 tc.X = c.X - dst.X;
629                 tc.Y = c.Y - dst.Y;
630                 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
631             }
632             else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
633                 okCHAR(hCon, c, '#', TEST_ATTRIB);
634             else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
635         }
636     }
637 }
638 
639 static int mch_count;
640 /* we need the event as Wine console event generation isn't synchronous
641  * (ie GenerateConsoleCtrlEvent returns before all ctrl-handlers in all
642  * processes have been called).
643  */
644 static HANDLE mch_event;
mch(DWORD event)645 static BOOL WINAPI mch(DWORD event)
646 {
647     mch_count++;
648     SetEvent(mch_event);
649     return TRUE;
650 }
651 
testCtrlHandler(void)652 static void testCtrlHandler(void)
653 {
654     ok(!SetConsoleCtrlHandler(mch, FALSE), "Shouldn't succeed\n");
655     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %u\n", GetLastError());
656     ok(SetConsoleCtrlHandler(mch, TRUE), "Couldn't set handler\n");
657     /* wine requires the event for the test, as we cannot ensure, so far, that
658      * events are processed synchronously in GenerateConsoleCtrlEvent()
659      */
660     mch_event = CreateEventA(NULL, TRUE, FALSE, NULL);
661     mch_count = 0;
662     ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n");
663     /* FIXME: it isn't synchronous on wine but it can still happen before we test */
664     if (0) ok(mch_count == 1, "Event isn't synchronous\n");
665     ok(WaitForSingleObject(mch_event, 3000) == WAIT_OBJECT_0, "event sending didn't work\n");
666     CloseHandle(mch_event);
667 
668     /* Turning off ctrl-c handling doesn't work on win9x such way ... */
669     ok(SetConsoleCtrlHandler(NULL, TRUE), "Couldn't turn off ctrl-c handling\n");
670     mch_event = CreateEventA(NULL, TRUE, FALSE, NULL);
671     mch_count = 0;
672     if(!(GetVersion() & 0x80000000))
673         /* ... and next line leads to an unhandled exception on 9x.  Avoid it on 9x. */
674         ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n");
675     ok(WaitForSingleObject(mch_event, 3000) == WAIT_TIMEOUT && mch_count == 0, "Event shouldn't have been sent\n");
676     CloseHandle(mch_event);
677     ok(SetConsoleCtrlHandler(mch, FALSE), "Couldn't remove handler\n");
678     ok(!SetConsoleCtrlHandler(mch, FALSE), "Shouldn't succeed\n");
679     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %u\n", GetLastError());
680 }
681 
682 /*
683  * Test console screen buffer:
684  * 1) Try to set invalid handle.
685  * 2) Try to set non-console handles.
686  * 3) Use CONOUT$ file as active SB.
687  * 4) Test cursor.
688  * 5) Test output codepage to show it is not a property of SB.
689  * 6) Test switching to old SB if we close all handles to current SB - works
690  * in Windows, TODO in wine.
691  *
692  * What is not tested but should be:
693  * 1) ScreenBufferInfo
694  */
testScreenBuffer(HANDLE hConOut)695 static void testScreenBuffer(HANDLE hConOut)
696 {
697     HANDLE hConOutRW, hConOutRO, hConOutWT;
698     HANDLE hFileOutRW, hFileOutRO, hFileOutWT;
699     HANDLE hConOutNew;
700     char test_str1[] = "Test for SB1";
701     char test_str2[] = "Test for SB2";
702     char test_cp866[] = {0xe2, 0xa5, 0xe1, 0xe2, 0};
703     char test_cp1251[] = {0xf2, 0xe5, 0xf1, 0xf2, 0};
704     WCHAR test_unicode[] = {0x0442, 0x0435, 0x0441, 0x0442, 0};
705     WCHAR str_wbuf[20];
706     char str_buf[20];
707     DWORD len, error;
708     COORD c;
709     BOOL ret;
710     DWORD oldcp;
711 
712     if (!IsValidCodePage(866))
713     {
714         skip("Codepage 866 not available\n");
715         return;
716     }
717 
718     /* In the beginning set output codepage to 866 */
719     oldcp = GetConsoleOutputCP();
720     SetLastError(0xdeadbeef);
721     ret = SetConsoleOutputCP(866);
722     if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
723     {
724         win_skip("SetConsoleOutputCP is not implemented\n");
725         return;
726     }
727     ok(ret, "Cannot set output codepage to 866\n");
728 
729     hConOutRW = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
730                          FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
731                          CONSOLE_TEXTMODE_BUFFER, NULL);
732     ok(hConOutRW != INVALID_HANDLE_VALUE,
733        "Cannot create a new screen buffer for ReadWrite\n");
734     hConOutRO = CreateConsoleScreenBuffer(GENERIC_READ,
735                          FILE_SHARE_READ, NULL,
736                          CONSOLE_TEXTMODE_BUFFER, NULL);
737     ok(hConOutRO != INVALID_HANDLE_VALUE,
738        "Cannot create a new screen buffer for ReadOnly\n");
739     hConOutWT = CreateConsoleScreenBuffer(GENERIC_WRITE,
740                          FILE_SHARE_WRITE, NULL,
741                          CONSOLE_TEXTMODE_BUFFER, NULL);
742     ok(hConOutWT != INVALID_HANDLE_VALUE,
743        "Cannot create a new screen buffer for WriteOnly\n");
744 
745     hFileOutRW = CreateFileA("NUL", GENERIC_READ | GENERIC_WRITE,
746                              FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
747                              OPEN_EXISTING, 0, NULL);
748     ok(hFileOutRW != INVALID_HANDLE_VALUE, "Cannot open NUL for ReadWrite\n");
749     hFileOutRO = CreateFileA("NUL", GENERIC_READ, FILE_SHARE_READ,
750                              NULL, OPEN_EXISTING, 0, NULL);
751     ok(hFileOutRO != INVALID_HANDLE_VALUE, "Cannot open NUL for ReadOnly\n");
752     hFileOutWT = CreateFileA("NUL", GENERIC_WRITE, FILE_SHARE_WRITE,
753                              NULL, OPEN_EXISTING, 0, NULL);
754     ok(hFileOutWT != INVALID_HANDLE_VALUE, "Cannot open NUL for WriteOnly\n");
755 
756     /* Trying to set invalid handle */
757     SetLastError(0);
758     ok(!SetConsoleActiveScreenBuffer(INVALID_HANDLE_VALUE),
759        "Shouldn't succeed\n");
760     ok(GetLastError() == ERROR_INVALID_HANDLE,
761        "GetLastError: expecting %u got %u\n",
762        ERROR_INVALID_HANDLE, GetLastError());
763 
764     /* Trying to set non-console handles */
765     SetLastError(0);
766     ok(!SetConsoleActiveScreenBuffer(hFileOutRW), "Shouldn't succeed\n");
767     ok(GetLastError() == ERROR_INVALID_HANDLE,
768        "GetLastError: expecting %u got %u\n",
769        ERROR_INVALID_HANDLE, GetLastError());
770 
771     SetLastError(0);
772     ok(!SetConsoleActiveScreenBuffer(hFileOutRO), "Shouldn't succeed\n");
773     ok(GetLastError() == ERROR_INVALID_HANDLE,
774        "GetLastError: expecting %u got %u\n",
775        ERROR_INVALID_HANDLE, GetLastError());
776 
777     SetLastError(0);
778     ok(!SetConsoleActiveScreenBuffer(hFileOutWT), "Shouldn't succeed\n");
779     ok(GetLastError() == ERROR_INVALID_HANDLE,
780        "GetLastError: expecting %u got %u\n",
781        ERROR_INVALID_HANDLE, GetLastError());
782 
783     /* trying to write non-console handle */
784     SetLastError(0xdeadbeef);
785     ret = WriteConsoleA(hFileOutRW, test_str1, lstrlenA(test_str1), &len, NULL);
786     error = GetLastError();
787     ok(!ret, "Shouldn't succeed\n");
788     ok(error == ERROR_INVALID_HANDLE || error == ERROR_INVALID_FUNCTION,
789        "GetLastError: got %u\n", error);
790 
791     SetLastError(0xdeadbeef);
792     ret = WriteConsoleA(hFileOutRO, test_str1, lstrlenA(test_str1), &len, NULL);
793     error = GetLastError();
794     ok(!ret, "Shouldn't succeed\n");
795     ok(error == ERROR_INVALID_HANDLE || error == ERROR_INVALID_FUNCTION,
796        "GetLastError: got %u\n", error);
797 
798     SetLastError(0xdeadbeef);
799     ret = WriteConsoleA(hFileOutWT, test_str1, lstrlenA(test_str1), &len, NULL);
800     error = GetLastError();
801     ok(!ret, "Shouldn't succeed\n");
802     todo_wine ok(error == ERROR_INVALID_HANDLE || error == ERROR_INVALID_FUNCTION,
803        "GetLastError: got %u\n", error);
804 
805     CloseHandle(hFileOutRW);
806     CloseHandle(hFileOutRO);
807     CloseHandle(hFileOutWT);
808 
809     /* Trying to set SB handles with various access modes */
810     SetLastError(0);
811     ok(!SetConsoleActiveScreenBuffer(hConOutRO), "Shouldn't succeed\n");
812     ok(GetLastError() == ERROR_INVALID_HANDLE,
813        "GetLastError: expecting %u got %u\n",
814        ERROR_INVALID_HANDLE, GetLastError());
815 
816     ok(SetConsoleActiveScreenBuffer(hConOutWT), "Couldn't set new WriteOnly SB\n");
817 
818     ok(SetConsoleActiveScreenBuffer(hConOutRW), "Couldn't set new ReadWrite SB\n");
819 
820     CloseHandle(hConOutWT);
821     CloseHandle(hConOutRO);
822 
823     /* Now we have two ReadWrite SB, active must be hConOutRW */
824     /* Open current SB via CONOUT$ */
825     hConOutNew = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0,
826                              NULL, OPEN_EXISTING, 0, 0);
827     ok(hConOutNew != INVALID_HANDLE_VALUE, "CONOUT$ is not opened\n");
828 
829 
830     /* test cursor */
831     c.X = c.Y = 10;
832     SetConsoleCursorPosition(hConOut, c);
833     c.X = c.Y = 5;
834     SetConsoleCursorPosition(hConOutRW, c);
835     okCURSOR(hConOutNew, c);
836     c.X = c.Y = 10;
837     okCURSOR(hConOut, c);
838 
839 
840     c.X = c.Y = 0;
841 
842     /* Write using hConOutNew... */
843     SetConsoleCursorPosition(hConOutNew, c);
844     ret = WriteConsoleA(hConOutNew, test_str2, lstrlenA(test_str2), &len, NULL);
845     ok (ret && len == lstrlenA(test_str2), "WriteConsoleA failed\n");
846     /* ... and read it back via hConOutRW */
847     ret = ReadConsoleOutputCharacterA(hConOutRW, str_buf, lstrlenA(test_str2), c, &len);
848     ok(ret && len == lstrlenA(test_str2), "ReadConsoleOutputCharacterA failed\n");
849     str_buf[lstrlenA(test_str2)] = 0;
850     ok(!lstrcmpA(str_buf, test_str2), "got '%s' expected '%s'\n", str_buf, test_str2);
851 
852 
853     /* Now test output codepage handling. Current is 866 as we set earlier. */
854     SetConsoleCursorPosition(hConOutRW, c);
855     ret = WriteConsoleA(hConOutRW, test_cp866, lstrlenA(test_cp866), &len, NULL);
856     ok(ret && len == lstrlenA(test_cp866), "WriteConsoleA failed\n");
857     ret = ReadConsoleOutputCharacterW(hConOutRW, str_wbuf, lstrlenA(test_cp866), c, &len);
858     ok(ret && len == lstrlenA(test_cp866), "ReadConsoleOutputCharacterW failed\n");
859     str_wbuf[lstrlenA(test_cp866)] = 0;
860     ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n");
861 
862     /*
863      * cp866 is OK, let's switch to cp1251.
864      * We expect that this codepage will be used in every SB - active and not.
865      */
866     ok(SetConsoleOutputCP(1251), "Cannot set output cp to 1251\n");
867     SetConsoleCursorPosition(hConOutRW, c);
868     ret = WriteConsoleA(hConOutRW, test_cp1251, lstrlenA(test_cp1251), &len, NULL);
869     ok(ret && len == lstrlenA(test_cp1251), "WriteConsoleA failed\n");
870     ret = ReadConsoleOutputCharacterW(hConOutRW, str_wbuf, lstrlenA(test_cp1251), c, &len);
871     ok(ret && len == lstrlenA(test_cp1251), "ReadConsoleOutputCharacterW failed\n");
872     str_wbuf[lstrlenA(test_cp1251)] = 0;
873     ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n");
874 
875     /* Check what has happened to hConOut. */
876     SetConsoleCursorPosition(hConOut, c);
877     ret = WriteConsoleA(hConOut, test_cp1251, lstrlenA(test_cp1251), &len, NULL);
878     ok(ret && len == lstrlenA(test_cp1251), "WriteConsoleA failed\n");
879     ret = ReadConsoleOutputCharacterW(hConOut, str_wbuf, lstrlenA(test_cp1251), c, &len);
880     ok(ret && len == lstrlenA(test_cp1251), "ReadConsoleOutputCharacterW failed\n");
881     str_wbuf[lstrlenA(test_cp1251)] = 0;
882     ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n");
883 
884     /* Close all handles of current console SB */
885     CloseHandle(hConOutNew);
886     CloseHandle(hConOutRW);
887 
888     /* Now active SB should be hConOut */
889     hConOutNew = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0,
890                              NULL, OPEN_EXISTING, 0, 0);
891     ok(hConOutNew != INVALID_HANDLE_VALUE, "CONOUT$ is not opened\n");
892 
893     /* Write using hConOutNew... */
894     SetConsoleCursorPosition(hConOutNew, c);
895     ret = WriteConsoleA(hConOutNew, test_str1, lstrlenA(test_str1), &len, NULL);
896     ok (ret && len == lstrlenA(test_str1), "WriteConsoleA failed\n");
897     /* ... and read it back via hConOut */
898     ret = ReadConsoleOutputCharacterA(hConOut, str_buf, lstrlenA(test_str1), c, &len);
899     ok(ret && len == lstrlenA(test_str1), "ReadConsoleOutputCharacterA failed\n");
900     str_buf[lstrlenA(test_str1)] = 0;
901     todo_wine ok(!lstrcmpA(str_buf, test_str1), "got '%s' expected '%s'\n", str_buf, test_str1);
902     CloseHandle(hConOutNew);
903 
904     /* This is not really needed under Windows */
905     SetConsoleActiveScreenBuffer(hConOut);
906 
907     /* restore codepage */
908     SetConsoleOutputCP(oldcp);
909 }
910 
signaled_function(void * p,BOOLEAN timeout)911 static void CALLBACK signaled_function(void *p, BOOLEAN timeout)
912 {
913     HANDLE event = p;
914     SetEvent(event);
915     ok(!timeout, "wait shouldn't have timed out\n");
916 }
917 
testWaitForConsoleInput(HANDLE input_handle)918 static void testWaitForConsoleInput(HANDLE input_handle)
919 {
920     HANDLE wait_handle;
921     HANDLE complete_event;
922     INPUT_RECORD record;
923     DWORD events_written;
924     DWORD wait_ret;
925     BOOL ret;
926 
927     complete_event = CreateEventW(NULL, FALSE, FALSE, NULL);
928 
929     /* Test success case */
930     ret = RegisterWaitForSingleObject(&wait_handle, input_handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
931     ok(ret == TRUE, "Expected RegisterWaitForSingleObject to return TRUE, got %d\n", ret);
932     /* give worker thread a chance to start up */
933     Sleep(100);
934     record.EventType = KEY_EVENT;
935     record.Event.KeyEvent.bKeyDown = 1;
936     record.Event.KeyEvent.wRepeatCount = 1;
937     record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
938     record.Event.KeyEvent.wVirtualScanCode = VK_RETURN;
939     record.Event.KeyEvent.uChar.UnicodeChar = '\r';
940     record.Event.KeyEvent.dwControlKeyState = 0;
941     ret = WriteConsoleInputW(input_handle, &record, 1, &events_written);
942     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
943     wait_ret = WaitForSingleObject(complete_event, INFINITE);
944     ok(wait_ret == WAIT_OBJECT_0, "Expected the handle to be signaled\n");
945     ret = UnregisterWait(wait_handle);
946     /* If the callback is still running, this fails with ERROR_IO_PENDING, but
947        that's ok and expected. */
948     ok(ret != 0 || GetLastError() == ERROR_IO_PENDING,
949         "UnregisterWait failed with error %d\n", GetLastError());
950 
951     /* Test timeout case */
952     FlushConsoleInputBuffer(input_handle);
953     ret = RegisterWaitForSingleObject(&wait_handle, input_handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
954     wait_ret = WaitForSingleObject(complete_event, 100);
955     ok(wait_ret == WAIT_TIMEOUT, "Expected the wait to time out\n");
956     ret = UnregisterWait(wait_handle);
957     ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
958 
959     /* Clean up */
960     CloseHandle(complete_event);
961 }
962 
test_GetSetConsoleInputExeName(void)963 static void test_GetSetConsoleInputExeName(void)
964 {
965     BOOL ret;
966     DWORD error;
967     char buffer[MAX_PATH], module[MAX_PATH], *p;
968     static char input_exe[MAX_PATH] = "winetest.exe";
969 
970     SetLastError(0xdeadbeef);
971     ret = pGetConsoleInputExeNameA(0, NULL);
972     error = GetLastError();
973     ok(ret, "GetConsoleInputExeNameA failed\n");
974     ok(error == ERROR_BUFFER_OVERFLOW, "got %u expected ERROR_BUFFER_OVERFLOW\n", error);
975 
976     SetLastError(0xdeadbeef);
977     ret = pGetConsoleInputExeNameA(0, buffer);
978     error = GetLastError();
979     ok(ret, "GetConsoleInputExeNameA failed\n");
980     ok(error == ERROR_BUFFER_OVERFLOW, "got %u expected ERROR_BUFFER_OVERFLOW\n", error);
981 
982     GetModuleFileNameA(GetModuleHandleA(NULL), module, sizeof(module));
983     p = strrchr(module, '\\') + 1;
984 
985     ret = pGetConsoleInputExeNameA(sizeof(buffer)/sizeof(buffer[0]), buffer);
986     ok(ret, "GetConsoleInputExeNameA failed\n");
987     todo_wine ok(!lstrcmpA(buffer, p), "got %s expected %s\n", buffer, p);
988 
989     SetLastError(0xdeadbeef);
990     ret = pSetConsoleInputExeNameA(NULL);
991     error = GetLastError();
992     ok(!ret, "SetConsoleInputExeNameA failed\n");
993     ok(error == ERROR_INVALID_PARAMETER, "got %u expected ERROR_INVALID_PARAMETER\n", error);
994 
995     SetLastError(0xdeadbeef);
996     ret = pSetConsoleInputExeNameA("");
997     error = GetLastError();
998     ok(!ret, "SetConsoleInputExeNameA failed\n");
999     ok(error == ERROR_INVALID_PARAMETER, "got %u expected ERROR_INVALID_PARAMETER\n", error);
1000 
1001     ret = pSetConsoleInputExeNameA(input_exe);
1002     ok(ret, "SetConsoleInputExeNameA failed\n");
1003 
1004     ret = pGetConsoleInputExeNameA(sizeof(buffer)/sizeof(buffer[0]), buffer);
1005     ok(ret, "GetConsoleInputExeNameA failed\n");
1006     ok(!lstrcmpA(buffer, input_exe), "got %s expected %s\n", buffer, input_exe);
1007 }
1008 
test_GetConsoleProcessList(void)1009 static void test_GetConsoleProcessList(void)
1010 {
1011     DWORD ret, *list = NULL;
1012 
1013     if (!pGetConsoleProcessList)
1014     {
1015         win_skip("GetConsoleProcessList is not available\n");
1016         return;
1017     }
1018 
1019     SetLastError(0xdeadbeef);
1020     ret = pGetConsoleProcessList(NULL, 0);
1021     ok(ret == 0, "Expected failure\n");
1022     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1023        "Expected ERROR_INVALID_PARAMETER, got %d\n",
1024        GetLastError());
1025 
1026     SetLastError(0xdeadbeef);
1027     ret = pGetConsoleProcessList(NULL, 1);
1028     ok(ret == 0, "Expected failure\n");
1029     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1030        "Expected ERROR_INVALID_PARAMETER, got %d\n",
1031        GetLastError());
1032 
1033     /* We should only have 1 process but only for these specific unit tests as
1034      * we created our own console. An AttachConsole(ATTACH_PARENT_PROCESS) would
1035      * give us two processes for example.
1036      */
1037     list = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD));
1038 
1039     SetLastError(0xdeadbeef);
1040     ret = pGetConsoleProcessList(list, 0);
1041     ok(ret == 0, "Expected failure\n");
1042     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1043        "Expected ERROR_INVALID_PARAMETER, got %d\n",
1044        GetLastError());
1045 
1046     SetLastError(0xdeadbeef);
1047     ret = pGetConsoleProcessList(list, 1);
1048     todo_wine
1049     ok(ret == 1, "Expected 1, got %d\n", ret);
1050 
1051     HeapFree(GetProcessHeap(), 0, list);
1052 
1053     list = HeapAlloc(GetProcessHeap(), 0, ret * sizeof(DWORD));
1054 
1055     SetLastError(0xdeadbeef);
1056     ret = pGetConsoleProcessList(list, ret);
1057     todo_wine
1058     ok(ret == 1, "Expected 1, got %d\n", ret);
1059 
1060     if (ret == 1)
1061     {
1062         DWORD pid = GetCurrentProcessId();
1063         ok(list[0] == pid, "Expected %d, got %d\n", pid, list[0]);
1064     }
1065 
1066     HeapFree(GetProcessHeap(), 0, list);
1067 }
1068 
test_OpenCON(void)1069 static void test_OpenCON(void)
1070 {
1071     static const WCHAR conW[] = {'C','O','N',0};
1072     static const DWORD accesses[] = {CREATE_NEW, CREATE_ALWAYS, OPEN_EXISTING,
1073                                      OPEN_ALWAYS, TRUNCATE_EXISTING};
1074     unsigned            i;
1075     HANDLE              h;
1076 
1077     for (i = 0; i < sizeof(accesses) / sizeof(accesses[0]); i++)
1078     {
1079         h = CreateFileW(conW, GENERIC_WRITE, 0, NULL, accesses[i], 0, NULL);
1080         ok(h != INVALID_HANDLE_VALUE || broken(accesses[i] == TRUNCATE_EXISTING /* Win8 */),
1081            "Expected to open the CON device on write (%x)\n", accesses[i]);
1082         CloseHandle(h);
1083 
1084         h = CreateFileW(conW, GENERIC_READ, 0, NULL, accesses[i], 0, NULL);
1085         /* Windows versions differ here:
1086          * MSDN states in CreateFile that TRUNCATE_EXISTING requires GENERIC_WRITE
1087          * NT, XP, Vista comply, but Win7 doesn't and allows opening CON with TRUNCATE_EXISTING
1088          * So don't test when disposition is TRUNCATE_EXISTING
1089          */
1090         ok(h != INVALID_HANDLE_VALUE || broken(accesses[i] == TRUNCATE_EXISTING /* Win7+ */),
1091            "Expected to open the CON device on read (%x)\n", accesses[i]);
1092         CloseHandle(h);
1093         h = CreateFileW(conW, GENERIC_READ|GENERIC_WRITE, 0, NULL, accesses[i], 0, NULL);
1094         ok(h == INVALID_HANDLE_VALUE, "Expected not to open the CON device on read-write (%x)\n", accesses[i]);
1095         ok(GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_INVALID_PARAMETER,
1096            "Unexpected error %x\n", GetLastError());
1097     }
1098 }
1099 
test_OpenConsoleW(void)1100 static void test_OpenConsoleW(void)
1101 {
1102     static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
1103     static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
1104     static const WCHAR emptyW[] = {0};
1105     static const WCHAR invalidW[] = {'I','N','V','A','L','I','D',0};
1106     DWORD gle;
1107 
1108     static const struct
1109     {
1110         LPCWSTR name;
1111         DWORD access;
1112         BOOL inherit;
1113         DWORD creation;
1114         DWORD gle, gle2;
1115     } invalid_table[] = {
1116         {NULL,     0,                            FALSE,      0,                 ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1117         {NULL,     0,                            FALSE,      0xdeadbeef,        ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1118         {NULL,     0xdeadbeef,                   FALSE,      0,                 ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1119         {NULL,     0xdeadbeef,                   TRUE,       0xdeadbeef,        ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1120         {NULL,     0,                            FALSE,      OPEN_ALWAYS,       ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1121         {NULL,     GENERIC_READ | GENERIC_WRITE, FALSE,      0,                 ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1122         {NULL,     GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_ALWAYS,       ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1123         {NULL,     GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_EXISTING,     ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1124         {emptyW,   0,                            FALSE,      0,                 ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1125         {emptyW,   0,                            FALSE,      0xdeadbeef,        ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1126         {emptyW,   0xdeadbeef,                   FALSE,      0,                 ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1127         {emptyW,   0xdeadbeef,                   TRUE,       0xdeadbeef,        ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1128         {emptyW,   0,                            FALSE,      OPEN_ALWAYS,       ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1129         {emptyW,   GENERIC_READ | GENERIC_WRITE, FALSE,      0,                 ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1130         {emptyW,   GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_ALWAYS,       ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1131         {emptyW,   GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_EXISTING,     ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1132         {invalidW, 0,                            FALSE,      0,                 ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1133         {invalidW, 0,                            FALSE,      0xdeadbeef,        ERROR_INVALID_PARAMETER, 0},
1134         {invalidW, 0xdeadbeef,                   FALSE,      0,                 ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1135         {invalidW, 0xdeadbeef,                   TRUE,       0xdeadbeef,        ERROR_INVALID_PARAMETER, 0},
1136         {invalidW, 0,                            FALSE,      OPEN_ALWAYS,       ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1137         {invalidW, GENERIC_READ | GENERIC_WRITE, FALSE,      0,                 ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1138         {invalidW, GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_ALWAYS,       ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1139         {invalidW, GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_EXISTING,     ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1140         {coninW,   0,                            FALSE,      0xdeadbeef,        ERROR_INVALID_PARAMETER, 0},
1141         {coninW,   0xdeadbeef,                   FALSE,      0,                 ERROR_INVALID_PARAMETER, ERROR_ACCESS_DENIED},
1142         {coninW,   0xdeadbeef,                   TRUE,       0xdeadbeef,        ERROR_INVALID_PARAMETER, 0},
1143         {conoutW,  0,                            FALSE,      0xdeadbeef,        ERROR_INVALID_PARAMETER, 0},
1144         {conoutW,  0xceadbeef,                   FALSE,      0,                 ERROR_INVALID_PARAMETER, ERROR_ACCESS_DENIED},
1145         {conoutW,  0xdeadbeef,                   TRUE,       0xdeadbeef,        ERROR_INVALID_PARAMETER, 0},
1146     };
1147     static const struct
1148     {
1149         LPCWSTR name;
1150         DWORD access;
1151         BOOL inherit;
1152         DWORD creation;
1153     } valid_table[] = {
1154         {coninW,   0,                            FALSE,      0                },
1155         {coninW,   0,                            TRUE,       0                },
1156         {coninW,   GENERIC_EXECUTE,              TRUE,       0                },
1157         {coninW,   GENERIC_ALL,                  TRUE,       0                },
1158         {coninW,   0,                            FALSE,      OPEN_ALWAYS      },
1159         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      0                },
1160         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      CREATE_NEW       },
1161         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      CREATE_ALWAYS    },
1162         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_ALWAYS      },
1163         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      TRUNCATE_EXISTING},
1164         {conoutW,  0,                            FALSE,      0                },
1165         {conoutW,  0,                            FALSE,      OPEN_ALWAYS      },
1166         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      0                },
1167         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      CREATE_NEW,      },
1168         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      CREATE_ALWAYS    },
1169         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_ALWAYS      },
1170         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      TRUNCATE_EXISTING},
1171     };
1172 
1173     int index;
1174     HANDLE ret;
1175 
1176     if (!pOpenConsoleW)
1177     {
1178         win_skip("OpenConsoleW is not available\n");
1179         return;
1180     }
1181 
1182     for (index = 0; index < sizeof(invalid_table)/sizeof(invalid_table[0]); index++)
1183     {
1184         SetLastError(0xdeadbeef);
1185         ret = pOpenConsoleW(invalid_table[index].name, invalid_table[index].access,
1186                             invalid_table[index].inherit, invalid_table[index].creation);
1187         gle = GetLastError();
1188         ok(ret == INVALID_HANDLE_VALUE,
1189            "Expected OpenConsoleW to return INVALID_HANDLE_VALUE for index %d, got %p\n",
1190            index, ret);
1191         ok(gle == invalid_table[index].gle || (gle != 0 && gle == invalid_table[index].gle2),
1192            "Expected GetLastError() to return %u/%u for index %d, got %u\n",
1193            invalid_table[index].gle, invalid_table[index].gle2, index, gle);
1194     }
1195 
1196     for (index = 0; index < sizeof(valid_table)/sizeof(valid_table[0]); index++)
1197     {
1198         ret = pOpenConsoleW(valid_table[index].name, valid_table[index].access,
1199                             valid_table[index].inherit, valid_table[index].creation);
1200         todo_wine
1201         ok(ret != INVALID_HANDLE_VALUE || broken(ret == INVALID_HANDLE_VALUE /* until Win7 */),
1202            "Expected OpenConsoleW to succeed for index %d, got %p\n", index, ret);
1203         if (ret != INVALID_HANDLE_VALUE)
1204             CloseHandle(ret);
1205     }
1206 
1207     ret = pOpenConsoleW(coninW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING);
1208     ok(ret != INVALID_HANDLE_VALUE, "Expected OpenConsoleW to return a valid handle\n");
1209     if (ret != INVALID_HANDLE_VALUE)
1210         CloseHandle(ret);
1211 
1212     ret = pOpenConsoleW(conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING);
1213     ok(ret != INVALID_HANDLE_VALUE, "Expected OpenConsoleW to return a valid handle\n");
1214     if (ret != INVALID_HANDLE_VALUE)
1215         CloseHandle(ret);
1216 }
1217 
test_CreateFileW(void)1218 static void test_CreateFileW(void)
1219 {
1220     static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
1221     static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
1222 
1223     static const struct
1224     {
1225         LPCWSTR name;
1226         DWORD access;
1227         BOOL inherit;
1228         DWORD creation;
1229         DWORD gle;
1230         BOOL is_broken;
1231     } cf_table[] = {
1232         {coninW,   0,                            FALSE,      0,                 ERROR_INVALID_PARAMETER,        TRUE},
1233         {coninW,   0,                            FALSE,      OPEN_ALWAYS,       0,                              FALSE},
1234         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      0,                 ERROR_INVALID_PARAMETER,        TRUE},
1235         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      CREATE_NEW,        0,                              FALSE},
1236         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      CREATE_ALWAYS,     0,                              FALSE},
1237         {coninW,   GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_ALWAYS,       0,                              FALSE},
1238         {conoutW,  0,                            FALSE,      0,                 ERROR_INVALID_PARAMETER,        TRUE},
1239         {conoutW,  0,                            FALSE,      OPEN_ALWAYS,       0,                              FALSE},
1240         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      0,                 ERROR_INVALID_PARAMETER,        TRUE},
1241         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      CREATE_NEW,        0,                              FALSE},
1242         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      CREATE_ALWAYS,     0,                              FALSE},
1243         {conoutW,  GENERIC_READ | GENERIC_WRITE, FALSE,      OPEN_ALWAYS,       0,                              FALSE},
1244         /* TRUNCATE_EXISTING is forbidden starting with Windows 8 */
1245     };
1246 
1247     int index;
1248     HANDLE ret;
1249     SECURITY_ATTRIBUTES sa;
1250 
1251     for (index = 0; index < sizeof(cf_table)/sizeof(cf_table[0]); index++)
1252     {
1253         SetLastError(0xdeadbeef);
1254 
1255         sa.nLength = sizeof(sa);
1256         sa.lpSecurityDescriptor = NULL;
1257         sa.bInheritHandle = cf_table[index].inherit;
1258 
1259         ret = CreateFileW(cf_table[index].name, cf_table[index].access,
1260                           FILE_SHARE_READ|FILE_SHARE_WRITE, &sa,
1261                           cf_table[index].creation, FILE_ATTRIBUTE_NORMAL, NULL);
1262         if (ret == INVALID_HANDLE_VALUE)
1263         {
1264             ok(cf_table[index].gle,
1265                "Expected CreateFileW not to return INVALID_HANDLE_VALUE for index %d\n", index);
1266             ok(GetLastError() == cf_table[index].gle,
1267                 "Expected GetLastError() to return %u for index %d, got %u\n",
1268                 cf_table[index].gle, index, GetLastError());
1269         }
1270         else
1271         {
1272             ok(!cf_table[index].gle || broken(cf_table[index].is_broken) /* Win7 */,
1273                "Expected CreateFileW to succeed for index %d\n", index);
1274             CloseHandle(ret);
1275         }
1276     }
1277 }
1278 
test_VerifyConsoleIoHandle(HANDLE handle)1279 static void test_VerifyConsoleIoHandle( HANDLE handle )
1280 {
1281     BOOL ret;
1282     DWORD error;
1283 
1284     if (!pVerifyConsoleIoHandle)
1285     {
1286         win_skip("VerifyConsoleIoHandle is not available\n");
1287         return;
1288     }
1289 
1290     /* invalid handle */
1291     SetLastError(0xdeadbeef);
1292     ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee0);
1293     error = GetLastError();
1294     ok(!ret, "expected VerifyConsoleIoHandle to fail\n");
1295     ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error);
1296 
1297     /* invalid handle + 1 */
1298     SetLastError(0xdeadbeef);
1299     ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee1);
1300     error = GetLastError();
1301     ok(!ret, "expected VerifyConsoleIoHandle to fail\n");
1302     ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error);
1303 
1304     /* invalid handle + 2 */
1305     SetLastError(0xdeadbeef);
1306     ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee2);
1307     error = GetLastError();
1308     ok(!ret, "expected VerifyConsoleIoHandle to fail\n");
1309     ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error);
1310 
1311     /* invalid handle + 3 */
1312     SetLastError(0xdeadbeef);
1313     ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee3);
1314     error = GetLastError();
1315     ok(!ret, "expected VerifyConsoleIoHandle to fail\n");
1316     ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error);
1317 
1318     /* valid handle */
1319     SetLastError(0xdeadbeef);
1320     ret = pVerifyConsoleIoHandle(handle);
1321     error = GetLastError();
1322     ok(ret ||
1323        broken(!ret), /* Windows 8 and 10 */
1324        "expected VerifyConsoleIoHandle to succeed\n");
1325     ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error);
1326 }
1327 
test_GetSetStdHandle(void)1328 static void test_GetSetStdHandle(void)
1329 {
1330     HANDLE handle;
1331     DWORD error;
1332     BOOL ret;
1333 
1334     /* get invalid std handle */
1335     SetLastError(0xdeadbeef);
1336     handle = GetStdHandle(42);
1337     error = GetLastError();
1338     ok(error == ERROR_INVALID_HANDLE || broken(error == ERROR_INVALID_FUNCTION)/* Win9x */,
1339        "wrong GetLastError() %d\n", error);
1340     ok(handle == INVALID_HANDLE_VALUE, "expected INVALID_HANDLE_VALUE\n");
1341 
1342     /* get valid */
1343     SetLastError(0xdeadbeef);
1344     handle = GetStdHandle(STD_INPUT_HANDLE);
1345     error = GetLastError();
1346     ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error);
1347 
1348     /* set invalid std handle */
1349     SetLastError(0xdeadbeef);
1350     ret = SetStdHandle(42, handle);
1351     error = GetLastError();
1352     ok(!ret, "expected SetStdHandle to fail\n");
1353     ok(error == ERROR_INVALID_HANDLE || broken(error == ERROR_INVALID_FUNCTION)/* Win9x */,
1354        "wrong GetLastError() %d\n", error);
1355 
1356     /* set valid (restore old value) */
1357     SetLastError(0xdeadbeef);
1358     ret = SetStdHandle(STD_INPUT_HANDLE, handle);
1359     error = GetLastError();
1360     ok(ret, "expected SetStdHandle to succeed\n");
1361     ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error);
1362 }
1363 
test_GetNumberOfConsoleInputEvents(HANDLE input_handle)1364 static void test_GetNumberOfConsoleInputEvents(HANDLE input_handle)
1365 {
1366     DWORD count;
1367     BOOL ret;
1368     int i;
1369 
1370     const struct
1371     {
1372         HANDLE handle;
1373         LPDWORD nrofevents;
1374         DWORD last_error;
1375     } invalid_table[] =
1376     {
1377         {NULL,                 NULL,   ERROR_INVALID_HANDLE},
1378         {NULL,                 &count, ERROR_INVALID_HANDLE},
1379         {INVALID_HANDLE_VALUE, NULL,   ERROR_INVALID_HANDLE},
1380         {INVALID_HANDLE_VALUE, &count, ERROR_INVALID_HANDLE},
1381     };
1382 
1383     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
1384     {
1385         SetLastError(0xdeadbeef);
1386         if (invalid_table[i].nrofevents) count = 0xdeadbeef;
1387         ret = GetNumberOfConsoleInputEvents(invalid_table[i].handle,
1388                                             invalid_table[i].nrofevents);
1389         ok(!ret, "[%d] Expected GetNumberOfConsoleInputEvents to return FALSE, got %d\n", i, ret);
1390         if (invalid_table[i].nrofevents)
1391         {
1392             ok(count == 0xdeadbeef,
1393                "[%d] Expected output count to be unmodified, got %u\n", i, count);
1394         }
1395         ok(GetLastError() == invalid_table[i].last_error,
1396            "[%d] Expected last error to be %u, got %u\n",
1397            i, invalid_table[i].last_error, GetLastError());
1398     }
1399 
1400     /* Test crashes on Windows 7. */
1401     if (0)
1402     {
1403         SetLastError(0xdeadbeef);
1404         ret = GetNumberOfConsoleInputEvents(input_handle, NULL);
1405         ok(!ret, "Expected GetNumberOfConsoleInputEvents to return FALSE, got %d\n", ret);
1406         ok(GetLastError() == ERROR_INVALID_ACCESS,
1407            "Expected last error to be ERROR_INVALID_ACCESS, got %u\n",
1408            GetLastError());
1409     }
1410 
1411     count = 0xdeadbeef;
1412     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1413     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1414     ok(count != 0xdeadbeef, "Expected output count to initialized\n");
1415 }
1416 
test_WriteConsoleInputA(HANDLE input_handle)1417 static void test_WriteConsoleInputA(HANDLE input_handle)
1418 {
1419     INPUT_RECORD event;
1420     INPUT_RECORD event_list[5];
1421     MOUSE_EVENT_RECORD mouse_event = { {0, 0}, 0, 0, MOUSE_MOVED };
1422     KEY_EVENT_RECORD key_event;
1423     DWORD count, console_mode, gle;
1424     BOOL ret;
1425     int i;
1426 
1427     const struct
1428     {
1429         HANDLE handle;
1430         const INPUT_RECORD *buffer;
1431         DWORD count;
1432         LPDWORD written;
1433         DWORD gle, gle2;
1434         int win_crash;
1435     } invalid_table[] =
1436     {
1437         {NULL, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1438         {NULL, NULL, 0, &count,ERROR_INVALID_HANDLE},
1439         {NULL, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1440         {NULL, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
1441         {NULL, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1442         {NULL, &event, 0, &count, ERROR_INVALID_HANDLE},
1443         {NULL, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1444         {NULL, &event, 1, &count, ERROR_INVALID_HANDLE},
1445         {INVALID_HANDLE_VALUE, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1446         {INVALID_HANDLE_VALUE, NULL, 0, &count, ERROR_INVALID_HANDLE},
1447         {INVALID_HANDLE_VALUE, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1448         {INVALID_HANDLE_VALUE, NULL, 1, &count, ERROR_INVALID_HANDLE, ERROR_INVALID_ACCESS},
1449         {INVALID_HANDLE_VALUE, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1450         {INVALID_HANDLE_VALUE, &event, 0, &count, ERROR_INVALID_HANDLE},
1451         {INVALID_HANDLE_VALUE, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1452         {INVALID_HANDLE_VALUE, &event, 1, &count, ERROR_INVALID_HANDLE},
1453         {input_handle, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1454         {input_handle, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1455         {input_handle, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
1456         {input_handle, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1457         {input_handle, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1458     };
1459 
1460     /* Suppress external sources of input events for the duration of the test. */
1461     ret = GetConsoleMode(input_handle, &console_mode);
1462     ok(ret == TRUE, "Expected GetConsoleMode to return TRUE, got %d\n", ret);
1463     if (!ret)
1464     {
1465         skip("GetConsoleMode failed with last error %u\n", GetLastError());
1466         return;
1467     }
1468 
1469     ret = SetConsoleMode(input_handle, console_mode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
1470     ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret);
1471     if (!ret)
1472     {
1473         skip("SetConsoleMode failed with last error %u\n", GetLastError());
1474         return;
1475     }
1476 
1477     /* Discard any events queued before the tests. */
1478     ret = FlushConsoleInputBuffer(input_handle);
1479     ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1480 
1481     event.EventType = MOUSE_EVENT;
1482     event.Event.MouseEvent = mouse_event;
1483 
1484     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
1485     {
1486         if (invalid_table[i].win_crash)
1487             continue;
1488 
1489         SetLastError(0xdeadbeef);
1490         if (invalid_table[i].written) count = 0xdeadbeef;
1491         ret = WriteConsoleInputA(invalid_table[i].handle,
1492                                  invalid_table[i].buffer,
1493                                  invalid_table[i].count,
1494                                  invalid_table[i].written);
1495         ok(!ret, "[%d] Expected WriteConsoleInputA to return FALSE, got %d\n", i, ret);
1496         gle = GetLastError();
1497         ok(gle == invalid_table[i].gle || (gle != 0 && gle == invalid_table[i].gle2),
1498            "[%d] Expected last error to be %u or %u, got %u\n",
1499            i, invalid_table[i].gle, invalid_table[i].gle2, gle);
1500     }
1501 
1502     count = 0xdeadbeef;
1503     ret = WriteConsoleInputA(input_handle, NULL, 0, &count);
1504     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1505     ok(count == 0, "Expected count to be 0, got %u\n", count);
1506 
1507     count = 0xdeadbeef;
1508     ret = WriteConsoleInputA(input_handle, &event, 0, &count);
1509     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1510     ok(count == 0, "Expected count to be 0, got %u\n", count);
1511 
1512     count = 0xdeadbeef;
1513     ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1514     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1515     ok(count == 1, "Expected count to be 1, got %u\n", count);
1516 
1517     ret = FlushConsoleInputBuffer(input_handle);
1518     ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1519 
1520     /* Writing a single mouse event doesn't seem to affect the count if an adjacent mouse event is already queued. */
1521     event.EventType = MOUSE_EVENT;
1522     event.Event.MouseEvent = mouse_event;
1523 
1524     ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1525     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1526     ok(count == 1, "Expected count to be 1, got %u\n", count);
1527 
1528     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1529     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1530     ok(count == 1, "Expected count to be 1, got %u\n", count);
1531 
1532     ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1533     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1534     ok(count == 1, "Expected count to be 1, got %u\n", count);
1535 
1536     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1537     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1538     todo_wine
1539     ok(count == 1, "Expected count to be 1, got %u\n", count);
1540 
1541     ret = FlushConsoleInputBuffer(input_handle);
1542     ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1543 
1544     for (i = 0; i < sizeof(event_list)/sizeof(event_list[0]); i++)
1545     {
1546         event_list[i].EventType = MOUSE_EVENT;
1547         event_list[i].Event.MouseEvent = mouse_event;
1548     }
1549 
1550     /* Writing consecutive chunks of mouse events appears to work. */
1551     ret = WriteConsoleInputA(input_handle, event_list, sizeof(event_list)/sizeof(event_list[0]), &count);
1552     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1553     ok(count == sizeof(event_list)/sizeof(event_list[0]),
1554        "Expected count to be event list length, got %u\n", count);
1555 
1556     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1557     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1558     ok(count == sizeof(event_list)/sizeof(event_list[0]),
1559        "Expected count to be event list length, got %u\n", count);
1560 
1561     ret = WriteConsoleInputA(input_handle, event_list, sizeof(event_list)/sizeof(event_list[0]), &count);
1562     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1563     ok(count == sizeof(event_list)/sizeof(event_list[0]),
1564        "Expected count to be event list length, got %u\n", count);
1565 
1566     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1567     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1568     ok(count == 2*sizeof(event_list)/sizeof(event_list[0]),
1569        "Expected count to be twice event list length, got %u\n", count);
1570 
1571     /* Again, writing a single mouse event with adjacent mouse events queued doesn't appear to affect the count. */
1572     ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1573     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1574     ok(count == 1, "Expected count to be 1, got %u\n", count);
1575 
1576     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1577     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1578     todo_wine
1579     ok(count == 2*sizeof(event_list)/sizeof(event_list[0]),
1580        "Expected count to be twice event list length, got %u\n", count);
1581 
1582     ret = FlushConsoleInputBuffer(input_handle);
1583     ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1584 
1585     key_event.bKeyDown = FALSE;
1586     key_event.wRepeatCount = 0;
1587     key_event.wVirtualKeyCode = VK_SPACE;
1588     key_event.wVirtualScanCode = VK_SPACE;
1589     key_event.uChar.AsciiChar = ' ';
1590     key_event.dwControlKeyState = 0;
1591 
1592     event.EventType = KEY_EVENT;
1593     event.Event.KeyEvent = key_event;
1594 
1595     /* Key events don't exhibit the same behavior as mouse events. */
1596     ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1597     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1598     ok(count == 1, "Expected count to be 1, got %u\n", count);
1599 
1600     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1601     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1602     ok(count == 1, "Expected count to be 1, got %u\n", count);
1603 
1604     ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1605     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1606     ok(count == 1, "Expected count to be 1, got %u\n", count);
1607 
1608     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1609     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1610     ok(count == 2, "Expected count to be 2, got %u\n", count);
1611 
1612     ret = FlushConsoleInputBuffer(input_handle);
1613     ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1614 
1615     /* Try interleaving mouse and key events. */
1616     event.EventType = MOUSE_EVENT;
1617     event.Event.MouseEvent = mouse_event;
1618 
1619     ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1620     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1621     ok(count == 1, "Expected count to be 1, got %u\n", count);
1622 
1623     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1624     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1625     ok(count == 1, "Expected count to be 1, got %u\n", count);
1626 
1627     event.EventType = KEY_EVENT;
1628     event.Event.KeyEvent = key_event;
1629 
1630     ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1631     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1632     ok(count == 1, "Expected count to be 1, got %u\n", count);
1633 
1634     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1635     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1636     ok(count == 2, "Expected count to be 2, got %u\n", count);
1637 
1638     event.EventType = MOUSE_EVENT;
1639     event.Event.MouseEvent = mouse_event;
1640 
1641     ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1642     ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1643     ok(count == 1, "Expected count to be 1, got %u\n", count);
1644 
1645     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1646     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1647     ok(count == 3, "Expected count to be 3, got %u\n", count);
1648 
1649     /* Restore the old console mode. */
1650     ret = SetConsoleMode(input_handle, console_mode);
1651     ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret);
1652 }
1653 
test_WriteConsoleInputW(HANDLE input_handle)1654 static void test_WriteConsoleInputW(HANDLE input_handle)
1655 {
1656     INPUT_RECORD event;
1657     INPUT_RECORD event_list[5];
1658     MOUSE_EVENT_RECORD mouse_event = { {0, 0}, 0, 0, MOUSE_MOVED };
1659     KEY_EVENT_RECORD key_event;
1660     DWORD count, console_mode, gle;
1661     BOOL ret;
1662     int i;
1663 
1664     const struct
1665     {
1666         HANDLE handle;
1667         const INPUT_RECORD *buffer;
1668         DWORD count;
1669         LPDWORD written;
1670         DWORD gle, gle2;
1671         int win_crash;
1672     } invalid_table[] =
1673     {
1674         {NULL, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1675         {NULL, NULL, 0, &count, ERROR_INVALID_HANDLE},
1676         {NULL, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1677         {NULL, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
1678         {NULL, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1679         {NULL, &event, 0, &count, ERROR_INVALID_HANDLE},
1680         {NULL, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1681         {NULL, &event, 1, &count, ERROR_INVALID_HANDLE},
1682         {INVALID_HANDLE_VALUE, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1683         {INVALID_HANDLE_VALUE, NULL, 0, &count, ERROR_INVALID_HANDLE},
1684         {INVALID_HANDLE_VALUE, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1685         {INVALID_HANDLE_VALUE, NULL, 1, &count, ERROR_INVALID_HANDLE, ERROR_INVALID_ACCESS},
1686         {INVALID_HANDLE_VALUE, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1687         {INVALID_HANDLE_VALUE, &event, 0, &count, ERROR_INVALID_HANDLE},
1688         {INVALID_HANDLE_VALUE, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1689         {INVALID_HANDLE_VALUE, &event, 1, &count, ERROR_INVALID_HANDLE},
1690         {input_handle, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1691         {input_handle, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1692         {input_handle, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
1693         {input_handle, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1694         {input_handle, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1695     };
1696 
1697     /* Suppress external sources of input events for the duration of the test. */
1698     ret = GetConsoleMode(input_handle, &console_mode);
1699     ok(ret == TRUE, "Expected GetConsoleMode to return TRUE, got %d\n", ret);
1700     if (!ret)
1701     {
1702         skip("GetConsoleMode failed with last error %u\n", GetLastError());
1703         return;
1704     }
1705 
1706     ret = SetConsoleMode(input_handle, console_mode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
1707     ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret);
1708     if (!ret)
1709     {
1710         skip("SetConsoleMode failed with last error %u\n", GetLastError());
1711         return;
1712     }
1713 
1714     /* Discard any events queued before the tests. */
1715     ret = FlushConsoleInputBuffer(input_handle);
1716     ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1717 
1718     event.EventType = MOUSE_EVENT;
1719     event.Event.MouseEvent = mouse_event;
1720 
1721     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
1722     {
1723         if (invalid_table[i].win_crash)
1724             continue;
1725 
1726         SetLastError(0xdeadbeef);
1727         if (invalid_table[i].written) count = 0xdeadbeef;
1728         ret = WriteConsoleInputW(invalid_table[i].handle,
1729                                  invalid_table[i].buffer,
1730                                  invalid_table[i].count,
1731                                  invalid_table[i].written);
1732         ok(!ret, "[%d] Expected WriteConsoleInputW to return FALSE, got %d\n", i, ret);
1733         gle = GetLastError();
1734         ok(gle == invalid_table[i].gle || (gle != 0 && gle == invalid_table[i].gle2),
1735            "[%d] Expected last error to be %u or %u, got %u\n",
1736            i, invalid_table[i].gle, invalid_table[i].gle2, gle);
1737     }
1738 
1739     count = 0xdeadbeef;
1740     ret = WriteConsoleInputW(input_handle, NULL, 0, &count);
1741     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1742     ok(count == 0, "Expected count to be 0, got %u\n", count);
1743 
1744     count = 0xdeadbeef;
1745     ret = WriteConsoleInputW(input_handle, &event, 0, &count);
1746     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1747     ok(count == 0, "Expected count to be 0, got %u\n", count);
1748 
1749     count = 0xdeadbeef;
1750     ret = WriteConsoleInputW(input_handle, &event, 1, &count);
1751     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1752     ok(count == 1, "Expected count to be 1, got %u\n", count);
1753 
1754     ret = FlushConsoleInputBuffer(input_handle);
1755     ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1756 
1757     /* Writing a single mouse event doesn't seem to affect the count if an adjacent mouse event is already queued. */
1758     event.EventType = MOUSE_EVENT;
1759     event.Event.MouseEvent = mouse_event;
1760 
1761     ret = WriteConsoleInputW(input_handle, &event, 1, &count);
1762     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1763     ok(count == 1, "Expected count to be 1, got %u\n", count);
1764 
1765     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1766     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1767     ok(count == 1, "Expected count to be 1, got %u\n", count);
1768 
1769     ret = WriteConsoleInputW(input_handle, &event, 1, &count);
1770     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1771     ok(count == 1, "Expected count to be 1, got %u\n", count);
1772 
1773     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1774     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1775     todo_wine
1776     ok(count == 1, "Expected count to be 1, got %u\n", count);
1777 
1778     ret = FlushConsoleInputBuffer(input_handle);
1779     ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1780 
1781     for (i = 0; i < sizeof(event_list)/sizeof(event_list[0]); i++)
1782     {
1783         event_list[i].EventType = MOUSE_EVENT;
1784         event_list[i].Event.MouseEvent = mouse_event;
1785     }
1786 
1787     /* Writing consecutive chunks of mouse events appears to work. */
1788     ret = WriteConsoleInputW(input_handle, event_list, sizeof(event_list)/sizeof(event_list[0]), &count);
1789     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1790     ok(count == sizeof(event_list)/sizeof(event_list[0]),
1791        "Expected count to be event list length, got %u\n", count);
1792 
1793     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1794     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1795     ok(count == sizeof(event_list)/sizeof(event_list[0]),
1796        "Expected count to be event list length, got %u\n", count);
1797 
1798     ret = WriteConsoleInputW(input_handle, event_list, sizeof(event_list)/sizeof(event_list[0]), &count);
1799     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1800     ok(count == sizeof(event_list)/sizeof(event_list[0]),
1801        "Expected count to be event list length, got %u\n", count);
1802 
1803     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1804     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1805     ok(count == 2*sizeof(event_list)/sizeof(event_list[0]),
1806        "Expected count to be twice event list length, got %u\n", count);
1807 
1808     /* Again, writing a single mouse event with adjacent mouse events queued doesn't appear to affect the count. */
1809     ret = WriteConsoleInputW(input_handle, &event, 1, &count);
1810     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1811     ok(count == 1, "Expected count to be 1, got %u\n", count);
1812 
1813     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1814     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1815     todo_wine
1816     ok(count == 2*sizeof(event_list)/sizeof(event_list[0]),
1817        "Expected count to be twice event list length, got %u\n", count);
1818 
1819     ret = FlushConsoleInputBuffer(input_handle);
1820     ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1821 
1822     key_event.bKeyDown = FALSE;
1823     key_event.wRepeatCount = 0;
1824     key_event.wVirtualKeyCode = VK_SPACE;
1825     key_event.wVirtualScanCode = VK_SPACE;
1826     key_event.uChar.UnicodeChar = ' ';
1827     key_event.dwControlKeyState = 0;
1828 
1829     event.EventType = KEY_EVENT;
1830     event.Event.KeyEvent = key_event;
1831 
1832     /* Key events don't exhibit the same behavior as mouse events. */
1833     ret = WriteConsoleInputW(input_handle, &event, 1, &count);
1834     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1835     ok(count == 1, "Expected count to be 1, got %u\n", count);
1836 
1837     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1838     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1839     ok(count == 1, "Expected count to be 1, got %u\n", count);
1840 
1841     ret = WriteConsoleInputW(input_handle, &event, 1, &count);
1842     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1843     ok(count == 1, "Expected count to be 1, got %u\n", count);
1844 
1845     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1846     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1847     ok(count == 2, "Expected count to be 2, got %u\n", count);
1848 
1849     ret = FlushConsoleInputBuffer(input_handle);
1850     ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1851 
1852     /* Try interleaving mouse and key events. */
1853     event.EventType = MOUSE_EVENT;
1854     event.Event.MouseEvent = mouse_event;
1855 
1856     ret = WriteConsoleInputW(input_handle, &event, 1, &count);
1857     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1858     ok(count == 1, "Expected count to be 1, got %u\n", count);
1859 
1860     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1861     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1862     ok(count == 1, "Expected count to be 1, got %u\n", count);
1863 
1864     event.EventType = KEY_EVENT;
1865     event.Event.KeyEvent = key_event;
1866 
1867     ret = WriteConsoleInputW(input_handle, &event, 1, &count);
1868     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1869     ok(count == 1, "Expected count to be 1, got %u\n", count);
1870 
1871     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1872     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1873     ok(count == 2, "Expected count to be 2, got %u\n", count);
1874 
1875     event.EventType = MOUSE_EVENT;
1876     event.Event.MouseEvent = mouse_event;
1877 
1878     ret = WriteConsoleInputW(input_handle, &event, 1, &count);
1879     ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1880     ok(count == 1, "Expected count to be 1, got %u\n", count);
1881 
1882     ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1883     ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1884     ok(count == 3, "Expected count to be 3, got %u\n", count);
1885 
1886     /* Restore the old console mode. */
1887     ret = SetConsoleMode(input_handle, console_mode);
1888     ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret);
1889 }
1890 
test_WriteConsoleOutputCharacterA(HANDLE output_handle)1891 static void test_WriteConsoleOutputCharacterA(HANDLE output_handle)
1892 {
1893     static const char output[] = {'a', 0};
1894 
1895     COORD origin = {0, 0};
1896     DWORD count;
1897     BOOL ret;
1898     int i;
1899 
1900     const struct
1901     {
1902         HANDLE hConsoleOutput;
1903         LPCSTR str;
1904         DWORD length;
1905         COORD coord;
1906         LPDWORD lpNumCharsWritten;
1907         DWORD expected_count;
1908         DWORD last_error;
1909         int win7_crash;
1910     } invalid_table[] =
1911     {
1912         {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1913         {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
1914         {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1915         {NULL, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1916         {NULL, output, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1917         {NULL, output, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
1918         {NULL, output, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1919         {NULL, output, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
1920         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1921         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
1922         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1923         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1924         {INVALID_HANDLE_VALUE, output, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1925         {INVALID_HANDLE_VALUE, output, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
1926         {INVALID_HANDLE_VALUE, output, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1927         {INVALID_HANDLE_VALUE, output, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
1928         {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1929         {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1930         {output_handle, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1931         {output_handle, output, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1932         {output_handle, output, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1933     };
1934 
1935     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
1936     {
1937         if (invalid_table[i].win7_crash)
1938             continue;
1939 
1940         SetLastError(0xdeadbeef);
1941         if (invalid_table[i].lpNumCharsWritten) count = 0xdeadbeef;
1942         ret = WriteConsoleOutputCharacterA(invalid_table[i].hConsoleOutput,
1943                                            invalid_table[i].str,
1944                                            invalid_table[i].length,
1945                                            invalid_table[i].coord,
1946                                            invalid_table[i].lpNumCharsWritten);
1947         ok(!ret, "[%d] Expected WriteConsoleOutputCharacterA to return FALSE, got %d\n", i, ret);
1948         if (invalid_table[i].lpNumCharsWritten)
1949         {
1950             ok(count == invalid_table[i].expected_count,
1951                "[%d] Expected count to be %u, got %u\n",
1952                i, invalid_table[i].expected_count, count);
1953         }
1954         ok(GetLastError() == invalid_table[i].last_error,
1955            "[%d] Expected last error to be %u, got %u\n",
1956            i, invalid_table[i].last_error, GetLastError());
1957     }
1958 
1959     count = 0xdeadbeef;
1960     ret = WriteConsoleOutputCharacterA(output_handle, NULL, 0, origin, &count);
1961     ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret);
1962     ok(count == 0, "Expected count to be 0, got %u\n", count);
1963 
1964     count = 0xdeadbeef;
1965     ret = WriteConsoleOutputCharacterA(output_handle, output, 0, origin, &count);
1966     ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret);
1967     ok(count == 0, "Expected count to be 0, got %u\n", count);
1968 
1969     count = 0xdeadbeef;
1970     ret = WriteConsoleOutputCharacterA(output_handle, output, 1, origin, &count);
1971     ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret);
1972     ok(count == 1, "Expected count to be 1, got %u\n", count);
1973 }
1974 
test_WriteConsoleOutputCharacterW(HANDLE output_handle)1975 static void test_WriteConsoleOutputCharacterW(HANDLE output_handle)
1976 {
1977     static const WCHAR outputW[] = {'a',0};
1978 
1979     COORD origin = {0, 0};
1980     DWORD count;
1981     BOOL ret;
1982     int i;
1983 
1984     const struct
1985     {
1986         HANDLE hConsoleOutput;
1987         LPCWSTR str;
1988         DWORD length;
1989         COORD coord;
1990         LPDWORD lpNumCharsWritten;
1991         DWORD expected_count;
1992         DWORD last_error;
1993         int win7_crash;
1994     } invalid_table[] =
1995     {
1996         {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1997         {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
1998         {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
1999         {NULL, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2000         {NULL, outputW, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2001         {NULL, outputW, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2002         {NULL, outputW, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2003         {NULL, outputW, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2004         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2005         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2006         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2007         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2008         {INVALID_HANDLE_VALUE, outputW, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2009         {INVALID_HANDLE_VALUE, outputW, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2010         {INVALID_HANDLE_VALUE, outputW, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2011         {INVALID_HANDLE_VALUE, outputW, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2012         {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2013         {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2014         {output_handle, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2015         {output_handle, outputW, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2016         {output_handle, outputW, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2017     };
2018 
2019     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
2020     {
2021         if (invalid_table[i].win7_crash)
2022             continue;
2023 
2024         SetLastError(0xdeadbeef);
2025         if (invalid_table[i].lpNumCharsWritten) count = 0xdeadbeef;
2026         ret = WriteConsoleOutputCharacterW(invalid_table[i].hConsoleOutput,
2027                                            invalid_table[i].str,
2028                                            invalid_table[i].length,
2029                                            invalid_table[i].coord,
2030                                            invalid_table[i].lpNumCharsWritten);
2031         ok(!ret, "[%d] Expected WriteConsoleOutputCharacterW to return FALSE, got %d\n", i, ret);
2032         if (invalid_table[i].lpNumCharsWritten)
2033         {
2034             ok(count == invalid_table[i].expected_count,
2035                "[%d] Expected count to be %u, got %u\n",
2036                i, invalid_table[i].expected_count, count);
2037         }
2038         ok(GetLastError() == invalid_table[i].last_error,
2039            "[%d] Expected last error to be %u, got %u\n",
2040            i, invalid_table[i].last_error, GetLastError());
2041     }
2042 
2043     count = 0xdeadbeef;
2044     ret = WriteConsoleOutputCharacterW(output_handle, NULL, 0, origin, &count);
2045     ok(ret == TRUE, "Expected WriteConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2046     ok(count == 0, "Expected count to be 0, got %u\n", count);
2047 
2048     count = 0xdeadbeef;
2049     ret = WriteConsoleOutputCharacterW(output_handle, outputW, 0, origin, &count);
2050     ok(ret == TRUE, "Expected WriteConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2051     ok(count == 0, "Expected count to be 0, got %u\n", count);
2052 
2053     count = 0xdeadbeef;
2054     ret = WriteConsoleOutputCharacterW(output_handle, outputW, 1, origin, &count);
2055     ok(ret == TRUE, "Expected WriteConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2056     ok(count == 1, "Expected count to be 1, got %u\n", count);
2057 }
2058 
test_WriteConsoleOutputAttribute(HANDLE output_handle)2059 static void test_WriteConsoleOutputAttribute(HANDLE output_handle)
2060 {
2061     WORD attr = FOREGROUND_BLUE;
2062     COORD origin = {0, 0};
2063     DWORD count;
2064     BOOL ret;
2065     int i;
2066 
2067     const struct
2068     {
2069         HANDLE hConsoleOutput;
2070         const WORD *attr;
2071         DWORD length;
2072         COORD coord;
2073         LPDWORD lpNumAttrsWritten;
2074         DWORD expected_count;
2075         DWORD last_error;
2076         int win7_crash;
2077     } invalid_table[] =
2078     {
2079         {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2080         {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2081         {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2082         {NULL, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2083         {NULL, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2084         {NULL, &attr, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2085         {NULL, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2086         {NULL, &attr, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2087         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2088         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2089         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2090         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2091         {INVALID_HANDLE_VALUE, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2092         {INVALID_HANDLE_VALUE, &attr, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2093         {INVALID_HANDLE_VALUE, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2094         {INVALID_HANDLE_VALUE, &attr, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2095         {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2096         {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2097         {output_handle, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2098         {output_handle, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2099         {output_handle, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2100     };
2101 
2102     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
2103     {
2104         if (invalid_table[i].win7_crash)
2105             continue;
2106 
2107         SetLastError(0xdeadbeef);
2108         if (invalid_table[i].lpNumAttrsWritten) count = 0xdeadbeef;
2109         ret = WriteConsoleOutputAttribute(invalid_table[i].hConsoleOutput,
2110                                           invalid_table[i].attr,
2111                                           invalid_table[i].length,
2112                                           invalid_table[i].coord,
2113                                           invalid_table[i].lpNumAttrsWritten);
2114         ok(!ret, "[%d] Expected WriteConsoleOutputAttribute to return FALSE, got %d\n", i, ret);
2115         if (invalid_table[i].lpNumAttrsWritten)
2116         {
2117             ok(count == invalid_table[i].expected_count,
2118                "[%d] Expected count to be %u, got %u\n",
2119                i, invalid_table[i].expected_count, count);
2120         }
2121         ok(GetLastError() == invalid_table[i].last_error,
2122            "[%d] Expected last error to be %u, got %u\n",
2123            i, invalid_table[i].last_error, GetLastError());
2124     }
2125 
2126     count = 0xdeadbeef;
2127     ret = WriteConsoleOutputAttribute(output_handle, NULL, 0, origin, &count);
2128     ok(ret == TRUE, "Expected WriteConsoleOutputAttribute to return TRUE, got %d\n", ret);
2129     ok(count == 0, "Expected count to be 0, got %u\n", count);
2130 
2131     count = 0xdeadbeef;
2132     ret = WriteConsoleOutputAttribute(output_handle, &attr, 0, origin, &count);
2133     ok(ret == TRUE, "Expected WriteConsoleOutputAttribute to return TRUE, got %d\n", ret);
2134     ok(count == 0, "Expected count to be 0, got %u\n", count);
2135 
2136     count = 0xdeadbeef;
2137     ret = WriteConsoleOutputAttribute(output_handle, &attr, 1, origin, &count);
2138     ok(ret == TRUE, "Expected WriteConsoleOutputAttribute to return TRUE, got %d\n", ret);
2139     ok(count == 1, "Expected count to be 1, got %u\n", count);
2140 }
2141 
test_FillConsoleOutputCharacterA(HANDLE output_handle)2142 static void test_FillConsoleOutputCharacterA(HANDLE output_handle)
2143 {
2144     COORD origin = {0, 0};
2145     DWORD count;
2146     BOOL ret;
2147     int i;
2148 
2149     const struct
2150     {
2151         HANDLE hConsoleOutput;
2152         CHAR ch;
2153         DWORD length;
2154         COORD coord;
2155         LPDWORD lpNumCharsWritten;
2156         DWORD last_error;
2157         int win7_crash;
2158     } invalid_table[] =
2159     {
2160         {NULL, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2161         {NULL, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2162         {NULL, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2163         {NULL, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2164         {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2165         {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2166         {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2167         {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2168         {output_handle, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2169         {output_handle, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2170     };
2171 
2172     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
2173     {
2174         if (invalid_table[i].win7_crash)
2175             continue;
2176 
2177         SetLastError(0xdeadbeef);
2178         if (invalid_table[i].lpNumCharsWritten) count = 0xdeadbeef;
2179         ret = FillConsoleOutputCharacterA(invalid_table[i].hConsoleOutput,
2180                                           invalid_table[i].ch,
2181                                           invalid_table[i].length,
2182                                           invalid_table[i].coord,
2183                                           invalid_table[i].lpNumCharsWritten);
2184         ok(!ret, "[%d] Expected FillConsoleOutputCharacterA to return FALSE, got %d\n", i, ret);
2185         ok(GetLastError() == invalid_table[i].last_error,
2186            "[%d] Expected last error to be %u, got %u\n",
2187            i, invalid_table[i].last_error, GetLastError());
2188     }
2189 
2190     count = 0xdeadbeef;
2191     ret = FillConsoleOutputCharacterA(output_handle, 'a', 0, origin, &count);
2192     ok(ret == TRUE, "Expected FillConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2193     ok(count == 0, "Expected count to be 0, got %u\n", count);
2194 
2195     count = 0xdeadbeef;
2196     ret = FillConsoleOutputCharacterA(output_handle, 'a', 1, origin, &count);
2197     ok(ret == TRUE, "Expected FillConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2198     ok(count == 1, "Expected count to be 1, got %u\n", count);
2199 }
2200 
test_FillConsoleOutputCharacterW(HANDLE output_handle)2201 static void test_FillConsoleOutputCharacterW(HANDLE output_handle)
2202 {
2203     COORD origin = {0, 0};
2204     DWORD count;
2205     BOOL ret;
2206     int i;
2207 
2208     const struct
2209     {
2210         HANDLE hConsoleOutput;
2211         WCHAR ch;
2212         DWORD length;
2213         COORD coord;
2214         LPDWORD lpNumCharsWritten;
2215         DWORD last_error;
2216         int win7_crash;
2217     } invalid_table[] =
2218     {
2219         {NULL, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2220         {NULL, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2221         {NULL, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2222         {NULL, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2223         {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2224         {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2225         {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2226         {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2227         {output_handle, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2228         {output_handle, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2229     };
2230 
2231     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
2232     {
2233         if (invalid_table[i].win7_crash)
2234             continue;
2235 
2236         SetLastError(0xdeadbeef);
2237         if (invalid_table[i].lpNumCharsWritten) count = 0xdeadbeef;
2238         ret = FillConsoleOutputCharacterW(invalid_table[i].hConsoleOutput,
2239                                           invalid_table[i].ch,
2240                                           invalid_table[i].length,
2241                                           invalid_table[i].coord,
2242                                           invalid_table[i].lpNumCharsWritten);
2243         ok(!ret, "[%d] Expected FillConsoleOutputCharacterW to return FALSE, got %d\n", i, ret);
2244         ok(GetLastError() == invalid_table[i].last_error,
2245            "[%d] Expected last error to be %u, got %u\n",
2246            i, invalid_table[i].last_error, GetLastError());
2247     }
2248 
2249     count = 0xdeadbeef;
2250     ret = FillConsoleOutputCharacterW(output_handle, 'a', 0, origin, &count);
2251     ok(ret == TRUE, "Expected FillConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2252     ok(count == 0, "Expected count to be 0, got %u\n", count);
2253 
2254     count = 0xdeadbeef;
2255     ret = FillConsoleOutputCharacterW(output_handle, 'a', 1, origin, &count);
2256     ok(ret == TRUE, "Expected FillConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2257     ok(count == 1, "Expected count to be 1, got %u\n", count);
2258 }
2259 
test_FillConsoleOutputAttribute(HANDLE output_handle)2260 static void test_FillConsoleOutputAttribute(HANDLE output_handle)
2261 {
2262     COORD origin = {0, 0};
2263     DWORD count;
2264     BOOL ret;
2265     int i;
2266 
2267     const struct
2268     {
2269         HANDLE hConsoleOutput;
2270         WORD attr;
2271         DWORD length;
2272         COORD coord;
2273         LPDWORD lpNumAttrsWritten;
2274         DWORD last_error;
2275         int win7_crash;
2276     } invalid_table[] =
2277     {
2278         {NULL, FOREGROUND_BLUE, 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2279         {NULL, FOREGROUND_BLUE, 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2280         {NULL, FOREGROUND_BLUE, 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2281         {NULL, FOREGROUND_BLUE, 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2282         {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2283         {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2284         {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2285         {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2286         {output_handle, FOREGROUND_BLUE, 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2287         {output_handle, FOREGROUND_BLUE, 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2288     };
2289 
2290     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
2291     {
2292         if (invalid_table[i].win7_crash)
2293             continue;
2294 
2295         SetLastError(0xdeadbeef);
2296         if (invalid_table[i].lpNumAttrsWritten) count = 0xdeadbeef;
2297         ret = FillConsoleOutputAttribute(invalid_table[i].hConsoleOutput,
2298                                          invalid_table[i].attr,
2299                                          invalid_table[i].length,
2300                                          invalid_table[i].coord,
2301                                          invalid_table[i].lpNumAttrsWritten);
2302         ok(!ret, "[%d] Expected FillConsoleOutputAttribute to return FALSE, got %d\n", i, ret);
2303         ok(GetLastError() == invalid_table[i].last_error,
2304            "[%d] Expected last error to be %u, got %u\n",
2305            i, invalid_table[i].last_error, GetLastError());
2306     }
2307 
2308     count = 0xdeadbeef;
2309     ret = FillConsoleOutputAttribute(output_handle, FOREGROUND_BLUE, 0, origin, &count);
2310     ok(ret == TRUE, "Expected FillConsoleOutputAttribute to return TRUE, got %d\n", ret);
2311     ok(count == 0, "Expected count to be 0, got %u\n", count);
2312 
2313     count = 0xdeadbeef;
2314     ret = FillConsoleOutputAttribute(output_handle, FOREGROUND_BLUE, 1, origin, &count);
2315     ok(ret == TRUE, "Expected FillConsoleOutputAttribute to return TRUE, got %d\n", ret);
2316     ok(count == 1, "Expected count to be 1, got %u\n", count);
2317 
2318     count = 0xdeadbeef;
2319     ret = FillConsoleOutputAttribute(output_handle, ~0, 1, origin, &count);
2320     ok(ret == TRUE, "Expected FillConsoleOutputAttribute to return TRUE, got %d\n", ret);
2321     ok(count == 1, "Expected count to be 1, got %u\n", count);
2322 }
2323 
test_ReadConsoleOutputCharacterA(HANDLE output_handle)2324 static void test_ReadConsoleOutputCharacterA(HANDLE output_handle)
2325 {
2326     CHAR read;
2327     COORD origin = {0, 0};
2328     DWORD count;
2329     BOOL ret;
2330     int i;
2331 
2332     const struct
2333     {
2334         HANDLE hConsoleOutput;
2335         LPSTR lpstr;
2336         DWORD length;
2337         COORD coord;
2338         LPDWORD read_count;
2339         DWORD expected_count;
2340         DWORD last_error;
2341         int win7_crash;
2342     } invalid_table[] =
2343     {
2344         {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2345         {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2346         {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2347         {NULL, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
2348         {NULL, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2349         {NULL, &read, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2350         {NULL, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2351         {NULL, &read, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2352         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2353         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2354         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2355         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
2356         {INVALID_HANDLE_VALUE, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2357         {INVALID_HANDLE_VALUE, &read, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2358         {INVALID_HANDLE_VALUE, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2359         {INVALID_HANDLE_VALUE, &read, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2360         {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2361         {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2362         {output_handle, NULL, 1, {0, 0}, &count, 1, ERROR_INVALID_ACCESS, 1},
2363         {output_handle, NULL, 10, {0, 0}, &count, 10, ERROR_INVALID_ACCESS, 1},
2364         {output_handle, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2365         {output_handle, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2366     };
2367 
2368     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
2369     {
2370         if (invalid_table[i].win7_crash)
2371             continue;
2372 
2373         SetLastError(0xdeadbeef);
2374         if (invalid_table[i].read_count) count = 0xdeadbeef;
2375         ret = ReadConsoleOutputCharacterA(invalid_table[i].hConsoleOutput,
2376                                           invalid_table[i].lpstr,
2377                                           invalid_table[i].length,
2378                                           invalid_table[i].coord,
2379                                           invalid_table[i].read_count);
2380         ok(!ret, "[%d] Expected ReadConsoleOutputCharacterA to return FALSE, got %d\n", i, ret);
2381         if (invalid_table[i].read_count)
2382         {
2383             ok(count == invalid_table[i].expected_count,
2384                "[%d] Expected count to be %u, got %u\n",
2385                i, invalid_table[i].expected_count, count);
2386         }
2387         ok(GetLastError() == invalid_table[i].last_error,
2388            "[%d] Expected last error to be %u, got %u\n",
2389            i, invalid_table[i].last_error, GetLastError());
2390     }
2391 
2392     count = 0xdeadbeef;
2393     ret = ReadConsoleOutputCharacterA(output_handle, NULL, 0, origin, &count);
2394     ok(ret == TRUE, "Expected ReadConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2395     ok(count == 0, "Expected count to be 0, got %u\n", count);
2396 
2397     count = 0xdeadbeef;
2398     ret = ReadConsoleOutputCharacterA(output_handle, &read, 0, origin, &count);
2399     ok(ret == TRUE, "Expected ReadConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2400     ok(count == 0, "Expected count to be 0, got %u\n", count);
2401 
2402     count = 0xdeadbeef;
2403     ret = ReadConsoleOutputCharacterA(output_handle, &read, 1, origin, &count);
2404     ok(ret == TRUE, "Expected ReadConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2405     ok(count == 1, "Expected count to be 1, got %u\n", count);
2406 }
2407 
test_ReadConsoleOutputCharacterW(HANDLE output_handle)2408 static void test_ReadConsoleOutputCharacterW(HANDLE output_handle)
2409 {
2410     WCHAR read;
2411     COORD origin = {0, 0};
2412     DWORD count;
2413     BOOL ret;
2414     int i;
2415 
2416     const struct
2417     {
2418         HANDLE hConsoleOutput;
2419         LPWSTR buffer;
2420         DWORD length;
2421         COORD coord;
2422         LPDWORD read_count;
2423         DWORD expected_count;
2424         DWORD last_error;
2425         int win7_crash;
2426     } invalid_table[] =
2427     {
2428         {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2429         {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2430         {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2431         {NULL, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
2432         {NULL, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2433         {NULL, &read, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2434         {NULL, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2435         {NULL, &read, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2436         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2437         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2438         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2439         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
2440         {INVALID_HANDLE_VALUE, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2441         {INVALID_HANDLE_VALUE, &read, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2442         {INVALID_HANDLE_VALUE, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2443         {INVALID_HANDLE_VALUE, &read, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2444         {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2445         {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2446         {output_handle, NULL, 1, {0, 0}, &count, 1, ERROR_INVALID_ACCESS, 1},
2447         {output_handle, NULL, 10, {0, 0}, &count, 10, ERROR_INVALID_ACCESS, 1},
2448         {output_handle, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2449         {output_handle, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2450     };
2451 
2452     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
2453     {
2454         if (invalid_table[i].win7_crash)
2455             continue;
2456 
2457         SetLastError(0xdeadbeef);
2458         if (invalid_table[i].read_count) count = 0xdeadbeef;
2459         ret = ReadConsoleOutputCharacterW(invalid_table[i].hConsoleOutput,
2460                                           invalid_table[i].buffer,
2461                                           invalid_table[i].length,
2462                                           invalid_table[i].coord,
2463                                           invalid_table[i].read_count);
2464         ok(!ret, "[%d] Expected ReadConsoleOutputCharacterW to return FALSE, got %d\n", i, ret);
2465         if (invalid_table[i].read_count)
2466         {
2467             ok(count == invalid_table[i].expected_count,
2468                "[%d] Expected count to be %u, got %u\n",
2469                i, invalid_table[i].expected_count, count);
2470         }
2471         ok(GetLastError() == invalid_table[i].last_error,
2472            "[%d] Expected last error to be %u, got %u\n",
2473            i, invalid_table[i].last_error, GetLastError());
2474     }
2475 
2476     count = 0xdeadbeef;
2477     ret = ReadConsoleOutputCharacterW(output_handle, NULL, 0, origin, &count);
2478     ok(ret == TRUE, "Expected ReadConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2479     ok(count == 0, "Expected count to be 0, got %u\n", count);
2480 
2481     count = 0xdeadbeef;
2482     ret = ReadConsoleOutputCharacterW(output_handle, &read, 0, origin, &count);
2483     ok(ret == TRUE, "Expected ReadConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2484     ok(count == 0, "Expected count to be 0, got %u\n", count);
2485 
2486     count = 0xdeadbeef;
2487     ret = ReadConsoleOutputCharacterW(output_handle, &read, 1, origin, &count);
2488     ok(ret == TRUE, "Expected ReadConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2489     ok(count == 1, "Expected count to be 1, got %u\n", count);
2490 }
2491 
test_ReadConsoleOutputAttribute(HANDLE output_handle)2492 static void test_ReadConsoleOutputAttribute(HANDLE output_handle)
2493 {
2494     WORD attr;
2495     COORD origin = {0, 0};
2496     DWORD count;
2497     BOOL ret;
2498     int i;
2499 
2500     const struct
2501     {
2502         HANDLE hConsoleOutput;
2503         LPWORD lpAttribute;
2504         DWORD length;
2505         COORD coord;
2506         LPDWORD read_count;
2507         DWORD expected_count;
2508         DWORD last_error;
2509         int win7_crash;
2510     } invalid_table[] =
2511     {
2512         {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2513         {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2514         {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2515         {NULL, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
2516         {NULL, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2517         {NULL, &attr, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2518         {NULL, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2519         {NULL, &attr, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2520         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2521         {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2522         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2523         {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
2524         {INVALID_HANDLE_VALUE, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2525         {INVALID_HANDLE_VALUE, &attr, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2526         {INVALID_HANDLE_VALUE, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2527         {INVALID_HANDLE_VALUE, &attr, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2528         {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2529         {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2530         {output_handle, NULL, 1, {0, 0}, &count, 1, ERROR_INVALID_ACCESS, 1},
2531         {output_handle, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2532         {output_handle, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2533     };
2534 
2535     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
2536     {
2537         if (invalid_table[i].win7_crash)
2538             continue;
2539 
2540         SetLastError(0xdeadbeef);
2541         if (invalid_table[i].read_count) count = 0xdeadbeef;
2542         ret = ReadConsoleOutputAttribute(invalid_table[i].hConsoleOutput,
2543                                          invalid_table[i].lpAttribute,
2544                                          invalid_table[i].length,
2545                                          invalid_table[i].coord,
2546                                          invalid_table[i].read_count);
2547         ok(!ret, "[%d] Expected ReadConsoleOutputAttribute to return FALSE, got %d\n", i, ret);
2548         if (invalid_table[i].read_count)
2549         {
2550             ok(count == invalid_table[i].expected_count,
2551                "[%d] Expected count to be %u, got %u\n",
2552                i, invalid_table[i].expected_count, count);
2553         }
2554         ok(GetLastError() == invalid_table[i].last_error,
2555            "[%d] Expected last error to be %u, got %u\n",
2556            i, invalid_table[i].last_error, GetLastError());
2557     }
2558 
2559     count = 0xdeadbeef;
2560     ret = ReadConsoleOutputAttribute(output_handle, NULL, 0, origin, &count);
2561     ok(ret == TRUE, "Expected ReadConsoleOutputAttribute to return TRUE, got %d\n", ret);
2562     ok(count == 0, "Expected count to be 0, got %u\n", count);
2563 
2564     count = 0xdeadbeef;
2565     ret = ReadConsoleOutputAttribute(output_handle, &attr, 0, origin, &count);
2566     ok(ret == TRUE, "Expected ReadConsoleOutputAttribute to return TRUE, got %d\n", ret);
2567     ok(count == 0, "Expected count to be 0, got %u\n", count);
2568 
2569     count = 0xdeadbeef;
2570     ret = ReadConsoleOutputAttribute(output_handle, &attr, 1, origin, &count);
2571     ok(ret == TRUE, "Expected ReadConsoleOutputAttribute to return TRUE, got %d\n", ret);
2572     ok(count == 1, "Expected count to be 1, got %u\n", count);
2573 }
2574 
test_ReadConsole(void)2575 static void test_ReadConsole(void)
2576 {
2577     HANDLE std_input;
2578     DWORD ret, bytes;
2579     char buf[1024];
2580 
2581     std_input = GetStdHandle(STD_INPUT_HANDLE);
2582 
2583     SetLastError(0xdeadbeef);
2584     ret = GetFileSize(std_input, NULL);
2585     if (GetLastError() == 0xdeadbeef)
2586     {
2587         skip("stdin is redirected\n");
2588         return;
2589     }
2590     ok(ret == INVALID_FILE_SIZE, "expected INVALID_FILE_SIZE, got %#x\n", ret);
2591     ok(GetLastError() == ERROR_INVALID_HANDLE ||
2592        GetLastError() == ERROR_INVALID_FUNCTION, /* Win 8, 10 */
2593        "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
2594 
2595     bytes = 0xdeadbeef;
2596     SetLastError(0xdeadbeef);
2597     ret = ReadFile(std_input, buf, -128, &bytes, NULL);
2598     ok(!ret, "expected 0, got %u\n", ret);
2599     ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
2600        GetLastError() == ERROR_NOACCESS, /* Win 8, 10 */
2601        "expected ERROR_NOT_ENOUGH_MEMORY, got %d\n", GetLastError());
2602     ok(!bytes, "expected 0, got %u\n", bytes);
2603 
2604     bytes = 0xdeadbeef;
2605     SetLastError(0xdeadbeef);
2606     ret = ReadConsoleA(std_input, buf, -128, &bytes, NULL);
2607     ok(!ret, "expected 0, got %u\n", ret);
2608     ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
2609        GetLastError() == ERROR_NOACCESS, /* Win 8, 10 */
2610        "expected ERROR_NOT_ENOUGH_MEMORY, got %d\n", GetLastError());
2611     ok(bytes == 0xdeadbeef, "expected 0xdeadbeef, got %#x\n", bytes);
2612 
2613     bytes = 0xdeadbeef;
2614     SetLastError(0xdeadbeef);
2615     ret = ReadConsoleW(std_input, buf, -128, &bytes, NULL);
2616     ok(!ret, "expected 0, got %u\n", ret);
2617     ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
2618        GetLastError() == ERROR_NOACCESS, /* Win 8, 10 */
2619        "expected ERROR_NOT_ENOUGH_MEMORY, got %d\n", GetLastError());
2620     ok(bytes == 0xdeadbeef, "expected 0xdeadbeef, got %#x\n", bytes);
2621 }
2622 
test_GetCurrentConsoleFont(HANDLE std_output)2623 static void test_GetCurrentConsoleFont(HANDLE std_output)
2624 {
2625     BOOL ret;
2626     CONSOLE_FONT_INFO cfi;
2627     CONSOLE_SCREEN_BUFFER_INFO csbi;
2628     short int width, height;
2629     COORD c;
2630 
2631     memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
2632     SetLastError(0xdeadbeef);
2633     ret = GetCurrentConsoleFont(NULL, FALSE, &cfi);
2634     ok(!ret, "got %d, expected 0\n", ret);
2635     ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2636     ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
2637     ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
2638 
2639     memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
2640     SetLastError(0xdeadbeef);
2641     ret = GetCurrentConsoleFont(NULL, TRUE, &cfi);
2642     ok(!ret, "got %d, expected 0\n", ret);
2643     ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2644     ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
2645     ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
2646 
2647     memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
2648     SetLastError(0xdeadbeef);
2649     ret = GetCurrentConsoleFont(GetStdHandle(STD_INPUT_HANDLE), FALSE, &cfi);
2650     ok(!ret, "got %d, expected 0\n", ret);
2651     ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2652     ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
2653     ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
2654 
2655     memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
2656     SetLastError(0xdeadbeef);
2657     ret = GetCurrentConsoleFont(GetStdHandle(STD_INPUT_HANDLE), TRUE, &cfi);
2658     ok(!ret, "got %d, expected 0\n", ret);
2659     ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2660     ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
2661     ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
2662 
2663     memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
2664     SetLastError(0xdeadbeef);
2665     ret = GetCurrentConsoleFont(std_output, FALSE, &cfi);
2666     ok(ret, "got %d, expected non-zero\n", ret);
2667     ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
2668     GetConsoleScreenBufferInfo(std_output, &csbi);
2669     width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
2670     height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
2671     c = GetConsoleFontSize(std_output, cfi.nFont);
2672     ok(cfi.dwFontSize.X == width || cfi.dwFontSize.X == c.X /* Vista and higher */,
2673         "got %d, expected %d\n", cfi.dwFontSize.X, width);
2674     ok(cfi.dwFontSize.Y == height || cfi.dwFontSize.Y == c.Y /* Vista and higher */,
2675         "got %d, expected %d\n", cfi.dwFontSize.Y, height);
2676 
2677     memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
2678     SetLastError(0xdeadbeef);
2679     ret = GetCurrentConsoleFont(std_output, TRUE, &cfi);
2680     ok(ret, "got %d, expected non-zero\n", ret);
2681     ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
2682     ok(cfi.dwFontSize.X == csbi.dwMaximumWindowSize.X,
2683        "got %d, expected %d\n", cfi.dwFontSize.X, csbi.dwMaximumWindowSize.X);
2684     ok(cfi.dwFontSize.Y == csbi.dwMaximumWindowSize.Y,
2685        "got %d, expected %d\n", cfi.dwFontSize.Y, csbi.dwMaximumWindowSize.Y);
2686 }
2687 
test_GetConsoleFontSize(HANDLE std_output)2688 static void test_GetConsoleFontSize(HANDLE std_output)
2689 {
2690     COORD c;
2691     DWORD index = 0;
2692     CONSOLE_FONT_INFO cfi;
2693     RECT r;
2694     CONSOLE_SCREEN_BUFFER_INFO csbi;
2695     LONG font_width, font_height;
2696     HMODULE hmod;
2697     DWORD (WINAPI *pGetNumberOfConsoleFonts)(void);
2698 
2699     memset(&c, 10, sizeof(COORD));
2700     SetLastError(0xdeadbeef);
2701     c = GetConsoleFontSize(NULL, 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     memset(&c, 10, sizeof(COORD));
2707     SetLastError(0xdeadbeef);
2708     c = GetConsoleFontSize(GetStdHandle(STD_INPUT_HANDLE), index);
2709     ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2710     ok(!c.X, "got %d, expected 0\n", c.X);
2711     ok(!c.Y, "got %d, expected 0\n", c.Y);
2712 
2713     GetCurrentConsoleFont(std_output, FALSE, &cfi);
2714     memset(&c, 10, sizeof(COORD));
2715     SetLastError(0xdeadbeef);
2716     c = GetConsoleFontSize(std_output, cfi.nFont);
2717     ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
2718     GetClientRect(GetConsoleWindow(), &r);
2719     GetConsoleScreenBufferInfo(std_output, &csbi);
2720     font_width = (r.right - r.left + 1) / csbi.srWindow.Right;
2721     font_height = (r.bottom - r.top + 1) / csbi.srWindow.Bottom;
2722     ok(c.X == font_width, "got %d, expected %d\n", c.X, font_width);
2723     ok(c.Y == font_height, "got %d, expected %d\n", c.Y, font_height);
2724 
2725     hmod = GetModuleHandleA("kernel32.dll");
2726     pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts");
2727     if (!pGetNumberOfConsoleFonts)
2728     {
2729         win_skip("GetNumberOfConsoleFonts is not available\n");
2730         return;
2731     }
2732     index = pGetNumberOfConsoleFonts();
2733 
2734     memset(&c, 10, sizeof(COORD));
2735     SetLastError(0xdeadbeef);
2736     c = GetConsoleFontSize(std_output, index);
2737     ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError());
2738     ok(!c.X, "got %d, expected 0\n", c.X);
2739     ok(!c.Y, "got %d, expected 0\n", c.Y);
2740 }
2741 
test_GetLargestConsoleWindowSize(HANDLE std_output)2742 static void test_GetLargestConsoleWindowSize(HANDLE std_output)
2743 {
2744     COORD c, font;
2745     RECT r;
2746     LONG workarea_w, workarea_h, maxcon_w, maxcon_h;
2747     CONSOLE_SCREEN_BUFFER_INFO sbi;
2748     CONSOLE_FONT_INFO cfi;
2749     DWORD index, i;
2750     HMODULE hmod;
2751     BOOL ret;
2752     DWORD (WINAPI *pGetNumberOfConsoleFonts)(void);
2753     BOOL (WINAPI *pSetConsoleFont)(HANDLE, DWORD);
2754 
2755     memset(&c, 10, sizeof(COORD));
2756     SetLastError(0xdeadbeef);
2757     c = GetLargestConsoleWindowSize(NULL);
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     memset(&c, 10, sizeof(COORD));
2763     SetLastError(0xdeadbeef);
2764     c = GetLargestConsoleWindowSize(GetStdHandle(STD_INPUT_HANDLE));
2765     ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2766     ok(!c.X, "got %d, expected 0\n", c.X);
2767     ok(!c.Y, "got %d, expected 0\n", c.Y);
2768 
2769     SystemParametersInfoW(SPI_GETWORKAREA, 0, &r, 0);
2770     workarea_w = r.right - r.left;
2771     workarea_h = r.bottom - r.top - GetSystemMetrics(SM_CYCAPTION);
2772 
2773     GetCurrentConsoleFont(std_output, FALSE, &cfi);
2774     index = cfi.nFont; /* save current font index */
2775 
2776     hmod = GetModuleHandleA("kernel32.dll");
2777     pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts");
2778     if (!pGetNumberOfConsoleFonts)
2779     {
2780         win_skip("GetNumberOfConsoleFonts is not available\n");
2781         return;
2782     }
2783     pSetConsoleFont = (void *)GetProcAddress(hmod, "SetConsoleFont");
2784     if (!pSetConsoleFont)
2785     {
2786         win_skip("SetConsoleFont is not available\n");
2787         return;
2788     }
2789 
2790     for (i = 0; i < pGetNumberOfConsoleFonts(); i++)
2791     {
2792         pSetConsoleFont(std_output, i);
2793         memset(&c, 10, sizeof(COORD));
2794         SetLastError(0xdeadbeef);
2795         c = GetLargestConsoleWindowSize(std_output);
2796         ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
2797         GetCurrentConsoleFont(std_output, FALSE, &cfi);
2798         font = GetConsoleFontSize(std_output, cfi.nFont);
2799         maxcon_w = workarea_w / font.X;
2800         maxcon_h = workarea_h / font.Y;
2801         ok(c.X == maxcon_w || c.X == maxcon_w - 1 /* Win10 */, "got %d, expected %d\n", c.X, maxcon_w);
2802         ok(c.Y == maxcon_h || c.Y == maxcon_h - 1 /* Win10 */, "got %d, expected %d\n", c.Y, maxcon_h);
2803 
2804         ret = GetConsoleScreenBufferInfo(std_output, &sbi);
2805         ok(ret, "GetConsoleScreenBufferInfo failed %u\n", GetLastError());
2806         ok(sbi.dwMaximumWindowSize.X == min(c.X, sbi.dwSize.X), "got %d, expected %d\n",
2807            sbi.dwMaximumWindowSize.X, min(c.X, sbi.dwSize.X));
2808         ok(sbi.dwMaximumWindowSize.Y == min(c.Y, sbi.dwSize.Y), "got %d, expected %d\n",
2809            sbi.dwMaximumWindowSize.Y, min(c.Y, sbi.dwSize.Y));
2810     }
2811     pSetConsoleFont(std_output, index); /* restore original font size */
2812 }
2813 
test_GetConsoleFontInfo(HANDLE std_output)2814 static void test_GetConsoleFontInfo(HANDLE std_output)
2815 {
2816     HANDLE hmod;
2817     BOOL (WINAPI *pGetConsoleFontInfo)(HANDLE, BOOL, DWORD, CONSOLE_FONT_INFO *);
2818     DWORD (WINAPI *pGetNumberOfConsoleFonts)(void);
2819     DWORD num_fonts, index, i;
2820     int memsize, win_width, win_height, tmp_w, tmp_h;
2821     CONSOLE_FONT_INFO *cfi;
2822     BOOL ret;
2823     CONSOLE_SCREEN_BUFFER_INFO csbi;
2824     COORD orig_sb_size, tmp_sb_size, orig_font, tmp_font;
2825 
2826     hmod = GetModuleHandleA("kernel32.dll");
2827     pGetConsoleFontInfo = (void *)GetProcAddress(hmod, "GetConsoleFontInfo");
2828     if (!pGetConsoleFontInfo)
2829     {
2830         win_skip("GetConsoleFontInfo is not available\n");
2831         return;
2832     }
2833 
2834     pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts");
2835     if (!pGetNumberOfConsoleFonts)
2836     {
2837         win_skip("GetNumberOfConsoleFonts is not available\n");
2838         return;
2839     }
2840 
2841     num_fonts = pGetNumberOfConsoleFonts();
2842     memsize = num_fonts * sizeof(CONSOLE_FONT_INFO);
2843     cfi = HeapAlloc(GetProcessHeap(), 0, memsize);
2844     memset(cfi, 0, memsize);
2845 
2846     GetConsoleScreenBufferInfo(std_output, &csbi);
2847     orig_sb_size = csbi.dwSize;
2848     tmp_sb_size.X = csbi.dwSize.X + 3;
2849     tmp_sb_size.Y = csbi.dwSize.Y + 5;
2850     SetConsoleScreenBufferSize(std_output, tmp_sb_size);
2851 
2852     SetLastError(0xdeadbeef);
2853     ret = pGetConsoleFontInfo(NULL, FALSE, 0, cfi);
2854     ok(!ret, "got %d, expected zero\n", ret);
2855     todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2856 
2857     SetLastError(0xdeadbeef);
2858     ret = pGetConsoleFontInfo(GetStdHandle(STD_INPUT_HANDLE), FALSE, 0, cfi);
2859     ok(!ret, "got %d, expected zero\n", ret);
2860     todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2861 
2862     SetLastError(0xdeadbeef);
2863     ret = pGetConsoleFontInfo(std_output, FALSE, 0, cfi);
2864     ok(!ret, "got %d, expected zero\n", ret);
2865     todo_wine ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
2866 
2867     GetConsoleScreenBufferInfo(std_output, &csbi);
2868     win_width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
2869     win_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
2870 
2871     GetCurrentConsoleFont(std_output, FALSE, &cfi[0]);
2872     index = cfi[0].nFont;
2873     orig_font = GetConsoleFontSize(std_output, index);
2874 
2875     memset(cfi, 0, memsize);
2876     ret = pGetConsoleFontInfo(std_output, FALSE, num_fonts, cfi);
2877     todo_wine ok(ret, "got %d, expected non-zero\n", ret);
2878 
2879     todo_wine ok(cfi[index].dwFontSize.X == win_width, "got %d, expected %d\n",
2880                  cfi[index].dwFontSize.X, win_width);
2881     todo_wine ok(cfi[index].dwFontSize.Y == win_height, "got %d, expected %d\n",
2882                  cfi[index].dwFontSize.Y, win_height);
2883 
2884     for (i = 0; i < num_fonts; i++)
2885     {
2886         ok(cfi[i].nFont == i, "element out of order, got nFont %d, expected %d\n", cfi[i].nFont, i);
2887         tmp_font = GetConsoleFontSize(std_output, cfi[i].nFont);
2888         tmp_w = (double)orig_font.X / tmp_font.X * win_width;
2889         tmp_h = (double)orig_font.Y / tmp_font.Y * win_height;
2890         todo_wine ok(cfi[i].dwFontSize.X == tmp_w, "got %d, expected %d\n", cfi[i].dwFontSize.X, tmp_w);
2891         todo_wine ok(cfi[i].dwFontSize.Y == tmp_h, "got %d, expected %d\n", cfi[i].dwFontSize.Y, tmp_h);
2892     }
2893 
2894     SetLastError(0xdeadbeef);
2895     ret = pGetConsoleFontInfo(NULL, TRUE, 0, cfi);
2896     ok(!ret, "got %d, expected zero\n", ret);
2897     todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2898 
2899     SetLastError(0xdeadbeef);
2900     ret = pGetConsoleFontInfo(GetStdHandle(STD_INPUT_HANDLE), TRUE, 0, cfi);
2901     ok(!ret, "got %d, expected zero\n", ret);
2902     todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2903 
2904     SetLastError(0xdeadbeef);
2905     ret = pGetConsoleFontInfo(std_output, TRUE, 0, cfi);
2906     ok(!ret, "got %d, expected zero\n", ret);
2907     todo_wine ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
2908 
2909     memset(cfi, 0, memsize);
2910     ret = pGetConsoleFontInfo(std_output, TRUE, num_fonts, cfi);
2911     todo_wine ok(ret, "got %d, expected non-zero\n", ret);
2912 
2913     todo_wine ok(cfi[index].dwFontSize.X == csbi.dwMaximumWindowSize.X, "got %d, expected %d\n",
2914                  cfi[index].dwFontSize.X, csbi.dwMaximumWindowSize.X);
2915     todo_wine ok(cfi[index].dwFontSize.Y == csbi.dwMaximumWindowSize.Y, "got %d, expected %d\n",
2916                  cfi[index].dwFontSize.Y, csbi.dwMaximumWindowSize.Y);
2917 
2918     for (i = 0; i < num_fonts; i++)
2919     {
2920         ok(cfi[i].nFont == i, "element out of order, got nFont %d, expected %d\n", cfi[i].nFont, i);
2921         tmp_font = GetConsoleFontSize(std_output, cfi[i].nFont);
2922         tmp_w = (double)orig_font.X / tmp_font.X * csbi.dwMaximumWindowSize.X;
2923         tmp_h = (double)orig_font.Y / tmp_font.Y * csbi.dwMaximumWindowSize.Y;
2924         todo_wine ok(cfi[i].dwFontSize.X == tmp_w, "got %d, expected %d\n", cfi[i].dwFontSize.X, tmp_w);
2925         todo_wine ok(cfi[i].dwFontSize.Y == tmp_h, "got %d, expected %d\n", cfi[i].dwFontSize.Y, tmp_h);
2926      }
2927 
2928     HeapFree(GetProcessHeap(), 0, cfi);
2929     SetConsoleScreenBufferSize(std_output, orig_sb_size);
2930 }
2931 
test_SetConsoleFont(HANDLE std_output)2932 static void test_SetConsoleFont(HANDLE std_output)
2933 {
2934     HANDLE hmod;
2935     BOOL (WINAPI *pSetConsoleFont)(HANDLE, DWORD);
2936     BOOL ret;
2937     DWORD (WINAPI *pGetNumberOfConsoleFonts)(void);
2938     DWORD num_fonts;
2939 
2940     hmod = GetModuleHandleA("kernel32.dll");
2941     pSetConsoleFont = (void *)GetProcAddress(hmod, "SetConsoleFont");
2942     if (!pSetConsoleFont)
2943     {
2944         win_skip("SetConsoleFont is not available\n");
2945         return;
2946     }
2947 
2948     SetLastError(0xdeadbeef);
2949     ret = pSetConsoleFont(NULL, 0);
2950     ok(!ret, "got %d, expected zero\n", ret);
2951     todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2952 
2953     SetLastError(0xdeadbeef);
2954     ret = pSetConsoleFont(GetStdHandle(STD_INPUT_HANDLE), 0);
2955     ok(!ret, "got %d, expected zero\n", ret);
2956     todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
2957 
2958     pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts");
2959     if (!pGetNumberOfConsoleFonts)
2960     {
2961         win_skip("GetNumberOfConsoleFonts is not available\n");
2962         return;
2963     }
2964 
2965     num_fonts = pGetNumberOfConsoleFonts();
2966 
2967     SetLastError(0xdeadbeef);
2968     ret = pSetConsoleFont(std_output, num_fonts);
2969     ok(!ret, "got %d, expected zero\n", ret);
2970     todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError());
2971 }
2972 
test_GetConsoleScreenBufferInfoEx(HANDLE std_output)2973 static void test_GetConsoleScreenBufferInfoEx(HANDLE std_output)
2974 {
2975     HANDLE hmod;
2976     BOOL (WINAPI *pGetConsoleScreenBufferInfoEx)(HANDLE, CONSOLE_SCREEN_BUFFER_INFOEX *);
2977     CONSOLE_SCREEN_BUFFER_INFOEX csbix;
2978     BOOL ret;
2979     HANDLE std_input = GetStdHandle(STD_INPUT_HANDLE);
2980 
2981     hmod = GetModuleHandleA("kernel32.dll");
2982     pGetConsoleScreenBufferInfoEx = (void *)GetProcAddress(hmod, "GetConsoleScreenBufferInfoEx");
2983     if (!pGetConsoleScreenBufferInfoEx)
2984     {
2985         win_skip("GetConsoleScreenBufferInfoEx is not available\n");
2986         return;
2987     }
2988 
2989     SetLastError(0xdeadbeef);
2990     ret = pGetConsoleScreenBufferInfoEx(NULL, &csbix);
2991     ok(!ret, "got %d, expected zero\n", ret);
2992     ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError());
2993 
2994     SetLastError(0xdeadbeef);
2995     ret = pGetConsoleScreenBufferInfoEx(std_input, &csbix);
2996     ok(!ret, "got %d, expected zero\n", ret);
2997     ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError());
2998 
2999     SetLastError(0xdeadbeef);
3000     ret = pGetConsoleScreenBufferInfoEx(std_output, &csbix);
3001     ok(!ret, "got %d, expected zero\n", ret);
3002     ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError());
3003 
3004     csbix.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
3005 
3006     SetLastError(0xdeadbeef);
3007     ret = pGetConsoleScreenBufferInfoEx(NULL, &csbix);
3008     ok(!ret, "got %d, expected zero\n", ret);
3009     ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3010 
3011     SetLastError(0xdeadbeef);
3012     ret = pGetConsoleScreenBufferInfoEx(std_input, &csbix);
3013     ok(!ret, "got %d, expected zero\n", ret);
3014     ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3015 
3016     SetLastError(0xdeadbeef);
3017     ret = pGetConsoleScreenBufferInfoEx(std_output, &csbix);
3018     ok(ret, "got %d, expected non-zero\n", ret);
3019     ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
3020 }
3021 
START_TEST(console)3022 START_TEST(console)
3023 {
3024     static const char font_name[] = "Lucida Console";
3025     HANDLE hConIn, hConOut;
3026     BOOL ret;
3027     CONSOLE_SCREEN_BUFFER_INFO	sbi;
3028     LONG err;
3029     HKEY console_key;
3030     char old_font[LF_FACESIZE];
3031     BOOL delete = FALSE;
3032     DWORD size;
3033 
3034     init_function_pointers();
3035 
3036     /* be sure we have a clean console (and that's our own)
3037      * FIXME: this will make the test fail (currently) if we don't run
3038      * under X11
3039      * Another solution would be to rerun the test under wineconsole with
3040      * the curses backend
3041      */
3042 
3043     /* ReadConsoleOutputW doesn't retrieve characters from the output buffer
3044      * correctly for characters that don't have a glyph in the console font. So,
3045      * we first set the console font to Lucida Console (which has a wider
3046      * selection of glyphs available than the default raster fonts). We want
3047      * to be able to restore the original font afterwards, so don't change
3048      * if we can't read the original font.
3049      */
3050     err = RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
3051                         KEY_QUERY_VALUE | KEY_SET_VALUE, &console_key);
3052     if (err == ERROR_SUCCESS)
3053     {
3054         size = sizeof(old_font);
3055         err = RegQueryValueExA(console_key, "FaceName", NULL, NULL,
3056                                (LPBYTE) old_font, &size);
3057         if (err == ERROR_SUCCESS || err == ERROR_FILE_NOT_FOUND)
3058         {
3059             delete = (err == ERROR_FILE_NOT_FOUND);
3060             err = RegSetValueExA(console_key, "FaceName", 0, REG_SZ,
3061                                  (const BYTE *) font_name, sizeof(font_name));
3062             if (err != ERROR_SUCCESS)
3063                 trace("Unable to change default console font, error %d\n", err);
3064         }
3065         else
3066         {
3067             trace("Unable to query default console font, error %d\n", err);
3068             RegCloseKey(console_key);
3069             console_key = NULL;
3070         }
3071     }
3072     else
3073     {
3074         trace("Unable to open HKCU\\Console, error %d\n", err);
3075         console_key = NULL;
3076     }
3077 
3078     /* Now detach and open a fresh console to play with */
3079     FreeConsole();
3080     ok(AllocConsole(), "Couldn't alloc console\n");
3081 
3082     /* Restore default console font if needed */
3083     if (console_key != NULL)
3084     {
3085         if (delete)
3086             err = RegDeleteValueA(console_key, "FaceName");
3087         else
3088             err = RegSetValueExA(console_key, "FaceName", 0, REG_SZ,
3089                                  (const BYTE *) old_font, strlen(old_font) + 1);
3090         ok(err == ERROR_SUCCESS, "Unable to restore default console font, error %d\n", err);
3091     }
3092     hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
3093     hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
3094 
3095     /* now verify everything's ok */
3096     ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n");
3097     ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n");
3098 
3099     ret = GetConsoleScreenBufferInfo(hConOut, &sbi);
3100     ok(ret, "Getting sb info\n");
3101     if (!ret) return;
3102 
3103     /* Reduce the size of the buffer to the visible area plus 3 lines to speed
3104      * up the tests.
3105      */
3106     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);
3107     sbi.dwSize.Y = size = (sbi.srWindow.Bottom + 1) + 3;
3108     ret = SetConsoleScreenBufferSize(hConOut, sbi.dwSize);
3109     ok(ret, "Setting sb info\n");
3110     ret = GetConsoleScreenBufferInfo(hConOut, &sbi);
3111     ok(ret, "Getting sb info\n");
3112     ok(sbi.dwSize.Y == size, "Unexpected buffer size: %d instead of %d\n", sbi.dwSize.Y, size);
3113     if (!ret) return;
3114 
3115     test_ReadConsole();
3116     /* Non interactive tests */
3117     testCursor(hConOut, sbi.dwSize);
3118     /* test parameters (FIXME: test functionality) */
3119     testCursorInfo(hConOut);
3120     /* will test wrapped (on/off) & processed (on/off) strings output */
3121     testWrite(hConOut, sbi.dwSize);
3122     /* will test line scrolling at the bottom of the screen */
3123     /* testBottomScroll(); */
3124     /* will test all the scrolling operations */
3125     testScroll(hConOut, sbi.dwSize);
3126     /* will test sb creation / modification / codepage handling */
3127     testScreenBuffer(hConOut);
3128     /* Test waiting for a console handle */
3129     testWaitForConsoleInput(hConIn);
3130 
3131     /* clear duplicated console font table */
3132     CloseHandle(hConIn);
3133     CloseHandle(hConOut);
3134     FreeConsole();
3135     ok(AllocConsole(), "Couldn't alloc console\n");
3136     hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
3137     hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
3138     ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n");
3139     ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n");
3140 
3141     testCtrlHandler();
3142     /* still to be done: access rights & access on objects */
3143 
3144     if (!pGetConsoleInputExeNameA || !pSetConsoleInputExeNameA)
3145         win_skip("GetConsoleInputExeNameA and/or SetConsoleInputExeNameA is not available\n");
3146     else
3147         test_GetSetConsoleInputExeName();
3148 
3149     test_GetConsoleProcessList();
3150     test_OpenConsoleW();
3151     test_CreateFileW();
3152     test_OpenCON();
3153     test_VerifyConsoleIoHandle(hConOut);
3154     test_GetSetStdHandle();
3155     test_GetNumberOfConsoleInputEvents(hConIn);
3156     test_WriteConsoleInputA(hConIn);
3157     test_WriteConsoleInputW(hConIn);
3158     test_WriteConsoleOutputCharacterA(hConOut);
3159     test_WriteConsoleOutputCharacterW(hConOut);
3160     test_WriteConsoleOutputAttribute(hConOut);
3161     test_FillConsoleOutputCharacterA(hConOut);
3162     test_FillConsoleOutputCharacterW(hConOut);
3163     test_FillConsoleOutputAttribute(hConOut);
3164     test_ReadConsoleOutputCharacterA(hConOut);
3165     test_ReadConsoleOutputCharacterW(hConOut);
3166     test_ReadConsoleOutputAttribute(hConOut);
3167     test_GetCurrentConsoleFont(hConOut);
3168     test_GetConsoleFontSize(hConOut);
3169     test_GetLargestConsoleWindowSize(hConOut);
3170     test_GetConsoleFontInfo(hConOut);
3171     test_SetConsoleFont(hConOut);
3172     test_GetConsoleScreenBufferInfoEx(hConOut);
3173 }
3174