winex11.drv: Map coordinates before calling send_mouse_input.
[wine/zf.git] / dlls / kernel32 / tests / console.c
blob918ecac8ac4eec6c611cc475193a006b8c81796f
1 /*
2 * Unit tests for console API
4 * Copyright (c) 2003,2004 Eric Pouech
5 * Copyright (c) 2007 Kirill K. Smirnov
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.
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.
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
22 #include <ntstatus.h>
23 #define WIN32_NO_STATUS
24 #include <windows.h>
25 #include <winternl.h>
26 #include <winioctl.h>
27 #include <stdio.h>
29 #include "wine/test.h"
31 static void (WINAPI *pClosePseudoConsole)(HPCON);
32 static HRESULT (WINAPI *pCreatePseudoConsole)(COORD,HANDLE,HANDLE,DWORD,HPCON*);
33 static BOOL (WINAPI *pGetConsoleInputExeNameA)(DWORD, LPSTR);
34 static DWORD (WINAPI *pGetConsoleProcessList)(LPDWORD, DWORD);
35 static HANDLE (WINAPI *pOpenConsoleW)(LPCWSTR,DWORD,BOOL,DWORD);
36 static BOOL (WINAPI *pSetConsoleInputExeNameA)(LPCSTR);
37 static BOOL (WINAPI *pVerifyConsoleIoHandle)(HANDLE handle);
39 static BOOL skip_nt;
41 /* DEFAULT_ATTRIB is used for all initial filling of the console.
42 * all modifications are made with TEST_ATTRIB so that we could check
43 * what has to be modified or not
45 #define TEST_ATTRIB (BACKGROUND_BLUE | FOREGROUND_GREEN)
46 #define DEFAULT_ATTRIB (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED)
47 /* when filling the screen with non-blank chars, this macro defines
48 * what character should be at position 'c'
50 #define CONTENT(c) ('A' + (((c).Y * 17 + (c).X) % 23))
52 #define okCURSOR(hCon, c) do { \
53 CONSOLE_SCREEN_BUFFER_INFO __sbi; \
54 BOOL expect = GetConsoleScreenBufferInfo((hCon), &__sbi) && \
55 __sbi.dwCursorPosition.X == (c).X && __sbi.dwCursorPosition.Y == (c).Y; \
56 ok(expect, "Expected cursor at (%d,%d), got (%d,%d)\n", \
57 (c).X, (c).Y, __sbi.dwCursorPosition.X, __sbi.dwCursorPosition.Y); \
58 } while (0)
60 #define okCHAR(hCon, c, ch, attr) do { \
61 char __ch; WORD __attr; DWORD __len; BOOL expect; \
62 expect = ReadConsoleOutputCharacterA((hCon), &__ch, 1, (c), &__len) == 1 && __len == 1 && __ch == (ch); \
63 ok(expect, "At (%d,%d): expecting char '%c'/%02x got '%c'/%02x\n", (c).X, (c).Y, (ch), (ch), __ch, __ch); \
64 expect = ReadConsoleOutputAttribute((hCon), &__attr, 1, (c), &__len) == 1 && __len == 1 && __attr == (attr); \
65 ok(expect, "At (%d,%d): expecting attr %04x got %04x\n", (c).X, (c).Y, (attr), __attr); \
66 } while (0)
68 static void init_function_pointers(void)
70 HMODULE hKernel32;
72 #define KERNEL32_GET_PROC(func) \
73 p##func = (void *)GetProcAddress(hKernel32, #func); \
74 if(!p##func) trace("GetProcAddress(hKernel32, '%s') failed\n", #func);
76 hKernel32 = GetModuleHandleA("kernel32.dll");
77 KERNEL32_GET_PROC(ClosePseudoConsole);
78 KERNEL32_GET_PROC(CreatePseudoConsole);
79 KERNEL32_GET_PROC(GetConsoleInputExeNameA);
80 KERNEL32_GET_PROC(GetConsoleProcessList);
81 KERNEL32_GET_PROC(OpenConsoleW);
82 KERNEL32_GET_PROC(SetConsoleInputExeNameA);
83 KERNEL32_GET_PROC(VerifyConsoleIoHandle);
85 #undef KERNEL32_GET_PROC
88 static HANDLE create_unbound_handle(BOOL output, BOOL test_status)
90 OBJECT_ATTRIBUTES attr = {sizeof(attr)};
91 IO_STATUS_BLOCK iosb;
92 UNICODE_STRING name;
93 HANDLE handle;
94 NTSTATUS status;
96 attr.ObjectName = &name;
97 attr.Attributes = OBJ_INHERIT;
98 RtlInitUnicodeString( &name, output ? L"\\Device\\ConDrv\\Output" : L"\\Device\\ConDrv\\Input" );
99 status = NtCreateFile( &handle, FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE | FILE_READ_ATTRIBUTES |
100 FILE_WRITE_ATTRIBUTES, &attr, &iosb, NULL, FILE_ATTRIBUTE_NORMAL,
101 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_CREATE,
102 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
103 if (test_status) ok(!status, "NtCreateFile failed: %#x\n", status);
104 return status ? NULL : handle;
107 /* FIXME: this could be optimized on a speed point of view */
108 static void resetContent(HANDLE hCon, COORD sbSize, BOOL content)
110 COORD c;
111 WORD attr = DEFAULT_ATTRIB;
112 char ch;
113 DWORD len;
115 for (c.X = 0; c.X < sbSize.X; c.X++)
117 for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
119 ch = (content) ? CONTENT(c) : ' ';
120 WriteConsoleOutputAttribute(hCon, &attr, 1, c, &len);
121 WriteConsoleOutputCharacterA(hCon, &ch, 1, c, &len);
126 static void testCursor(HANDLE hCon, COORD sbSize)
128 COORD c;
130 c.X = c.Y = 0;
131 ok(SetConsoleCursorPosition(0, c) == 0, "No handle\n");
132 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n",
133 ERROR_INVALID_HANDLE, GetLastError());
135 c.X = c.Y = 0;
136 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
137 okCURSOR(hCon, c);
139 c.X = sbSize.X - 1;
140 c.Y = sbSize.Y - 1;
141 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in lower-right\n");
142 okCURSOR(hCon, c);
144 c.X = sbSize.X;
145 c.Y = sbSize.Y - 1;
146 ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
147 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n",
148 ERROR_INVALID_PARAMETER, GetLastError());
150 c.X = sbSize.X - 1;
151 c.Y = sbSize.Y;
152 ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
153 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n",
154 ERROR_INVALID_PARAMETER, GetLastError());
156 c.X = -1;
157 c.Y = 0;
158 ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
159 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n",
160 ERROR_INVALID_PARAMETER, GetLastError());
162 c.X = 0;
163 c.Y = -1;
164 ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
165 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n",
166 ERROR_INVALID_PARAMETER, GetLastError());
169 static void testCursorInfo(HANDLE hCon)
171 BOOL ret;
172 CONSOLE_CURSOR_INFO info;
173 HANDLE pipe1, pipe2;
175 SetLastError(0xdeadbeef);
176 ret = GetConsoleCursorInfo(NULL, NULL);
177 ok(!ret, "Expected failure\n");
178 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n",
179 ERROR_INVALID_HANDLE, GetLastError());
181 SetLastError(0xdeadbeef);
182 info.dwSize = -1;
183 ret = GetConsoleCursorInfo(NULL, &info);
184 ok(!ret, "Expected failure\n");
185 ok(info.dwSize == -1, "Expected no change for dwSize\n");
186 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n",
187 ERROR_INVALID_HANDLE, GetLastError());
189 /* Test the correct call first to distinguish between win9x and the rest */
190 SetLastError(0xdeadbeef);
191 ret = GetConsoleCursorInfo(hCon, &info);
192 ok(ret, "Expected success\n");
193 ok(info.dwSize == 25 ||
194 info.dwSize == 12 /* win9x */,
195 "Expected 12 or 25, got %d\n", info.dwSize);
196 ok(info.bVisible, "Expected the cursor to be visible\n");
197 ok(GetLastError() == 0xdeadbeef, "GetLastError: expecting %u got %u\n",
198 0xdeadbeef, GetLastError());
200 CreatePipe(&pipe1, &pipe2, NULL, 0);
201 info.dwSize = -1;
202 ret = GetConsoleCursorInfo(pipe1, &info);
203 ok(!ret, "Expected failure\n");
204 ok(info.dwSize == -1, "Expected no change for dwSize\n");
205 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: %u\n", GetLastError());
206 CloseHandle(pipe1);
207 CloseHandle(pipe2);
209 /* Don't test NULL CONSOLE_CURSOR_INFO, it crashes on win9x and win7 */
212 static void testEmptyWrite(HANDLE hCon)
214 static const char emptybuf[16];
215 COORD c;
216 DWORD len;
218 c.X = c.Y = 0;
219 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
221 len = -1;
222 ok(WriteConsoleA(hCon, NULL, 0, &len, NULL) != 0 && len == 0, "WriteConsole\n");
223 okCURSOR(hCon, c);
225 /* Passing a NULL lpBuffer with sufficiently large non-zero length succeeds
226 * on native Windows and result in memory-like contents being written to
227 * the console. Calling WriteConsoleW like this will crash on Wine. */
228 if (0)
230 len = -1;
231 ok(!WriteConsoleA(hCon, NULL, 16, &len, NULL) && len == -1, "WriteConsole\n");
232 okCURSOR(hCon, c);
234 /* Cursor advances for this call. */
235 len = -1;
236 ok(WriteConsoleA(hCon, NULL, 128, &len, NULL) != 0 && len == 128, "WriteConsole\n");
239 len = -1;
240 ok(WriteConsoleA(hCon, emptybuf, 0, &len, NULL) != 0 && len == 0, "WriteConsole\n");
241 okCURSOR(hCon, c);
243 /* WriteConsole does not halt on a null terminator and is happy to write
244 * memory contents beyond the actual size of the buffer. */
245 len = -1;
246 ok(WriteConsoleA(hCon, emptybuf, 16, &len, NULL) != 0 && len == 16, "WriteConsole\n");
247 c.X += 16;
248 okCURSOR(hCon, c);
251 static void simple_write_console(HANDLE console, const char *text)
253 DWORD len;
254 COORD c = {0, 0};
255 BOOL ret;
257 /* single line write */
258 c.X = c.Y = 0;
259 ok(SetConsoleCursorPosition(console, c) != 0, "Cursor in upper-left\n");
261 ret = WriteConsoleA(console, text, strlen(text), &len, NULL);
262 ok(ret, "WriteConsoleA failed: %u\n", GetLastError());
263 ok(len == strlen(text), "unexpected len %u\n", len);
266 static void testWriteSimple(HANDLE hCon)
268 const char* mytest = "abcdefg";
269 int mylen = strlen(mytest);
270 COORD c = {0, 0};
271 DWORD len;
272 BOOL ret;
274 simple_write_console(hCon, mytest);
276 for (c.X = 0; c.X < mylen; c.X++)
278 okCHAR(hCon, c, mytest[c.X], TEST_ATTRIB);
281 okCURSOR(hCon, c);
282 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
284 ret = WriteFile(hCon, mytest, mylen, &len, NULL);
285 ok(ret, "WriteFile failed: %u\n", GetLastError());
286 ok(len == mylen, "unexpected len = %u\n", len);
288 for (c.X = 0; c.X < 2 * mylen; c.X++)
290 okCHAR(hCon, c, mytest[c.X % mylen], TEST_ATTRIB);
293 okCURSOR(hCon, c);
294 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
297 static void testWriteNotWrappedNotProcessed(HANDLE hCon, COORD sbSize)
299 COORD c;
300 DWORD len, mode;
301 const char* mytest = "123";
302 const int mylen = strlen(mytest);
303 int ret;
304 int p;
306 ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode & ~(ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT)),
307 "clearing wrap at EOL & processed output\n");
309 /* write line, wrapping disabled, buffer exceeds sb width */
310 c.X = sbSize.X - 3; c.Y = 0;
311 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
313 ret = WriteConsoleA(hCon, mytest, mylen, &len, NULL);
314 ok(ret != 0 && len == mylen, "Couldn't write, ret = %d, len = %d\n", ret, len);
315 c.Y = 0;
316 for (p = mylen - 3; p < mylen; p++)
318 c.X = sbSize.X - 3 + p % 3;
319 okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
322 c.X = 0; c.Y = 1;
323 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
325 p = sbSize.X - 3 + mylen % 3;
326 c.X = p; c.Y = 0;
328 /* write line, wrapping disabled, strings end on end of line */
329 c.X = sbSize.X - mylen; c.Y = 0;
330 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
332 ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
335 static void testWriteNotWrappedProcessed(HANDLE hCon, COORD sbSize)
337 COORD c;
338 DWORD len, mode;
339 const char* mytest = "abcd\nf\tg";
340 const int mylen = strlen(mytest);
341 const int mylen2 = strchr(mytest, '\n') - mytest;
342 int p;
343 WORD attr;
345 ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, (mode | ENABLE_PROCESSED_OUTPUT) &
346 ~(ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING)),
347 "clearing wrap at EOL & setting processed output\n");
349 /* write line, wrapping disabled, buffer exceeds sb width */
350 c.X = sbSize.X - 5; c.Y = 0;
351 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-5\n");
353 ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
354 c.Y = 0;
355 for (c.X = sbSize.X - 5; c.X < sbSize.X - 1; c.X++)
357 okCHAR(hCon, c, mytest[c.X - sbSize.X + 5], TEST_ATTRIB);
360 ReadConsoleOutputAttribute(hCon, &attr, 1, c, &len);
361 /* Win9x and WinMe change the attribs for '\n' up to 'f' */
362 if (attr == TEST_ATTRIB)
364 win_skip("Win9x/WinMe don't respect ~ENABLE_WRAP_AT_EOL_OUTPUT\n");
365 return;
368 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
370 c.X = 0; c.Y++;
371 okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
372 for (c.X = 1; c.X < 8; c.X++)
373 okCHAR(hCon, c, ' ', TEST_ATTRIB);
374 okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
375 c.X++;
376 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
378 okCURSOR(hCon, c);
380 /* write line, wrapping disabled, strings end on end of line */
381 c.X = sbSize.X - 4; c.Y = 0;
382 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-4\n");
384 ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
385 c.Y = 0;
386 for (c.X = sbSize.X - 4; c.X < sbSize.X; c.X++)
388 okCHAR(hCon, c, mytest[c.X - sbSize.X + 4], TEST_ATTRIB);
390 c.X = 0; c.Y++;
391 okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
392 for (c.X = 1; c.X < 8; c.X++)
393 okCHAR(hCon, c, ' ', TEST_ATTRIB);
394 okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
395 c.X++;
396 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
398 okCURSOR(hCon, c);
400 /* write line, wrapping disabled, strings end after end of line */
401 c.X = sbSize.X - 3; c.Y = 0;
402 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-4\n");
404 ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
405 c.Y = 0;
406 for (p = mylen2 - 3; p < mylen2; p++)
408 c.X = sbSize.X - 3 + p % 3;
409 okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
411 c.X = 0; c.Y = 1;
412 okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
413 for (c.X = 1; c.X < 8; c.X++)
414 okCHAR(hCon, c, ' ', TEST_ATTRIB);
415 okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
416 c.X++;
417 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
419 okCURSOR(hCon, c);
422 static void testWriteWrappedNotProcessed(HANDLE hCon, COORD sbSize)
424 COORD c;
425 DWORD len, mode;
426 const char* mytest = "abcd\nf\tg";
427 const int mylen = strlen(mytest);
428 int p;
430 ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon,(mode | ENABLE_WRAP_AT_EOL_OUTPUT) & ~(ENABLE_PROCESSED_OUTPUT)),
431 "setting wrap at EOL & clearing processed output\n");
433 /* write line, wrapping enabled, buffer doesn't exceed sb width */
434 c.X = sbSize.X - 9; c.Y = 0;
435 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-9\n");
437 ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
438 c.Y = 0;
439 for (p = 0; p < mylen; p++)
441 c.X = sbSize.X - 9 + p;
442 okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
444 c.X = sbSize.X - 9 + mylen;
445 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
446 c.X = 0; c.Y = 1;
447 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
449 /* write line, wrapping enabled, buffer does exceed sb width */
450 c.X = sbSize.X - 3; c.Y = 0;
451 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
453 c.Y = 1;
454 c.X = mylen - 3;
455 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
458 static void testWriteWrappedProcessed(HANDLE hCon, COORD sbSize)
460 COORD c;
461 DWORD len, mode;
462 const char* mytest = "abcd\nf\tg";
463 const int mylen = strlen(mytest);
464 int p;
465 WORD attr;
467 ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode | (ENABLE_WRAP_AT_EOL_OUTPUT|ENABLE_PROCESSED_OUTPUT)),
468 "setting wrap at EOL & processed output\n");
470 /* write line, wrapping enabled, buffer doesn't exceed sb width */
471 c.X = sbSize.X - 9; c.Y = 0;
472 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-9\n");
474 ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
475 for (p = 0; p < 4; p++)
477 c.X = sbSize.X - 9 + p;
478 okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
480 c.X = sbSize.X - 9 + p;
481 ReadConsoleOutputAttribute(hCon, &attr, 1, c, &len);
482 if (attr == TEST_ATTRIB)
483 win_skip("Win9x/WinMe changes attribs for '\\n' up to 'f'\n");
484 else
485 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
486 c.X = 0; c.Y++;
487 okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
488 for (c.X = 1; c.X < 8; c.X++)
489 okCHAR(hCon, c, ' ', TEST_ATTRIB);
490 okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
491 c.X++;
492 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
493 okCURSOR(hCon, c);
495 /* write line, wrapping enabled, buffer does exceed sb width */
496 c.X = sbSize.X - 3; c.Y = 2;
497 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
499 ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
500 for (p = 0; p < 3; p++)
502 c.X = sbSize.X - 3 + p;
503 okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
505 c.X = 0; c.Y++;
506 okCHAR(hCon, c, mytest[3], TEST_ATTRIB);
507 c.X++;
508 ReadConsoleOutputAttribute(hCon, &attr, 1, c, &len);
509 if (attr == TEST_ATTRIB)
510 win_skip("Win9x/WinMe changes attribs for '\\n' up to 'f'\n");
511 else
512 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
514 c.X = 0; c.Y++;
515 okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
516 for (c.X = 1; c.X < 8; c.X++)
517 okCHAR(hCon, c, ' ', TEST_ATTRIB);
518 okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
519 c.X++;
520 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
521 okCURSOR(hCon, c);
524 static void testWrite(HANDLE hCon, COORD sbSize)
526 /* FIXME: should in fact ensure that the sb is at least 10 characters wide */
527 ok(SetConsoleTextAttribute(hCon, TEST_ATTRIB), "Setting default text color\n");
528 resetContent(hCon, sbSize, FALSE);
529 testEmptyWrite(hCon);
530 resetContent(hCon, sbSize, FALSE);
531 testWriteSimple(hCon);
532 resetContent(hCon, sbSize, FALSE);
533 testWriteNotWrappedNotProcessed(hCon, sbSize);
534 resetContent(hCon, sbSize, FALSE);
535 testWriteNotWrappedProcessed(hCon, sbSize);
536 resetContent(hCon, sbSize, FALSE);
537 testWriteWrappedNotProcessed(hCon, sbSize);
538 resetContent(hCon, sbSize, FALSE);
539 testWriteWrappedProcessed(hCon, sbSize);
542 static void testScroll(HANDLE hCon, COORD sbSize)
544 SMALL_RECT scroll, clip;
545 COORD dst, c, tc;
546 CHAR_INFO ci;
547 BOOL ret;
549 #define W 11
550 #define H 7
552 #define IN_SRECT(r,c) ((r).Left <= (c).X && (c).X <= (r).Right && (r).Top <= (c).Y && (c).Y <= (r).Bottom)
553 #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)
555 /* no clipping, src & dst rect don't overlap */
556 resetContent(hCon, sbSize, TRUE);
558 scroll.Left = 0;
559 scroll.Right = W - 1;
560 scroll.Top = 0;
561 scroll.Bottom = H - 1;
562 dst.X = W + 3;
563 dst.Y = H + 3;
564 ci.Char.UnicodeChar = '#';
565 ci.Attributes = TEST_ATTRIB;
567 clip.Left = 0;
568 clip.Right = sbSize.X - 1;
569 clip.Top = 0;
570 clip.Bottom = sbSize.Y - 1;
572 ok(ScrollConsoleScreenBufferA(hCon, &scroll, NULL, dst, &ci), "Scrolling SB\n");
574 for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
576 for (c.X = 0; c.X < sbSize.X; c.X++)
578 if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
580 tc.X = c.X - dst.X;
581 tc.Y = c.Y - dst.Y;
582 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
584 else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
585 okCHAR(hCon, c, '#', TEST_ATTRIB);
586 else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
590 /* no clipping, src & dst rect do overlap */
591 resetContent(hCon, sbSize, TRUE);
593 scroll.Left = 0;
594 scroll.Right = W - 1;
595 scroll.Top = 0;
596 scroll.Bottom = H - 1;
597 dst.X = W /2;
598 dst.Y = H / 2;
599 ci.Char.UnicodeChar = '#';
600 ci.Attributes = TEST_ATTRIB;
602 clip.Left = 0;
603 clip.Right = sbSize.X - 1;
604 clip.Top = 0;
605 clip.Bottom = sbSize.Y - 1;
607 ok(ScrollConsoleScreenBufferA(hCon, &scroll, NULL, dst, &ci), "Scrolling SB\n");
609 for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
611 for (c.X = 0; c.X < sbSize.X; c.X++)
613 if (dst.X <= c.X && c.X < dst.X + W && dst.Y <= c.Y && c.Y < dst.Y + H)
615 tc.X = c.X - dst.X;
616 tc.Y = c.Y - dst.Y;
617 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
619 else if (c.X < W && c.Y < H) okCHAR(hCon, c, '#', TEST_ATTRIB);
620 else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
624 /* clipping, src & dst rect don't overlap */
625 resetContent(hCon, sbSize, TRUE);
627 scroll.Left = 0;
628 scroll.Right = W - 1;
629 scroll.Top = 0;
630 scroll.Bottom = H - 1;
631 dst.X = W + 3;
632 dst.Y = H + 3;
633 ci.Char.UnicodeChar = '#';
634 ci.Attributes = TEST_ATTRIB;
636 clip.Left = W / 2;
637 clip.Right = min(W + W / 2, sbSize.X - 1);
638 clip.Top = H / 2;
639 clip.Bottom = min(H + H / 2, sbSize.Y - 1);
641 SetLastError(0xdeadbeef);
642 ret = ScrollConsoleScreenBufferA(hCon, &scroll, &clip, dst, &ci);
643 if (ret)
645 for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
647 for (c.X = 0; c.X < sbSize.X; c.X++)
649 if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
651 tc.X = c.X - dst.X;
652 tc.Y = c.Y - dst.Y;
653 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
655 else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
656 okCHAR(hCon, c, '#', TEST_ATTRIB);
657 else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
661 else
663 /* Win9x will fail, Only accept ERROR_NOT_ENOUGH_MEMORY */
664 ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY,
665 "Expected ERROR_NOT_ENOUGH_MEMORY, got %u\n", GetLastError());
668 /* clipping, src & dst rect do overlap */
669 resetContent(hCon, sbSize, TRUE);
671 scroll.Left = 0;
672 scroll.Right = W - 1;
673 scroll.Top = 0;
674 scroll.Bottom = H - 1;
675 dst.X = W / 2 - 3;
676 dst.Y = H / 2 - 3;
677 ci.Char.UnicodeChar = '#';
678 ci.Attributes = TEST_ATTRIB;
680 clip.Left = W / 2;
681 clip.Right = min(W + W / 2, sbSize.X - 1);
682 clip.Top = H / 2;
683 clip.Bottom = min(H + H / 2, sbSize.Y - 1);
685 ret = ScrollConsoleScreenBufferA(hCon, &scroll, &clip, dst, &ci);
686 ok(ret, "ScrollConsoleScreenBufferA failed: %u\n", GetLastError());
688 for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
690 for (c.X = 0; c.X < sbSize.X; c.X++)
692 if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
694 tc.X = c.X - dst.X;
695 tc.Y = c.Y - dst.Y;
696 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
698 else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
699 okCHAR(hCon, c, '#', TEST_ATTRIB);
700 else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
705 static int mch_count;
706 /* we need the event as Wine console event generation isn't synchronous
707 * (ie GenerateConsoleCtrlEvent returns before all ctrl-handlers in all
708 * processes have been called).
710 static HANDLE mch_event;
711 static BOOL WINAPI mch(DWORD event)
713 mch_count++;
714 SetEvent(mch_event);
715 return TRUE;
718 static void testCtrlHandler(void)
720 ok(!SetConsoleCtrlHandler(mch, FALSE), "Shouldn't succeed\n");
721 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %u\n", GetLastError());
722 ok(SetConsoleCtrlHandler(mch, TRUE), "Couldn't set handler\n");
723 /* wine requires the event for the test, as we cannot ensure, so far, that
724 * events are processed synchronously in GenerateConsoleCtrlEvent()
726 mch_event = CreateEventA(NULL, TRUE, FALSE, NULL);
727 mch_count = 0;
728 ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n");
729 /* FIXME: it isn't synchronous on wine but it can still happen before we test */
730 if (0) ok(mch_count == 1, "Event isn't synchronous\n");
731 ok(WaitForSingleObject(mch_event, 3000) == WAIT_OBJECT_0, "event sending didn't work\n");
732 CloseHandle(mch_event);
734 /* Turning off ctrl-c handling doesn't work on win9x such way ... */
735 ok(SetConsoleCtrlHandler(NULL, TRUE), "Couldn't turn off ctrl-c handling\n");
736 mch_event = CreateEventA(NULL, TRUE, FALSE, NULL);
737 mch_count = 0;
738 if(!(GetVersion() & 0x80000000))
739 /* ... and next line leads to an unhandled exception on 9x. Avoid it on 9x. */
740 ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n");
741 ok(WaitForSingleObject(mch_event, 3000) == WAIT_TIMEOUT && mch_count == 0, "Event shouldn't have been sent\n");
742 CloseHandle(mch_event);
743 ok(SetConsoleCtrlHandler(mch, FALSE), "Couldn't remove handler\n");
744 ok(!SetConsoleCtrlHandler(mch, FALSE), "Shouldn't succeed\n");
745 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %u\n", GetLastError());
749 * Test console screen buffer:
750 * 1) Try to set invalid handle.
751 * 2) Try to set non-console handles.
752 * 3) Use CONOUT$ file as active SB.
753 * 4) Test cursor.
754 * 5) Test output codepage to show it is not a property of SB.
755 * 6) Test switching to old SB if we close all handles to current SB - works
756 * in Windows, TODO in wine.
758 * What is not tested but should be:
759 * 1) ScreenBufferInfo
761 static void testScreenBuffer(HANDLE hConOut)
763 HANDLE hConOutRW, hConOutRO, hConOutWT;
764 HANDLE hFileOutRW, hFileOutRO, hFileOutWT;
765 HANDLE hConOutNew;
766 char test_str1[] = "Test for SB1";
767 char test_str2[] = "Test for SB2";
768 char test_cp866[] = {0xe2, 0xa5, 0xe1, 0xe2, 0};
769 char test_cp1251[] = {0xf2, 0xe5, 0xf1, 0xf2, 0};
770 WCHAR test_unicode[] = {0x0442, 0x0435, 0x0441, 0x0442, 0};
771 WCHAR str_wbuf[20];
772 char str_buf[20];
773 DWORD len, error;
774 COORD c;
775 BOOL ret;
776 DWORD oldcp;
778 if (!IsValidCodePage(866))
780 skip("Codepage 866 not available\n");
781 return;
784 /* In the beginning set output codepage to 866 */
785 oldcp = GetConsoleOutputCP();
786 SetLastError(0xdeadbeef);
787 ret = SetConsoleOutputCP(866);
788 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
790 win_skip("SetConsoleOutputCP is not implemented\n");
791 return;
793 ok(ret, "Cannot set output codepage to 866\n");
795 hConOutRW = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
796 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
797 CONSOLE_TEXTMODE_BUFFER, NULL);
798 ok(hConOutRW != INVALID_HANDLE_VALUE,
799 "Cannot create a new screen buffer for ReadWrite\n");
800 hConOutRO = CreateConsoleScreenBuffer(GENERIC_READ,
801 FILE_SHARE_READ, NULL,
802 CONSOLE_TEXTMODE_BUFFER, NULL);
803 ok(hConOutRO != INVALID_HANDLE_VALUE,
804 "Cannot create a new screen buffer for ReadOnly\n");
805 hConOutWT = CreateConsoleScreenBuffer(GENERIC_WRITE,
806 FILE_SHARE_WRITE, NULL,
807 CONSOLE_TEXTMODE_BUFFER, NULL);
808 ok(hConOutWT != INVALID_HANDLE_VALUE,
809 "Cannot create a new screen buffer for WriteOnly\n");
811 hFileOutRW = CreateFileA("NUL", GENERIC_READ | GENERIC_WRITE,
812 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
813 OPEN_EXISTING, 0, NULL);
814 ok(hFileOutRW != INVALID_HANDLE_VALUE, "Cannot open NUL for ReadWrite\n");
815 hFileOutRO = CreateFileA("NUL", GENERIC_READ, FILE_SHARE_READ,
816 NULL, OPEN_EXISTING, 0, NULL);
817 ok(hFileOutRO != INVALID_HANDLE_VALUE, "Cannot open NUL for ReadOnly\n");
818 hFileOutWT = CreateFileA("NUL", GENERIC_WRITE, FILE_SHARE_WRITE,
819 NULL, OPEN_EXISTING, 0, NULL);
820 ok(hFileOutWT != INVALID_HANDLE_VALUE, "Cannot open NUL for WriteOnly\n");
822 /* Trying to set invalid handle */
823 SetLastError(0);
824 ok(!SetConsoleActiveScreenBuffer(INVALID_HANDLE_VALUE),
825 "Shouldn't succeed\n");
826 ok(GetLastError() == ERROR_INVALID_HANDLE,
827 "GetLastError: expecting %u got %u\n",
828 ERROR_INVALID_HANDLE, GetLastError());
830 /* Trying to set non-console handles */
831 SetLastError(0);
832 ok(!SetConsoleActiveScreenBuffer(hFileOutRW), "Shouldn't succeed\n");
833 ok(GetLastError() == ERROR_INVALID_HANDLE,
834 "GetLastError: expecting %u got %u\n",
835 ERROR_INVALID_HANDLE, GetLastError());
837 SetLastError(0);
838 ok(!SetConsoleActiveScreenBuffer(hFileOutRO), "Shouldn't succeed\n");
839 ok(GetLastError() == ERROR_INVALID_HANDLE,
840 "GetLastError: expecting %u got %u\n",
841 ERROR_INVALID_HANDLE, GetLastError());
843 SetLastError(0);
844 ok(!SetConsoleActiveScreenBuffer(hFileOutWT), "Shouldn't succeed\n");
845 ok(GetLastError() == ERROR_INVALID_HANDLE,
846 "GetLastError: expecting %u got %u\n",
847 ERROR_INVALID_HANDLE, GetLastError());
849 /* trying to write non-console handle */
850 SetLastError(0xdeadbeef);
851 ret = WriteConsoleA(hFileOutRW, test_str1, lstrlenA(test_str1), &len, NULL);
852 error = GetLastError();
853 ok(!ret, "Shouldn't succeed\n");
854 ok(error == ERROR_INVALID_HANDLE || error == ERROR_INVALID_FUNCTION,
855 "GetLastError: got %u\n", error);
857 SetLastError(0xdeadbeef);
858 ret = WriteConsoleA(hFileOutRO, test_str1, lstrlenA(test_str1), &len, NULL);
859 error = GetLastError();
860 ok(!ret, "Shouldn't succeed\n");
861 ok(error == ERROR_INVALID_HANDLE || error == ERROR_INVALID_FUNCTION,
862 "GetLastError: got %u\n", error);
864 SetLastError(0xdeadbeef);
865 ret = WriteConsoleA(hFileOutWT, test_str1, lstrlenA(test_str1), &len, NULL);
866 error = GetLastError();
867 ok(!ret, "Shouldn't succeed\n");
868 ok(error == ERROR_INVALID_HANDLE || error == ERROR_INVALID_FUNCTION,
869 "GetLastError: got %u\n", error);
871 CloseHandle(hFileOutRW);
872 CloseHandle(hFileOutRO);
873 CloseHandle(hFileOutWT);
875 /* Trying to set SB handles with various access modes */
876 SetLastError(0);
877 ok(!SetConsoleActiveScreenBuffer(hConOutRO), "Shouldn't succeed\n");
878 ok(GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == ERROR_ACCESS_DENIED) /* win10 1809 */,
879 "unexpected last error %u\n", GetLastError());
881 ok(SetConsoleActiveScreenBuffer(hConOutWT), "Couldn't set new WriteOnly SB\n");
883 ok(SetConsoleActiveScreenBuffer(hConOutRW), "Couldn't set new ReadWrite SB\n");
885 CloseHandle(hConOutWT);
886 CloseHandle(hConOutRO);
888 /* Now we have two ReadWrite SB, active must be hConOutRW */
889 /* Open current SB via CONOUT$ */
890 hConOutNew = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0,
891 NULL, OPEN_EXISTING, 0, 0);
892 ok(hConOutNew != INVALID_HANDLE_VALUE, "CONOUT$ is not opened\n");
895 /* test cursor */
896 c.X = c.Y = 10;
897 SetConsoleCursorPosition(hConOut, c);
898 c.X = c.Y = 5;
899 SetConsoleCursorPosition(hConOutRW, c);
900 okCURSOR(hConOutNew, c);
901 c.X = c.Y = 10;
902 okCURSOR(hConOut, c);
905 c.X = c.Y = 0;
907 /* Write using hConOutNew... */
908 SetConsoleCursorPosition(hConOutNew, c);
909 ret = WriteConsoleA(hConOutNew, test_str2, lstrlenA(test_str2), &len, NULL);
910 ok (ret && len == lstrlenA(test_str2), "WriteConsoleA failed\n");
911 /* ... and read it back via hConOutRW */
912 ret = ReadConsoleOutputCharacterA(hConOutRW, str_buf, lstrlenA(test_str2), c, &len);
913 ok(ret && len == lstrlenA(test_str2), "ReadConsoleOutputCharacterA failed\n");
914 str_buf[lstrlenA(test_str2)] = 0;
915 ok(!lstrcmpA(str_buf, test_str2), "got '%s' expected '%s'\n", str_buf, test_str2);
918 /* Now test output codepage handling. Current is 866 as we set earlier. */
919 SetConsoleCursorPosition(hConOutRW, c);
920 ret = WriteConsoleA(hConOutRW, test_cp866, lstrlenA(test_cp866), &len, NULL);
921 ok(ret && len == lstrlenA(test_cp866), "WriteConsoleA failed\n");
922 ret = ReadConsoleOutputCharacterW(hConOutRW, str_wbuf, lstrlenA(test_cp866), c, &len);
923 ok(ret && len == lstrlenA(test_cp866), "ReadConsoleOutputCharacterW failed\n");
924 str_wbuf[lstrlenA(test_cp866)] = 0;
925 ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n");
928 * cp866 is OK, let's switch to cp1251.
929 * We expect that this codepage will be used in every SB - active and not.
931 ok(SetConsoleOutputCP(1251), "Cannot set output cp to 1251\n");
932 SetConsoleCursorPosition(hConOutRW, c);
933 ret = WriteConsoleA(hConOutRW, test_cp1251, lstrlenA(test_cp1251), &len, NULL);
934 ok(ret && len == lstrlenA(test_cp1251), "WriteConsoleA failed\n");
935 ret = ReadConsoleOutputCharacterW(hConOutRW, str_wbuf, lstrlenA(test_cp1251), c, &len);
936 ok(ret && len == lstrlenA(test_cp1251), "ReadConsoleOutputCharacterW failed\n");
937 str_wbuf[lstrlenA(test_cp1251)] = 0;
938 ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n");
940 /* Check what has happened to hConOut. */
941 SetConsoleCursorPosition(hConOut, c);
942 ret = WriteConsoleA(hConOut, test_cp1251, lstrlenA(test_cp1251), &len, NULL);
943 ok(ret && len == lstrlenA(test_cp1251), "WriteConsoleA failed\n");
944 ret = ReadConsoleOutputCharacterW(hConOut, str_wbuf, lstrlenA(test_cp1251), c, &len);
945 ok(ret && len == lstrlenA(test_cp1251), "ReadConsoleOutputCharacterW failed\n");
946 str_wbuf[lstrlenA(test_cp1251)] = 0;
947 ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n");
949 /* Close all handles of current console SB */
950 CloseHandle(hConOutNew);
951 CloseHandle(hConOutRW);
953 /* Now active SB should be hConOut */
954 hConOutNew = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0,
955 NULL, OPEN_EXISTING, 0, 0);
956 ok(hConOutNew != INVALID_HANDLE_VALUE, "CONOUT$ is not opened\n");
958 /* Write using hConOutNew... */
959 SetConsoleCursorPosition(hConOutNew, c);
960 ret = WriteConsoleA(hConOutNew, test_str1, lstrlenA(test_str1), &len, NULL);
961 ok (ret && len == lstrlenA(test_str1), "WriteConsoleA failed\n");
962 /* ... and read it back via hConOut */
963 ret = ReadConsoleOutputCharacterA(hConOut, str_buf, lstrlenA(test_str1), c, &len);
964 ok(ret && len == lstrlenA(test_str1), "ReadConsoleOutputCharacterA failed\n");
965 str_buf[lstrlenA(test_str1)] = 0;
966 todo_wine ok(!lstrcmpA(str_buf, test_str1), "got '%s' expected '%s'\n", str_buf, test_str1);
967 CloseHandle(hConOutNew);
969 /* This is not really needed under Windows */
970 SetConsoleActiveScreenBuffer(hConOut);
972 /* restore codepage */
973 SetConsoleOutputCP(oldcp);
976 static void CALLBACK signaled_function(void *p, BOOLEAN timeout)
978 HANDLE event = p;
979 SetEvent(event);
980 ok(!timeout, "wait shouldn't have timed out\n");
983 static void testWaitForConsoleInput(HANDLE input_handle)
985 HANDLE wait_handle;
986 HANDLE complete_event;
987 INPUT_RECORD record;
988 DWORD events_written;
989 DWORD wait_ret;
990 BOOL ret;
992 complete_event = CreateEventW(NULL, FALSE, FALSE, NULL);
994 /* Test success case */
995 ret = RegisterWaitForSingleObject(&wait_handle, input_handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
996 ok(ret == TRUE, "Expected RegisterWaitForSingleObject to return TRUE, got %d\n", ret);
997 /* give worker thread a chance to start up */
998 Sleep(100);
999 record.EventType = KEY_EVENT;
1000 record.Event.KeyEvent.bKeyDown = 1;
1001 record.Event.KeyEvent.wRepeatCount = 1;
1002 record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
1003 record.Event.KeyEvent.wVirtualScanCode = VK_RETURN;
1004 record.Event.KeyEvent.uChar.UnicodeChar = '\r';
1005 record.Event.KeyEvent.dwControlKeyState = 0;
1006 ret = WriteConsoleInputW(input_handle, &record, 1, &events_written);
1007 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1008 wait_ret = WaitForSingleObject(complete_event, INFINITE);
1009 ok(wait_ret == WAIT_OBJECT_0, "Expected the handle to be signaled\n");
1010 ret = UnregisterWait(wait_handle);
1011 /* If the callback is still running, this fails with ERROR_IO_PENDING, but
1012 that's ok and expected. */
1013 ok(ret != 0 || GetLastError() == ERROR_IO_PENDING,
1014 "UnregisterWait failed with error %d\n", GetLastError());
1016 /* Test timeout case */
1017 FlushConsoleInputBuffer(input_handle);
1018 ret = RegisterWaitForSingleObject(&wait_handle, input_handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
1019 wait_ret = WaitForSingleObject(complete_event, 100);
1020 ok(wait_ret == WAIT_TIMEOUT, "Expected the wait to time out\n");
1021 ret = UnregisterWait(wait_handle);
1022 ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
1024 /* Clean up */
1025 CloseHandle(complete_event);
1028 static void test_wait(HANDLE input, HANDLE orig_output)
1030 HANDLE output, unbound_output, unbound_input;
1031 LARGE_INTEGER zero;
1032 INPUT_RECORD ir;
1033 DWORD res, count;
1034 NTSTATUS status;
1035 BOOL ret;
1037 if (skip_nt) return;
1039 memset(&ir, 0, sizeof(ir));
1040 ir.EventType = MOUSE_EVENT;
1041 ir.Event.MouseEvent.dwEventFlags = MOUSE_MOVED;
1042 zero.QuadPart = 0;
1044 output = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
1045 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1046 CONSOLE_TEXTMODE_BUFFER, NULL);
1047 ok(output != INVALID_HANDLE_VALUE, "CreateConsoleScreenBuffer failed: %u\n", GetLastError());
1049 ret = SetConsoleActiveScreenBuffer(output);
1050 ok(ret, "SetConsoleActiveScreenBuffer failed: %u\n", GetLastError());
1051 FlushConsoleInputBuffer(input);
1053 unbound_output = create_unbound_handle(TRUE, TRUE);
1054 unbound_input = create_unbound_handle(FALSE, TRUE);
1056 res = WaitForSingleObject(input, 0);
1057 ok(res == WAIT_TIMEOUT, "WaitForSingleObject returned %x\n", res);
1058 res = WaitForSingleObject(output, 0);
1059 ok(res == WAIT_TIMEOUT, "WaitForSingleObject returned %x\n", res);
1060 res = WaitForSingleObject(orig_output, 0);
1061 ok(res == WAIT_TIMEOUT, "WaitForSingleObject returned %x\n", res);
1062 res = WaitForSingleObject(unbound_output, 0);
1063 ok(res == WAIT_TIMEOUT, "WaitForSingleObject returned %x\n", res);
1064 res = WaitForSingleObject(unbound_input, 0);
1065 ok(res == WAIT_TIMEOUT, "WaitForSingleObject returned %x\n", res);
1066 status = NtWaitForSingleObject(input, FALSE, &zero);
1067 ok(status == STATUS_TIMEOUT || broken(status == STATUS_ACCESS_DENIED /* win2k8 */),
1068 "NtWaitForSingleObject returned %x\n", status);
1069 status = NtWaitForSingleObject(output, FALSE, &zero);
1070 ok(status == STATUS_TIMEOUT || broken(status == STATUS_ACCESS_DENIED /* win2k8 */),
1071 "NtWaitForSingleObject returned %x\n", status);
1073 ret = WriteConsoleInputW(input, &ir, 1, &count);
1074 ok(ret, "WriteConsoleInputW failed: %u\n", GetLastError());
1076 res = WaitForSingleObject(input, 0);
1077 ok(!res, "WaitForSingleObject returned %x\n", res);
1078 res = WaitForSingleObject(output, 0);
1079 ok(!res, "WaitForSingleObject returned %x\n", res);
1080 res = WaitForSingleObject(orig_output, 0);
1081 ok(!res, "WaitForSingleObject returned %x\n", res);
1082 res = WaitForSingleObject(unbound_output, 0);
1083 ok(!res, "WaitForSingleObject returned %x\n", res);
1084 res = WaitForSingleObject(unbound_input, 0);
1085 ok(!res, "WaitForSingleObject returned %x\n", res);
1086 status = NtWaitForSingleObject(input, FALSE, &zero);
1087 ok(!status || broken(status == STATUS_ACCESS_DENIED /* win2k8 */),
1088 "NtWaitForSingleObject returned %x\n", status);
1089 status = NtWaitForSingleObject(output, FALSE, &zero);
1090 ok(!status || broken(status == STATUS_ACCESS_DENIED /* win2k8 */),
1091 "NtWaitForSingleObject returned %x\n", status);
1093 ret = SetConsoleActiveScreenBuffer(orig_output);
1094 ok(ret, "SetConsoleActiveScreenBuffer failed: %u\n", GetLastError());
1096 CloseHandle(unbound_input);
1097 CloseHandle(unbound_output);
1098 CloseHandle(output);
1101 static void test_GetSetConsoleInputExeName(void)
1103 BOOL ret;
1104 DWORD error;
1105 char buffer[MAX_PATH], module[MAX_PATH], *p;
1106 static char input_exe[MAX_PATH] = "winetest.exe";
1108 SetLastError(0xdeadbeef);
1109 ret = pGetConsoleInputExeNameA(0, NULL);
1110 error = GetLastError();
1111 ok(ret, "GetConsoleInputExeNameA failed\n");
1112 ok(error == ERROR_BUFFER_OVERFLOW, "got %u expected ERROR_BUFFER_OVERFLOW\n", error);
1114 SetLastError(0xdeadbeef);
1115 ret = pGetConsoleInputExeNameA(0, buffer);
1116 error = GetLastError();
1117 ok(ret, "GetConsoleInputExeNameA failed\n");
1118 ok(error == ERROR_BUFFER_OVERFLOW, "got %u expected ERROR_BUFFER_OVERFLOW\n", error);
1120 GetModuleFileNameA(GetModuleHandleA(NULL), module, sizeof(module));
1121 p = strrchr(module, '\\') + 1;
1123 ret = pGetConsoleInputExeNameA(ARRAY_SIZE(buffer), buffer);
1124 ok(ret, "GetConsoleInputExeNameA failed\n");
1125 todo_wine ok(!lstrcmpA(buffer, p), "got %s expected %s\n", buffer, p);
1127 SetLastError(0xdeadbeef);
1128 ret = pSetConsoleInputExeNameA(NULL);
1129 error = GetLastError();
1130 ok(!ret, "SetConsoleInputExeNameA failed\n");
1131 ok(error == ERROR_INVALID_PARAMETER, "got %u expected ERROR_INVALID_PARAMETER\n", error);
1133 SetLastError(0xdeadbeef);
1134 ret = pSetConsoleInputExeNameA("");
1135 error = GetLastError();
1136 ok(!ret, "SetConsoleInputExeNameA failed\n");
1137 ok(error == ERROR_INVALID_PARAMETER, "got %u expected ERROR_INVALID_PARAMETER\n", error);
1139 ret = pSetConsoleInputExeNameA(input_exe);
1140 ok(ret, "SetConsoleInputExeNameA failed\n");
1142 ret = pGetConsoleInputExeNameA(ARRAY_SIZE(buffer), buffer);
1143 ok(ret, "GetConsoleInputExeNameA failed\n");
1144 ok(!lstrcmpA(buffer, input_exe), "got %s expected %s\n", buffer, input_exe);
1147 static void test_GetConsoleProcessList(void)
1149 DWORD ret, *list = NULL;
1151 if (!pGetConsoleProcessList)
1153 win_skip("GetConsoleProcessList is not available\n");
1154 return;
1157 SetLastError(0xdeadbeef);
1158 ret = pGetConsoleProcessList(NULL, 0);
1159 ok(ret == 0, "Expected failure\n");
1160 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1161 "Expected ERROR_INVALID_PARAMETER, got %d\n",
1162 GetLastError());
1164 SetLastError(0xdeadbeef);
1165 ret = pGetConsoleProcessList(NULL, 1);
1166 ok(ret == 0, "Expected failure\n");
1167 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1168 "Expected ERROR_INVALID_PARAMETER, got %d\n",
1169 GetLastError());
1171 /* We should only have 1 process but only for these specific unit tests as
1172 * we created our own console. An AttachConsole(ATTACH_PARENT_PROCESS) would
1173 * give us two processes for example.
1175 list = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD));
1177 SetLastError(0xdeadbeef);
1178 ret = pGetConsoleProcessList(list, 0);
1179 ok(ret == 0, "Expected failure\n");
1180 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1181 "Expected ERROR_INVALID_PARAMETER, got %d\n",
1182 GetLastError());
1184 SetLastError(0xdeadbeef);
1185 ret = pGetConsoleProcessList(list, 1);
1186 todo_wine
1187 ok(ret == 1, "Expected 1, got %d\n", ret);
1189 HeapFree(GetProcessHeap(), 0, list);
1191 list = HeapAlloc(GetProcessHeap(), 0, ret * sizeof(DWORD));
1193 SetLastError(0xdeadbeef);
1194 ret = pGetConsoleProcessList(list, ret);
1195 todo_wine
1196 ok(ret == 1, "Expected 1, got %d\n", ret);
1198 if (ret == 1)
1200 DWORD pid = GetCurrentProcessId();
1201 ok(list[0] == pid, "Expected %d, got %d\n", pid, list[0]);
1204 HeapFree(GetProcessHeap(), 0, list);
1207 static void test_OpenCON(void)
1209 static const WCHAR conW[] = {'C','O','N',0};
1210 static const DWORD accesses[] = {CREATE_NEW, CREATE_ALWAYS, OPEN_EXISTING,
1211 OPEN_ALWAYS, TRUNCATE_EXISTING};
1212 unsigned i;
1213 HANDLE h;
1215 for (i = 0; i < ARRAY_SIZE(accesses); i++)
1217 h = CreateFileW(conW, GENERIC_WRITE, 0, NULL, accesses[i], 0, NULL);
1218 ok(h != INVALID_HANDLE_VALUE || broken(accesses[i] == TRUNCATE_EXISTING /* Win8 */),
1219 "Expected to open the CON device on write (%x)\n", accesses[i]);
1220 CloseHandle(h);
1222 h = CreateFileW(conW, GENERIC_READ, 0, NULL, accesses[i], 0, NULL);
1223 /* Windows versions differ here:
1224 * MSDN states in CreateFile that TRUNCATE_EXISTING requires GENERIC_WRITE
1225 * NT, XP, Vista comply, but Win7 doesn't and allows opening CON with TRUNCATE_EXISTING
1226 * So don't test when disposition is TRUNCATE_EXISTING
1228 ok(h != INVALID_HANDLE_VALUE || broken(accesses[i] == TRUNCATE_EXISTING /* Win7+ */),
1229 "Expected to open the CON device on read (%x)\n", accesses[i]);
1230 CloseHandle(h);
1231 h = CreateFileW(conW, GENERIC_READ|GENERIC_WRITE, 0, NULL, accesses[i], 0, NULL);
1232 ok(h == INVALID_HANDLE_VALUE, "Expected not to open the CON device on read-write (%x)\n", accesses[i]);
1233 ok(GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_INVALID_PARAMETER,
1234 "Unexpected error %x\n", GetLastError());
1238 static void test_OpenConsoleW(void)
1240 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
1241 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
1242 static const WCHAR emptyW[] = {0};
1243 static const WCHAR invalidW[] = {'I','N','V','A','L','I','D',0};
1244 DWORD gle;
1246 static const struct
1248 LPCWSTR name;
1249 DWORD access;
1250 BOOL inherit;
1251 DWORD creation;
1252 DWORD gle, gle2;
1253 } invalid_table[] = {
1254 {NULL, 0, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1255 {NULL, 0, FALSE, 0xdeadbeef, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1256 {NULL, 0xdeadbeef, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1257 {NULL, 0xdeadbeef, TRUE, 0xdeadbeef, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1258 {NULL, 0, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1259 {NULL, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1260 {NULL, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1261 {NULL, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1262 {emptyW, 0, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1263 {emptyW, 0, FALSE, 0xdeadbeef, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1264 {emptyW, 0xdeadbeef, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1265 {emptyW, 0xdeadbeef, TRUE, 0xdeadbeef, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1266 {emptyW, 0, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1267 {emptyW, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1268 {emptyW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1269 {emptyW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1270 {invalidW, 0, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1271 {invalidW, 0, FALSE, 0xdeadbeef, ERROR_INVALID_PARAMETER, 0},
1272 {invalidW, 0xdeadbeef, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1273 {invalidW, 0xdeadbeef, TRUE, 0xdeadbeef, ERROR_INVALID_PARAMETER, 0},
1274 {invalidW, 0, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1275 {invalidW, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1276 {invalidW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1277 {invalidW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING, ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1278 {coninW, 0, FALSE, 0xdeadbeef, ERROR_INVALID_PARAMETER, 0},
1279 {coninW, 0xdeadbeef, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_ACCESS_DENIED},
1280 {coninW, 0xdeadbeef, TRUE, 0xdeadbeef, ERROR_INVALID_PARAMETER, 0},
1281 {conoutW, 0, FALSE, 0xdeadbeef, ERROR_INVALID_PARAMETER, 0},
1282 {conoutW, 0xceadbeef, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_ACCESS_DENIED},
1283 {conoutW, 0xdeadbeef, TRUE, 0xdeadbeef, ERROR_INVALID_PARAMETER, 0},
1285 static const struct
1287 LPCWSTR name;
1288 DWORD access;
1289 BOOL inherit;
1290 DWORD creation;
1291 } valid_table[] = {
1292 {coninW, 0, FALSE, 0 },
1293 {coninW, 0, TRUE, 0 },
1294 {coninW, GENERIC_EXECUTE, TRUE, 0 },
1295 {coninW, GENERIC_ALL, TRUE, 0 },
1296 {coninW, 0, FALSE, OPEN_ALWAYS },
1297 {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, 0 },
1298 {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_NEW },
1299 {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_ALWAYS },
1300 {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS },
1301 {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, TRUNCATE_EXISTING},
1302 {conoutW, 0, FALSE, 0 },
1303 {conoutW, 0, FALSE, OPEN_ALWAYS },
1304 {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, 0 },
1305 {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_NEW, },
1306 {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_ALWAYS },
1307 {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS },
1308 {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, TRUNCATE_EXISTING},
1311 int index;
1312 HANDLE ret;
1314 if (!pOpenConsoleW)
1316 win_skip("OpenConsoleW is not available\n");
1317 return;
1320 for (index = 0; index < ARRAY_SIZE(invalid_table); index++)
1322 SetLastError(0xdeadbeef);
1323 ret = pOpenConsoleW(invalid_table[index].name, invalid_table[index].access,
1324 invalid_table[index].inherit, invalid_table[index].creation);
1325 gle = GetLastError();
1326 ok(ret == INVALID_HANDLE_VALUE,
1327 "Expected OpenConsoleW to return INVALID_HANDLE_VALUE for index %d, got %p\n",
1328 index, ret);
1329 ok(gle == invalid_table[index].gle || (gle != 0 && gle == invalid_table[index].gle2),
1330 "Expected GetLastError() to return %u/%u for index %d, got %u\n",
1331 invalid_table[index].gle, invalid_table[index].gle2, index, gle);
1334 for (index = 0; index < ARRAY_SIZE(valid_table); index++)
1336 ret = pOpenConsoleW(valid_table[index].name, valid_table[index].access,
1337 valid_table[index].inherit, valid_table[index].creation);
1338 todo_wine
1339 ok(ret != INVALID_HANDLE_VALUE || broken(ret == INVALID_HANDLE_VALUE /* until Win7 */),
1340 "Expected OpenConsoleW to succeed for index %d, got %p\n", index, ret);
1341 if (ret != INVALID_HANDLE_VALUE)
1342 CloseHandle(ret);
1345 ret = pOpenConsoleW(coninW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING);
1346 ok(ret != INVALID_HANDLE_VALUE, "Expected OpenConsoleW to return a valid handle\n");
1347 if (ret != INVALID_HANDLE_VALUE)
1348 CloseHandle(ret);
1350 ret = pOpenConsoleW(conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING);
1351 ok(ret != INVALID_HANDLE_VALUE, "Expected OpenConsoleW to return a valid handle\n");
1352 if (ret != INVALID_HANDLE_VALUE)
1353 CloseHandle(ret);
1356 static void test_CreateFileW(void)
1358 static const struct
1360 BOOL input;
1361 DWORD access;
1362 BOOL inherit;
1363 DWORD creation;
1364 DWORD gle;
1365 BOOL is_broken;
1366 } cf_table[] = {
1367 {TRUE, 0, FALSE, OPEN_ALWAYS, 0, FALSE},
1368 {TRUE, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_INVALID_PARAMETER, TRUE},
1369 {TRUE, 0, FALSE, 0, ERROR_INVALID_PARAMETER, TRUE},
1370 {TRUE, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_NEW, 0, FALSE},
1371 {TRUE, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_ALWAYS, 0, FALSE},
1372 {TRUE, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, 0, FALSE},
1373 {FALSE, 0, FALSE, 0, ERROR_INVALID_PARAMETER, TRUE},
1374 {FALSE, 0, FALSE, OPEN_ALWAYS, 0, FALSE},
1375 {FALSE, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_INVALID_PARAMETER, TRUE},
1376 {FALSE, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_NEW, 0, FALSE},
1377 {FALSE, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_ALWAYS, 0, FALSE},
1378 {FALSE, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, 0, FALSE},
1379 /* TRUNCATE_EXISTING is forbidden starting with Windows 8 */
1382 static const UINT nt_disposition[5] =
1384 FILE_CREATE, /* CREATE_NEW */
1385 FILE_OVERWRITE_IF, /* CREATE_ALWAYS */
1386 FILE_OPEN, /* OPEN_EXISTING */
1387 FILE_OPEN_IF, /* OPEN_ALWAYS */
1388 FILE_OVERWRITE /* TRUNCATE_EXISTING */
1391 int index;
1392 HANDLE ret;
1393 SECURITY_ATTRIBUTES sa;
1394 OBJECT_ATTRIBUTES attr = {sizeof(attr)};
1395 UNICODE_STRING string;
1396 IO_STATUS_BLOCK iosb;
1397 NTSTATUS status;
1399 for (index = 0; index < ARRAY_SIZE(cf_table); index++)
1401 SetLastError(0xdeadbeef);
1403 sa.nLength = sizeof(sa);
1404 sa.lpSecurityDescriptor = NULL;
1405 sa.bInheritHandle = cf_table[index].inherit;
1407 ret = CreateFileW(cf_table[index].input ? L"CONIN$" : L"CONOUT$", cf_table[index].access,
1408 FILE_SHARE_READ|FILE_SHARE_WRITE, &sa,
1409 cf_table[index].creation, FILE_ATTRIBUTE_NORMAL, NULL);
1410 if (ret == INVALID_HANDLE_VALUE)
1412 ok(cf_table[index].gle,
1413 "Expected CreateFileW not to return INVALID_HANDLE_VALUE for index %d\n", index);
1414 ok(GetLastError() == cf_table[index].gle,
1415 "Expected GetLastError() to return %u for index %d, got %u\n",
1416 cf_table[index].gle, index, GetLastError());
1418 else
1420 ok(!cf_table[index].gle || broken(cf_table[index].is_broken) /* Win7 */,
1421 "Expected CreateFileW to succeed for index %d\n", index);
1422 CloseHandle(ret);
1425 if (skip_nt) continue;
1427 SetLastError(0xdeadbeef);
1429 sa.nLength = sizeof(sa);
1430 sa.lpSecurityDescriptor = NULL;
1431 sa.bInheritHandle = cf_table[index].inherit;
1433 ret = CreateFileW(cf_table[index].input ? L"\\??\\CONIN$" : L"\\??\\CONOUT$", cf_table[index].access,
1434 FILE_SHARE_READ|FILE_SHARE_WRITE, &sa,
1435 cf_table[index].creation, FILE_ATTRIBUTE_NORMAL, NULL);
1436 if (cf_table[index].gle)
1437 ok(ret == INVALID_HANDLE_VALUE && GetLastError() == cf_table[index].gle,
1438 "CreateFileW to returned %p %u for index %d\n", ret, GetLastError(), index);
1439 else
1440 ok(ret != INVALID_HANDLE_VALUE && (!cf_table[index].gle || broken(cf_table[index].is_broken) /* Win7 */),
1441 "CreateFileW to returned %p %u for index %d\n", ret, GetLastError(), index);
1442 if (ret != INVALID_HANDLE_VALUE) CloseHandle(ret);
1444 if (cf_table[index].gle) continue;
1446 RtlInitUnicodeString(&string, cf_table[index].input
1447 ? L"\\Device\\ConDrv\\CurrentIn" : L"\\Device\\ConDrv\\CurrentOut");
1448 attr.ObjectName = &string;
1449 status = NtCreateFile(&ret, cf_table[index].access | SYNCHRONIZE | FILE_READ_ATTRIBUTES, &attr, &iosb, NULL,
1450 FILE_ATTRIBUTE_NORMAL, 0, nt_disposition[cf_table[index].creation - CREATE_NEW],
1451 FILE_NON_DIRECTORY_FILE, NULL, 0);
1452 ok(!status, "NtCreateFile failed %x for %u\n", status, index);
1453 CloseHandle(ret);
1455 RtlInitUnicodeString(&string, cf_table[index].input ? L"\\??\\CONIN$" : L"\\??\\CONOUT$");
1456 attr.ObjectName = &string;
1457 status = NtCreateFile(&ret, cf_table[index].access | SYNCHRONIZE | FILE_READ_ATTRIBUTES, &attr, &iosb, NULL,
1458 FILE_ATTRIBUTE_NORMAL, 0, nt_disposition[cf_table[index].creation - CREATE_NEW],
1459 FILE_NON_DIRECTORY_FILE, NULL, 0);
1460 ok(!status, "NtCreateFile failed %x for %u\n", status, index);
1461 CloseHandle(ret);
1465 static void test_VerifyConsoleIoHandle( HANDLE handle )
1467 BOOL ret;
1468 DWORD error;
1470 if (!pVerifyConsoleIoHandle)
1472 win_skip("VerifyConsoleIoHandle is not available\n");
1473 return;
1476 /* invalid handle */
1477 SetLastError(0xdeadbeef);
1478 ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee0);
1479 error = GetLastError();
1480 ok(!ret, "expected VerifyConsoleIoHandle to fail\n");
1481 ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error);
1483 /* invalid handle + 1 */
1484 SetLastError(0xdeadbeef);
1485 ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee1);
1486 error = GetLastError();
1487 ok(!ret, "expected VerifyConsoleIoHandle to fail\n");
1488 ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error);
1490 /* invalid handle + 2 */
1491 SetLastError(0xdeadbeef);
1492 ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee2);
1493 error = GetLastError();
1494 ok(!ret, "expected VerifyConsoleIoHandle to fail\n");
1495 ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error);
1497 /* invalid handle + 3 */
1498 SetLastError(0xdeadbeef);
1499 ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee3);
1500 error = GetLastError();
1501 ok(!ret, "expected VerifyConsoleIoHandle to fail\n");
1502 ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error);
1504 /* valid handle */
1505 SetLastError(0xdeadbeef);
1506 ret = pVerifyConsoleIoHandle(handle);
1507 error = GetLastError();
1508 ok(ret ||
1509 broken(!ret), /* Windows 8 and 10 */
1510 "expected VerifyConsoleIoHandle to succeed\n");
1511 ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error);
1514 static void test_GetSetStdHandle(void)
1516 HANDLE handle;
1517 DWORD error;
1518 BOOL ret;
1520 /* get invalid std handle */
1521 SetLastError(0xdeadbeef);
1522 handle = GetStdHandle(42);
1523 error = GetLastError();
1524 ok(error == ERROR_INVALID_HANDLE || broken(error == ERROR_INVALID_FUNCTION)/* Win9x */,
1525 "wrong GetLastError() %d\n", error);
1526 ok(handle == INVALID_HANDLE_VALUE, "expected INVALID_HANDLE_VALUE\n");
1528 /* get valid */
1529 SetLastError(0xdeadbeef);
1530 handle = GetStdHandle(STD_INPUT_HANDLE);
1531 error = GetLastError();
1532 ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error);
1534 /* set invalid std handle */
1535 SetLastError(0xdeadbeef);
1536 ret = SetStdHandle(42, handle);
1537 error = GetLastError();
1538 ok(!ret, "expected SetStdHandle to fail\n");
1539 ok(error == ERROR_INVALID_HANDLE || broken(error == ERROR_INVALID_FUNCTION)/* Win9x */,
1540 "wrong GetLastError() %d\n", error);
1542 /* set valid (restore old value) */
1543 SetLastError(0xdeadbeef);
1544 ret = SetStdHandle(STD_INPUT_HANDLE, handle);
1545 error = GetLastError();
1546 ok(ret, "expected SetStdHandle to succeed\n");
1547 ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error);
1550 static void test_DuplicateConsoleHandle(void)
1552 HANDLE handle, event;
1553 BOOL ret;
1555 if (skip_nt) return;
1557 event = CreateEventW(NULL, TRUE, FALSE, NULL);
1559 /* duplicate an event handle with DuplicateConsoleHandle */
1560 handle = DuplicateConsoleHandle(event, 0, FALSE, DUPLICATE_SAME_ACCESS);
1561 ok(handle != NULL, "DuplicateConsoleHandle failed: %u\n", GetLastError());
1563 ret = SetEvent(handle);
1564 ok(ret, "SetEvent failed: %u\n", GetLastError());
1566 ret = CloseConsoleHandle(handle);
1567 ok(ret, "CloseConsoleHandle failed: %u\n", GetLastError());
1568 ret = CloseConsoleHandle(event);
1569 ok(ret, "CloseConsoleHandle failed: %u\n", GetLastError());
1571 handle = DuplicateConsoleHandle((HANDLE)0xdeadbeef, 0, FALSE, DUPLICATE_SAME_ACCESS);
1572 ok(handle == INVALID_HANDLE_VALUE, "DuplicateConsoleHandle failed: %u\n", GetLastError());
1573 ok(GetLastError() == ERROR_INVALID_HANDLE, "last error = %u\n", GetLastError());
1576 static void test_GetNumberOfConsoleInputEvents(HANDLE input_handle)
1578 DWORD count;
1579 BOOL ret;
1580 int i;
1582 const struct
1584 HANDLE handle;
1585 LPDWORD nrofevents;
1586 DWORD last_error;
1587 } invalid_table[] =
1589 {NULL, NULL, ERROR_INVALID_HANDLE},
1590 {NULL, &count, ERROR_INVALID_HANDLE},
1591 {INVALID_HANDLE_VALUE, NULL, ERROR_INVALID_HANDLE},
1592 {INVALID_HANDLE_VALUE, &count, ERROR_INVALID_HANDLE},
1595 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
1597 SetLastError(0xdeadbeef);
1598 if (invalid_table[i].nrofevents) count = 0xdeadbeef;
1599 ret = GetNumberOfConsoleInputEvents(invalid_table[i].handle,
1600 invalid_table[i].nrofevents);
1601 ok(!ret, "[%d] Expected GetNumberOfConsoleInputEvents to return FALSE, got %d\n", i, ret);
1602 if (invalid_table[i].nrofevents)
1604 ok(count == 0xdeadbeef,
1605 "[%d] Expected output count to be unmodified, got %u\n", i, count);
1607 ok(GetLastError() == invalid_table[i].last_error,
1608 "[%d] Expected last error to be %u, got %u\n",
1609 i, invalid_table[i].last_error, GetLastError());
1612 /* Test crashes on Windows 7. */
1613 if (0)
1615 SetLastError(0xdeadbeef);
1616 ret = GetNumberOfConsoleInputEvents(input_handle, NULL);
1617 ok(!ret, "Expected GetNumberOfConsoleInputEvents to return FALSE, got %d\n", ret);
1618 ok(GetLastError() == ERROR_INVALID_ACCESS,
1619 "Expected last error to be ERROR_INVALID_ACCESS, got %u\n",
1620 GetLastError());
1623 count = 0xdeadbeef;
1624 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1625 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1626 ok(count != 0xdeadbeef, "Expected output count to initialized\n");
1629 static void test_WriteConsoleInputA(HANDLE input_handle)
1631 INPUT_RECORD event;
1632 INPUT_RECORD event_list[5];
1633 MOUSE_EVENT_RECORD mouse_event = { {0, 0}, 0, 0, MOUSE_MOVED };
1634 KEY_EVENT_RECORD key_event;
1635 DWORD count, console_mode, gle;
1636 BOOL ret;
1637 int i;
1639 const struct
1641 HANDLE handle;
1642 const INPUT_RECORD *buffer;
1643 DWORD count;
1644 LPDWORD written;
1645 DWORD gle, gle2;
1646 int win_crash;
1647 } invalid_table[] =
1649 {NULL, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1650 {NULL, NULL, 0, &count,ERROR_INVALID_HANDLE},
1651 {NULL, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1652 {NULL, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
1653 {NULL, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1654 {NULL, &event, 0, &count, ERROR_INVALID_HANDLE},
1655 {NULL, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1656 {NULL, &event, 1, &count, ERROR_INVALID_HANDLE},
1657 {INVALID_HANDLE_VALUE, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1658 {INVALID_HANDLE_VALUE, NULL, 0, &count, ERROR_INVALID_HANDLE},
1659 {INVALID_HANDLE_VALUE, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1660 {INVALID_HANDLE_VALUE, NULL, 1, &count, ERROR_INVALID_HANDLE, ERROR_INVALID_ACCESS},
1661 {INVALID_HANDLE_VALUE, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1662 {INVALID_HANDLE_VALUE, &event, 0, &count, ERROR_INVALID_HANDLE},
1663 {INVALID_HANDLE_VALUE, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1664 {INVALID_HANDLE_VALUE, &event, 1, &count, ERROR_INVALID_HANDLE},
1665 {input_handle, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1666 {input_handle, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1667 {input_handle, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
1668 {input_handle, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1669 {input_handle, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1672 /* Suppress external sources of input events for the duration of the test. */
1673 ret = GetConsoleMode(input_handle, &console_mode);
1674 ok(ret == TRUE, "Expected GetConsoleMode to return TRUE, got %d\n", ret);
1675 if (!ret)
1677 skip("GetConsoleMode failed with last error %u\n", GetLastError());
1678 return;
1681 ret = SetConsoleMode(input_handle, console_mode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
1682 ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret);
1683 if (!ret)
1685 skip("SetConsoleMode failed with last error %u\n", GetLastError());
1686 return;
1689 /* Discard any events queued before the tests. */
1690 ret = FlushConsoleInputBuffer(input_handle);
1691 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1693 event.EventType = MOUSE_EVENT;
1694 event.Event.MouseEvent = mouse_event;
1696 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
1698 if (invalid_table[i].win_crash)
1699 continue;
1701 SetLastError(0xdeadbeef);
1702 if (invalid_table[i].written) count = 0xdeadbeef;
1703 ret = WriteConsoleInputA(invalid_table[i].handle,
1704 invalid_table[i].buffer,
1705 invalid_table[i].count,
1706 invalid_table[i].written);
1707 ok(!ret, "[%d] Expected WriteConsoleInputA to return FALSE, got %d\n", i, ret);
1708 gle = GetLastError();
1709 ok(gle == invalid_table[i].gle || (gle != 0 && gle == invalid_table[i].gle2),
1710 "[%d] Expected last error to be %u or %u, got %u\n",
1711 i, invalid_table[i].gle, invalid_table[i].gle2, gle);
1714 count = 0xdeadbeef;
1715 ret = WriteConsoleInputA(input_handle, NULL, 0, &count);
1716 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1717 ok(count == 0, "Expected count to be 0, got %u\n", count);
1719 count = 0xdeadbeef;
1720 ret = WriteConsoleInputA(input_handle, &event, 0, &count);
1721 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1722 ok(count == 0, "Expected count to be 0, got %u\n", count);
1724 count = 0xdeadbeef;
1725 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1726 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1727 ok(count == 1, "Expected count to be 1, got %u\n", count);
1729 ret = FlushConsoleInputBuffer(input_handle);
1730 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1732 /* Writing a single mouse event doesn't seem to affect the count if an adjacent mouse event is already queued. */
1733 event.EventType = MOUSE_EVENT;
1734 event.Event.MouseEvent = mouse_event;
1736 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1737 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1738 ok(count == 1, "Expected count to be 1, got %u\n", count);
1740 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1741 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1742 ok(count == 1, "Expected count to be 1, got %u\n", count);
1744 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1745 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1746 ok(count == 1, "Expected count to be 1, got %u\n", count);
1748 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1749 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1750 todo_wine
1751 ok(count == 1, "Expected count to be 1, got %u\n", count);
1753 ret = FlushConsoleInputBuffer(input_handle);
1754 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1756 for (i = 0; i < ARRAY_SIZE(event_list); i++)
1758 event_list[i].EventType = MOUSE_EVENT;
1759 event_list[i].Event.MouseEvent = mouse_event;
1762 /* Writing consecutive chunks of mouse events appears to work. */
1763 ret = WriteConsoleInputA(input_handle, event_list, ARRAY_SIZE(event_list), &count);
1764 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1765 ok(count == ARRAY_SIZE(event_list),
1766 "Expected count to be event list length, got %u\n", count);
1768 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1769 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1770 ok(count == ARRAY_SIZE(event_list),
1771 "Expected count to be event list length, got %u\n", count);
1773 ret = WriteConsoleInputA(input_handle, event_list, ARRAY_SIZE(event_list), &count);
1774 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1775 ok(count == ARRAY_SIZE(event_list),
1776 "Expected count to be event list length, got %u\n", count);
1778 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1779 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1780 ok(count == 2*ARRAY_SIZE(event_list),
1781 "Expected count to be twice event list length, got %u\n", count);
1783 /* Again, writing a single mouse event with adjacent mouse events queued doesn't appear to affect the count. */
1784 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1785 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1786 ok(count == 1, "Expected count to be 1, got %u\n", count);
1788 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1789 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1790 todo_wine
1791 ok(count == 2*ARRAY_SIZE(event_list),
1792 "Expected count to be twice event list length, got %u\n", count);
1794 ret = FlushConsoleInputBuffer(input_handle);
1795 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1797 key_event.bKeyDown = FALSE;
1798 key_event.wRepeatCount = 0;
1799 key_event.wVirtualKeyCode = VK_SPACE;
1800 key_event.wVirtualScanCode = VK_SPACE;
1801 key_event.uChar.AsciiChar = ' ';
1802 key_event.dwControlKeyState = 0;
1804 event.EventType = KEY_EVENT;
1805 event.Event.KeyEvent = key_event;
1807 /* Key events don't exhibit the same behavior as mouse events. */
1808 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1809 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1810 ok(count == 1, "Expected count to be 1, got %u\n", count);
1812 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1813 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1814 ok(count == 1, "Expected count to be 1, got %u\n", count);
1816 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1817 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1818 ok(count == 1, "Expected count to be 1, got %u\n", count);
1820 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1821 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1822 ok(count == 2, "Expected count to be 2, got %u\n", count);
1824 ret = FlushConsoleInputBuffer(input_handle);
1825 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1827 /* Try interleaving mouse and key events. */
1828 event.EventType = MOUSE_EVENT;
1829 event.Event.MouseEvent = mouse_event;
1831 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1832 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1833 ok(count == 1, "Expected count to be 1, got %u\n", count);
1835 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1836 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1837 ok(count == 1, "Expected count to be 1, got %u\n", count);
1839 event.EventType = KEY_EVENT;
1840 event.Event.KeyEvent = key_event;
1842 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1843 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1844 ok(count == 1, "Expected count to be 1, got %u\n", count);
1846 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1847 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1848 ok(count == 2, "Expected count to be 2, got %u\n", count);
1850 event.EventType = MOUSE_EVENT;
1851 event.Event.MouseEvent = mouse_event;
1853 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1854 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1855 ok(count == 1, "Expected count to be 1, got %u\n", count);
1857 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1858 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1859 ok(count == 3, "Expected count to be 3, got %u\n", count);
1861 /* Restore the old console mode. */
1862 ret = SetConsoleMode(input_handle, console_mode);
1863 ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret);
1866 static void test_WriteConsoleInputW(HANDLE input_handle)
1868 INPUT_RECORD event;
1869 INPUT_RECORD event_list[5];
1870 MOUSE_EVENT_RECORD mouse_event = { {0, 0}, 0, 0, MOUSE_MOVED };
1871 KEY_EVENT_RECORD key_event;
1872 DWORD count, console_mode, gle;
1873 BOOL ret;
1874 int i;
1876 const struct
1878 HANDLE handle;
1879 const INPUT_RECORD *buffer;
1880 DWORD count;
1881 LPDWORD written;
1882 DWORD gle, gle2;
1883 int win_crash;
1884 } invalid_table[] =
1886 {NULL, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1887 {NULL, NULL, 0, &count, ERROR_INVALID_HANDLE},
1888 {NULL, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1889 {NULL, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
1890 {NULL, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1891 {NULL, &event, 0, &count, ERROR_INVALID_HANDLE},
1892 {NULL, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1893 {NULL, &event, 1, &count, ERROR_INVALID_HANDLE},
1894 {INVALID_HANDLE_VALUE, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1895 {INVALID_HANDLE_VALUE, NULL, 0, &count, ERROR_INVALID_HANDLE},
1896 {INVALID_HANDLE_VALUE, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1897 {INVALID_HANDLE_VALUE, NULL, 1, &count, ERROR_INVALID_HANDLE, ERROR_INVALID_ACCESS},
1898 {INVALID_HANDLE_VALUE, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1899 {INVALID_HANDLE_VALUE, &event, 0, &count, ERROR_INVALID_HANDLE},
1900 {INVALID_HANDLE_VALUE, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1901 {INVALID_HANDLE_VALUE, &event, 1, &count, ERROR_INVALID_HANDLE},
1902 {input_handle, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1903 {input_handle, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1904 {input_handle, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
1905 {input_handle, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1906 {input_handle, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1909 /* Suppress external sources of input events for the duration of the test. */
1910 ret = GetConsoleMode(input_handle, &console_mode);
1911 ok(ret == TRUE, "Expected GetConsoleMode to return TRUE, got %d\n", ret);
1912 if (!ret)
1914 skip("GetConsoleMode failed with last error %u\n", GetLastError());
1915 return;
1918 ret = SetConsoleMode(input_handle, console_mode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
1919 ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret);
1920 if (!ret)
1922 skip("SetConsoleMode failed with last error %u\n", GetLastError());
1923 return;
1926 /* Discard any events queued before the tests. */
1927 ret = FlushConsoleInputBuffer(input_handle);
1928 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1930 event.EventType = MOUSE_EVENT;
1931 event.Event.MouseEvent = mouse_event;
1933 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
1935 if (invalid_table[i].win_crash)
1936 continue;
1938 SetLastError(0xdeadbeef);
1939 if (invalid_table[i].written) count = 0xdeadbeef;
1940 ret = WriteConsoleInputW(invalid_table[i].handle,
1941 invalid_table[i].buffer,
1942 invalid_table[i].count,
1943 invalid_table[i].written);
1944 ok(!ret, "[%d] Expected WriteConsoleInputW to return FALSE, got %d\n", i, ret);
1945 gle = GetLastError();
1946 ok(gle == invalid_table[i].gle || (gle != 0 && gle == invalid_table[i].gle2),
1947 "[%d] Expected last error to be %u or %u, got %u\n",
1948 i, invalid_table[i].gle, invalid_table[i].gle2, gle);
1951 count = 0xdeadbeef;
1952 ret = WriteConsoleInputW(input_handle, NULL, 0, &count);
1953 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1954 ok(count == 0, "Expected count to be 0, got %u\n", count);
1956 count = 0xdeadbeef;
1957 ret = WriteConsoleInputW(input_handle, &event, 0, &count);
1958 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1959 ok(count == 0, "Expected count to be 0, got %u\n", count);
1961 count = 0xdeadbeef;
1962 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
1963 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1964 ok(count == 1, "Expected count to be 1, got %u\n", count);
1966 ret = FlushConsoleInputBuffer(input_handle);
1967 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1969 /* Writing a single mouse event doesn't seem to affect the count if an adjacent mouse event is already queued. */
1970 event.EventType = MOUSE_EVENT;
1971 event.Event.MouseEvent = mouse_event;
1973 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
1974 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1975 ok(count == 1, "Expected count to be 1, got %u\n", count);
1977 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1978 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1979 ok(count == 1, "Expected count to be 1, got %u\n", count);
1981 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
1982 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1983 ok(count == 1, "Expected count to be 1, got %u\n", count);
1985 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1986 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1987 todo_wine
1988 ok(count == 1, "Expected count to be 1, got %u\n", count);
1990 ret = FlushConsoleInputBuffer(input_handle);
1991 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1993 for (i = 0; i < ARRAY_SIZE(event_list); i++)
1995 event_list[i].EventType = MOUSE_EVENT;
1996 event_list[i].Event.MouseEvent = mouse_event;
1999 /* Writing consecutive chunks of mouse events appears to work. */
2000 ret = WriteConsoleInputW(input_handle, event_list, ARRAY_SIZE(event_list), &count);
2001 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2002 ok(count == ARRAY_SIZE(event_list),
2003 "Expected count to be event list length, got %u\n", count);
2005 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2006 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2007 ok(count == ARRAY_SIZE(event_list),
2008 "Expected count to be event list length, got %u\n", count);
2010 ret = WriteConsoleInputW(input_handle, event_list, ARRAY_SIZE(event_list), &count);
2011 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2012 ok(count == ARRAY_SIZE(event_list),
2013 "Expected count to be event list length, got %u\n", count);
2015 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2016 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2017 ok(count == 2*ARRAY_SIZE(event_list),
2018 "Expected count to be twice event list length, got %u\n", count);
2020 /* Again, writing a single mouse event with adjacent mouse events queued doesn't appear to affect the count. */
2021 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2022 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2023 ok(count == 1, "Expected count to be 1, got %u\n", count);
2025 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2026 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2027 todo_wine
2028 ok(count == 2*ARRAY_SIZE(event_list),
2029 "Expected count to be twice event list length, got %u\n", count);
2031 ret = FlushConsoleInputBuffer(input_handle);
2032 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
2034 key_event.bKeyDown = FALSE;
2035 key_event.wRepeatCount = 0;
2036 key_event.wVirtualKeyCode = VK_SPACE;
2037 key_event.wVirtualScanCode = VK_SPACE;
2038 key_event.uChar.UnicodeChar = ' ';
2039 key_event.dwControlKeyState = 0;
2041 event.EventType = KEY_EVENT;
2042 event.Event.KeyEvent = key_event;
2044 /* Key events don't exhibit the same behavior as mouse events. */
2045 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2046 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2047 ok(count == 1, "Expected count to be 1, got %u\n", count);
2049 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2050 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2051 ok(count == 1, "Expected count to be 1, got %u\n", count);
2053 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2054 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2055 ok(count == 1, "Expected count to be 1, got %u\n", count);
2057 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2058 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2059 ok(count == 2, "Expected count to be 2, got %u\n", count);
2061 ret = FlushConsoleInputBuffer(input_handle);
2062 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
2064 /* Try interleaving mouse and key events. */
2065 event.EventType = MOUSE_EVENT;
2066 event.Event.MouseEvent = mouse_event;
2068 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2069 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2070 ok(count == 1, "Expected count to be 1, got %u\n", count);
2072 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2073 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2074 ok(count == 1, "Expected count to be 1, got %u\n", count);
2076 event.EventType = KEY_EVENT;
2077 event.Event.KeyEvent = key_event;
2079 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2080 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2081 ok(count == 1, "Expected count to be 1, got %u\n", count);
2083 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2084 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2085 ok(count == 2, "Expected count to be 2, got %u\n", count);
2087 event.EventType = MOUSE_EVENT;
2088 event.Event.MouseEvent = mouse_event;
2090 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2091 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2092 ok(count == 1, "Expected count to be 1, got %u\n", count);
2094 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2095 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2096 ok(count == 3, "Expected count to be 3, got %u\n", count);
2098 /* Restore the old console mode. */
2099 ret = SetConsoleMode(input_handle, console_mode);
2100 ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret);
2103 static void test_FlushConsoleInputBuffer(HANDLE input, HANDLE output)
2105 INPUT_RECORD record;
2106 DWORD count;
2107 BOOL ret;
2109 ret = FlushConsoleInputBuffer(input);
2110 ok(ret, "FlushConsoleInputBuffer failed: %u\n", GetLastError());
2112 ret = GetNumberOfConsoleInputEvents(input, &count);
2113 ok(ret, "GetNumberOfConsoleInputEvents failed: %u\n", GetLastError());
2114 ok(count == 0, "Expected count to be 0, got %u\n", count);
2116 record.EventType = KEY_EVENT;
2117 record.Event.KeyEvent.bKeyDown = 1;
2118 record.Event.KeyEvent.wRepeatCount = 1;
2119 record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
2120 record.Event.KeyEvent.wVirtualScanCode = VK_RETURN;
2121 record.Event.KeyEvent.uChar.UnicodeChar = '\r';
2122 record.Event.KeyEvent.dwControlKeyState = 0;
2123 ret = WriteConsoleInputW(input, &record, 1, &count);
2124 ok(ret, "WriteConsoleInputW failed: %u\n", GetLastError());
2126 ret = GetNumberOfConsoleInputEvents(input, &count);
2127 ok(ret, "GetNumberOfConsoleInputEvents failed: %u\n", GetLastError());
2128 ok(count == 1, "Expected count to be 0, got %u\n", count);
2130 ret = FlushConsoleInputBuffer(input);
2131 ok(ret, "FlushConsoleInputBuffer failed: %u\n", GetLastError());
2133 ret = GetNumberOfConsoleInputEvents(input, &count);
2134 ok(ret, "GetNumberOfConsoleInputEvents failed: %u\n", GetLastError());
2135 ok(count == 0, "Expected count to be 0, got %u\n", count);
2137 ret = WriteConsoleInputW(input, &record, 1, &count);
2138 ok(ret, "WriteConsoleInputW failed: %u\n", GetLastError());
2140 ret = GetNumberOfConsoleInputEvents(input, &count);
2141 ok(ret, "GetNumberOfConsoleInputEvents failed: %u\n", GetLastError());
2142 ok(count == 1, "Expected count to be 0, got %u\n", count);
2144 ret = FlushFileBuffers(input);
2145 ok(ret, "FlushFileBuffers failed: %u\n", GetLastError());
2147 ret = GetNumberOfConsoleInputEvents(input, &count);
2148 ok(ret, "GetNumberOfConsoleInputEvents failed: %u\n", GetLastError());
2149 ok(count == 0, "Expected count to be 0, got %u\n", count);
2151 ret = FlushConsoleInputBuffer(output);
2152 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "FlushConsoleInputBuffer returned: %x(%u)\n",
2153 ret, GetLastError());
2155 ret = FlushFileBuffers(output);
2156 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "FlushFileBuffers returned: %x(%u)\n",
2157 ret, GetLastError());
2160 static void test_WriteConsoleOutputCharacterA(HANDLE output_handle)
2162 static const char output[] = {'a', 0};
2164 COORD origin = {0, 0};
2165 DWORD count;
2166 BOOL ret;
2167 int i;
2169 const struct
2171 HANDLE hConsoleOutput;
2172 LPCSTR str;
2173 DWORD length;
2174 COORD coord;
2175 LPDWORD lpNumCharsWritten;
2176 DWORD expected_count;
2177 DWORD last_error;
2178 int win7_crash;
2179 } invalid_table[] =
2181 {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2182 {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2183 {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2184 {NULL, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2185 {NULL, output, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2186 {NULL, output, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2187 {NULL, output, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2188 {NULL, output, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2189 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2190 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2191 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2192 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2193 {INVALID_HANDLE_VALUE, output, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2194 {INVALID_HANDLE_VALUE, output, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2195 {INVALID_HANDLE_VALUE, output, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2196 {INVALID_HANDLE_VALUE, output, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2197 {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2198 {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2199 {output_handle, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2200 {output_handle, output, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2201 {output_handle, output, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2204 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2206 if (invalid_table[i].win7_crash)
2207 continue;
2209 SetLastError(0xdeadbeef);
2210 if (invalid_table[i].lpNumCharsWritten) count = 0xdeadbeef;
2211 ret = WriteConsoleOutputCharacterA(invalid_table[i].hConsoleOutput,
2212 invalid_table[i].str,
2213 invalid_table[i].length,
2214 invalid_table[i].coord,
2215 invalid_table[i].lpNumCharsWritten);
2216 ok(!ret, "[%d] Expected WriteConsoleOutputCharacterA to return FALSE, got %d\n", i, ret);
2217 if (invalid_table[i].lpNumCharsWritten)
2219 ok(count == invalid_table[i].expected_count,
2220 "[%d] Expected count to be %u, got %u\n",
2221 i, invalid_table[i].expected_count, count);
2223 ok(GetLastError() == invalid_table[i].last_error,
2224 "[%d] Expected last error to be %u, got %u\n",
2225 i, invalid_table[i].last_error, GetLastError());
2228 count = 0xdeadbeef;
2229 ret = WriteConsoleOutputCharacterA(output_handle, NULL, 0, origin, &count);
2230 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2231 ok(count == 0, "Expected count to be 0, got %u\n", count);
2233 count = 0xdeadbeef;
2234 ret = WriteConsoleOutputCharacterA(output_handle, output, 0, origin, &count);
2235 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2236 ok(count == 0, "Expected count to be 0, got %u\n", count);
2238 count = 0xdeadbeef;
2239 ret = WriteConsoleOutputCharacterA(output_handle, output, 1, origin, &count);
2240 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2241 ok(count == 1, "Expected count to be 1, got %u\n", count);
2243 count = 0xdeadbeef;
2244 origin.X = 200;
2245 ret = WriteConsoleOutputCharacterA(output_handle, output, 0, origin, &count);
2246 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2247 ok(count == 0, "Expected count to be 0, got %u\n", count);
2250 static void test_WriteConsoleOutputCharacterW(HANDLE output_handle)
2252 static const WCHAR outputW[] = {'a',0};
2254 COORD origin = {0, 0};
2255 DWORD count;
2256 BOOL ret;
2257 int i;
2259 const struct
2261 HANDLE hConsoleOutput;
2262 LPCWSTR str;
2263 DWORD length;
2264 COORD coord;
2265 LPDWORD lpNumCharsWritten;
2266 DWORD expected_count;
2267 DWORD last_error;
2268 int win7_crash;
2269 } invalid_table[] =
2271 {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2272 {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2273 {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2274 {NULL, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2275 {NULL, outputW, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2276 {NULL, outputW, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2277 {NULL, outputW, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2278 {NULL, outputW, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2279 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2280 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2281 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2282 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2283 {INVALID_HANDLE_VALUE, outputW, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2284 {INVALID_HANDLE_VALUE, outputW, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2285 {INVALID_HANDLE_VALUE, outputW, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2286 {INVALID_HANDLE_VALUE, outputW, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2287 {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2288 {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2289 {output_handle, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2290 {output_handle, outputW, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2291 {output_handle, outputW, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2294 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2296 if (invalid_table[i].win7_crash)
2297 continue;
2299 SetLastError(0xdeadbeef);
2300 if (invalid_table[i].lpNumCharsWritten) count = 0xdeadbeef;
2301 ret = WriteConsoleOutputCharacterW(invalid_table[i].hConsoleOutput,
2302 invalid_table[i].str,
2303 invalid_table[i].length,
2304 invalid_table[i].coord,
2305 invalid_table[i].lpNumCharsWritten);
2306 ok(!ret, "[%d] Expected WriteConsoleOutputCharacterW to return FALSE, got %d\n", i, ret);
2307 if (invalid_table[i].lpNumCharsWritten)
2309 ok(count == invalid_table[i].expected_count,
2310 "[%d] Expected count to be %u, got %u\n",
2311 i, invalid_table[i].expected_count, count);
2313 ok(GetLastError() == invalid_table[i].last_error,
2314 "[%d] Expected last error to be %u, got %u\n",
2315 i, invalid_table[i].last_error, GetLastError());
2318 count = 0xdeadbeef;
2319 ret = WriteConsoleOutputCharacterW(output_handle, NULL, 0, origin, &count);
2320 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2321 ok(count == 0, "Expected count to be 0, got %u\n", count);
2323 count = 0xdeadbeef;
2324 ret = WriteConsoleOutputCharacterW(output_handle, outputW, 0, origin, &count);
2325 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2326 ok(count == 0, "Expected count to be 0, got %u\n", count);
2328 count = 0xdeadbeef;
2329 ret = WriteConsoleOutputCharacterW(output_handle, outputW, 1, origin, &count);
2330 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2331 ok(count == 1, "Expected count to be 1, got %u\n", count);
2333 count = 0xdeadbeef;
2334 origin.X = 200;
2335 ret = WriteConsoleOutputCharacterW(output_handle, outputW, 0, origin, &count);
2336 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2337 ok(count == 0, "Expected count to be 0, got %u\n", count);
2341 static void test_WriteConsoleOutputAttribute(HANDLE output_handle)
2343 WORD attr = FOREGROUND_BLUE;
2344 COORD origin = {0, 0};
2345 DWORD count;
2346 BOOL ret;
2347 int i;
2349 const struct
2351 HANDLE hConsoleOutput;
2352 const WORD *attr;
2353 DWORD length;
2354 COORD coord;
2355 LPDWORD lpNumAttrsWritten;
2356 DWORD expected_count;
2357 DWORD last_error;
2358 int win7_crash;
2359 } invalid_table[] =
2361 {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2362 {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2363 {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2364 {NULL, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2365 {NULL, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2366 {NULL, &attr, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2367 {NULL, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2368 {NULL, &attr, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2369 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2370 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2371 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2372 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2373 {INVALID_HANDLE_VALUE, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2374 {INVALID_HANDLE_VALUE, &attr, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2375 {INVALID_HANDLE_VALUE, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2376 {INVALID_HANDLE_VALUE, &attr, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2377 {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2378 {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2379 {output_handle, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2380 {output_handle, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2381 {output_handle, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2384 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2386 if (invalid_table[i].win7_crash)
2387 continue;
2389 SetLastError(0xdeadbeef);
2390 if (invalid_table[i].lpNumAttrsWritten) count = 0xdeadbeef;
2391 ret = WriteConsoleOutputAttribute(invalid_table[i].hConsoleOutput,
2392 invalid_table[i].attr,
2393 invalid_table[i].length,
2394 invalid_table[i].coord,
2395 invalid_table[i].lpNumAttrsWritten);
2396 ok(!ret, "[%d] Expected WriteConsoleOutputAttribute to return FALSE, got %d\n", i, ret);
2397 if (invalid_table[i].lpNumAttrsWritten)
2399 ok(count == invalid_table[i].expected_count,
2400 "[%d] Expected count to be %u, got %u\n",
2401 i, invalid_table[i].expected_count, count);
2403 ok(GetLastError() == invalid_table[i].last_error,
2404 "[%d] Expected last error to be %u, got %u\n",
2405 i, invalid_table[i].last_error, GetLastError());
2408 count = 0xdeadbeef;
2409 ret = WriteConsoleOutputAttribute(output_handle, NULL, 0, origin, &count);
2410 ok(ret == TRUE, "Expected WriteConsoleOutputAttribute to return TRUE, got %d\n", ret);
2411 ok(count == 0, "Expected count to be 0, got %u\n", count);
2413 count = 0xdeadbeef;
2414 ret = WriteConsoleOutputAttribute(output_handle, &attr, 0, origin, &count);
2415 ok(ret == TRUE, "Expected WriteConsoleOutputAttribute to return TRUE, got %d\n", ret);
2416 ok(count == 0, "Expected count to be 0, got %u\n", count);
2418 count = 0xdeadbeef;
2419 ret = WriteConsoleOutputAttribute(output_handle, &attr, 1, origin, &count);
2420 ok(ret == TRUE, "Expected WriteConsoleOutputAttribute to return TRUE, got %d\n", ret);
2421 ok(count == 1, "Expected count to be 1, got %u\n", count);
2423 count = 0xdeadbeef;
2424 origin.X = 200;
2425 ret = WriteConsoleOutputAttribute(output_handle, &attr, 0, origin, &count);
2426 ok(ret == TRUE, "Expected WriteConsoleOutputAttribute to return TRUE, got %d\n", ret);
2427 ok(count == 0, "Expected count to be 0, got %u\n", count);
2430 static void set_region(SMALL_RECT *region, unsigned int left, unsigned int top, unsigned int right, unsigned int bottom)
2432 region->Left = left;
2433 region->Top = top;
2434 region->Right = right;
2435 region->Bottom = bottom;
2438 #define check_region(a,b,c,d,e) check_region_(__LINE__,a,b,c,d,e)
2439 static void check_region_(unsigned int line, const SMALL_RECT *region, unsigned int left, unsigned int top, int right, int bottom)
2441 ok_(__FILE__,line)(region->Left == left, "Left = %u, expected %u\n", region->Left, left);
2442 ok_(__FILE__,line)(region->Top == top, "Top = %u, expected %u\n", region->Top, top);
2443 /* In multiple places returned region depends on Windows versions: some return right < left, others leave it untouched */
2444 if (right >= 0)
2445 ok_(__FILE__,line)(region->Right == right, "Right = %u, expected %u\n", region->Right, right);
2446 else
2447 ok_(__FILE__,line)(region->Right == -right || region->Right == region->Left - 1,
2448 "Right = %u, expected %d\n", region->Right, right);
2449 if (bottom > 0)
2450 ok_(__FILE__,line)(region->Bottom == bottom, "Bottom = %u, expected %u\n", region->Bottom, bottom);
2451 else if (bottom < 0)
2452 ok_(__FILE__,line)(region->Bottom == -bottom || region->Bottom == region->Top - 1,
2453 "Bottom = %u, expected %d\n", region->Bottom, bottom);
2456 static void test_WriteConsoleOutput(HANDLE console)
2458 CONSOLE_SCREEN_BUFFER_INFO info;
2459 CHAR_INFO char_info_buf[2048];
2460 SMALL_RECT region;
2461 COORD size, coord;
2462 unsigned int i;
2463 BOOL ret;
2465 for (i = 0; i < ARRAY_SIZE(char_info_buf); i++)
2467 char_info_buf[i].Char.UnicodeChar = '0' + i % 10;
2468 char_info_buf[i].Attributes = 0;
2471 ret = GetConsoleScreenBufferInfo(console, &info);
2472 ok(ret, "GetConsoleScreenBufferInfo failed: %u\n", GetLastError());
2474 size.X = 23;
2475 size.Y = 17;
2476 coord.X = 2;
2477 coord.Y = 3;
2478 set_region(&region, 10, 7, 15, 11);
2479 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region);
2480 ok(ret, "WriteConsoleOutputW failed: %u\n", GetLastError());
2481 check_region(&region, 10, 7, 15, 11);
2483 size.X = 23;
2484 size.Y = 17;
2485 coord.X = 2;
2486 coord.Y = 3;
2487 set_region(&region, 200, 7, 15, 211);
2488 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region);
2489 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%u)\n", ret, GetLastError());
2490 check_region(&region, 200, 7, 15, 211);
2492 size.X = 23;
2493 size.Y = 17;
2494 coord.X = 2;
2495 coord.Y = 3;
2496 set_region(&region, 200, 7, 211, 8);
2497 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region);
2498 ok(ret, "WriteConsoleOutputW failed: %u\n", GetLastError());
2499 check_region(&region, 200, 7, 211, 8);
2501 size.X = 23;
2502 size.Y = 17;
2503 coord.X = 2;
2504 coord.Y = 3;
2505 set_region(&region, 10, 7, 9, 11);
2506 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region);
2507 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%u)\n", ret, GetLastError());
2508 check_region(&region, 10, 7, 9, 11);
2510 size.X = 23;
2511 size.Y = 17;
2512 coord.X = 2;
2513 coord.Y = 3;
2514 set_region(&region, 10, 7, 11, 6);
2515 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region);
2516 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%u)\n", ret, GetLastError());
2517 check_region(&region, 10, 7, 11, 6);
2519 size.X = 2;
2520 size.Y = 17;
2521 coord.X = 2;
2522 coord.Y = 3;
2523 set_region(&region, 10, 7, 15, 11);
2524 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region);
2525 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%u)\n", ret, GetLastError());
2526 check_region(&region, 10, 7, 15, 11);
2528 size.X = 23;
2529 size.Y = 3;
2530 coord.X = 2;
2531 coord.Y = 3;
2532 set_region(&region, 10, 7, 15, 11);
2533 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region);
2534 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%u)\n", ret, GetLastError());
2535 check_region(&region, 10, 7, 15, 11);
2537 size.X = 6;
2538 size.Y = 17;
2539 coord.X = 2;
2540 coord.Y = 3;
2541 set_region(&region, 10, 7, 15, 11);
2542 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region);
2543 ok(ret, "WriteConsoleOutputW failed: %u\n", GetLastError());
2544 check_region(&region, 10, 7, 13, 11);
2546 size.X = 6;
2547 size.Y = 17;
2548 coord.X = 2;
2549 coord.Y = 3;
2550 set_region(&region, 10, 7, 15, 11);
2551 ret = WriteConsoleOutputW((HANDLE)0xdeadbeef, char_info_buf, size, coord, &region);
2552 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "WriteConsoleOutputW returned: %x(%u)\n", ret, GetLastError());
2553 if (!skip_nt) check_region(&region, 10, 7, 13, 11);
2555 size.X = 16;
2556 size.Y = 7;
2557 coord.X = 2;
2558 coord.Y = 3;
2559 set_region(&region, 10, 7, 15, 11);
2560 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region);
2561 ok(ret, "WriteConsoleOutputW failed: %u\n", GetLastError());
2562 check_region(&region, 10, 7, 15, 10);
2564 size.X = 16;
2565 size.Y = 7;
2566 coord.X = 2;
2567 coord.Y = 3;
2568 set_region(&region, info.dwSize.X - 2, 7, info.dwSize.X + 2, 7);
2569 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region);
2570 ok(ret, "WriteConsoleOutputW failed: %u\n", GetLastError());
2571 check_region(&region, info.dwSize.X - 2, 7, info.dwSize.X - 1, 7);
2574 static void test_FillConsoleOutputCharacterA(HANDLE output_handle)
2576 COORD origin = {0, 0};
2577 DWORD count;
2578 BOOL ret;
2579 int i;
2581 const struct
2583 HANDLE hConsoleOutput;
2584 CHAR ch;
2585 DWORD length;
2586 COORD coord;
2587 LPDWORD lpNumCharsWritten;
2588 DWORD last_error;
2589 int win7_crash;
2590 } invalid_table[] =
2592 {NULL, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2593 {NULL, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2594 {NULL, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2595 {NULL, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2596 {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2597 {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2598 {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2599 {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2600 {output_handle, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2601 {output_handle, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2604 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2606 if (invalid_table[i].win7_crash)
2607 continue;
2609 SetLastError(0xdeadbeef);
2610 if (invalid_table[i].lpNumCharsWritten) count = 0xdeadbeef;
2611 ret = FillConsoleOutputCharacterA(invalid_table[i].hConsoleOutput,
2612 invalid_table[i].ch,
2613 invalid_table[i].length,
2614 invalid_table[i].coord,
2615 invalid_table[i].lpNumCharsWritten);
2616 ok(!ret, "[%d] Expected FillConsoleOutputCharacterA to return FALSE, got %d\n", i, ret);
2617 ok(GetLastError() == invalid_table[i].last_error,
2618 "[%d] Expected last error to be %u, got %u\n",
2619 i, invalid_table[i].last_error, GetLastError());
2622 count = 0xdeadbeef;
2623 ret = FillConsoleOutputCharacterA(output_handle, 'a', 0, origin, &count);
2624 ok(ret == TRUE, "Expected FillConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2625 ok(count == 0, "Expected count to be 0, got %u\n", count);
2627 count = 0xdeadbeef;
2628 ret = FillConsoleOutputCharacterA(output_handle, 'a', 1, origin, &count);
2629 ok(ret == TRUE, "Expected FillConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2630 ok(count == 1, "Expected count to be 1, got %u\n", count);
2633 static void test_FillConsoleOutputCharacterW(HANDLE output_handle)
2635 COORD origin = {0, 0};
2636 DWORD count;
2637 BOOL ret;
2638 int i;
2640 const struct
2642 HANDLE hConsoleOutput;
2643 WCHAR ch;
2644 DWORD length;
2645 COORD coord;
2646 LPDWORD lpNumCharsWritten;
2647 DWORD last_error;
2648 int win7_crash;
2649 } invalid_table[] =
2651 {NULL, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2652 {NULL, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2653 {NULL, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2654 {NULL, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2655 {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2656 {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2657 {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2658 {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2659 {output_handle, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2660 {output_handle, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2663 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2665 if (invalid_table[i].win7_crash)
2666 continue;
2668 SetLastError(0xdeadbeef);
2669 if (invalid_table[i].lpNumCharsWritten) count = 0xdeadbeef;
2670 ret = FillConsoleOutputCharacterW(invalid_table[i].hConsoleOutput,
2671 invalid_table[i].ch,
2672 invalid_table[i].length,
2673 invalid_table[i].coord,
2674 invalid_table[i].lpNumCharsWritten);
2675 ok(!ret, "[%d] Expected FillConsoleOutputCharacterW to return FALSE, got %d\n", i, ret);
2676 ok(GetLastError() == invalid_table[i].last_error,
2677 "[%d] Expected last error to be %u, got %u\n",
2678 i, invalid_table[i].last_error, GetLastError());
2681 count = 0xdeadbeef;
2682 ret = FillConsoleOutputCharacterW(output_handle, 'a', 0, origin, &count);
2683 ok(ret == TRUE, "Expected FillConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2684 ok(count == 0, "Expected count to be 0, got %u\n", count);
2686 count = 0xdeadbeef;
2687 ret = FillConsoleOutputCharacterW(output_handle, 'a', 1, origin, &count);
2688 ok(ret == TRUE, "Expected FillConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2689 ok(count == 1, "Expected count to be 1, got %u\n", count);
2692 static void test_FillConsoleOutputAttribute(HANDLE output_handle)
2694 COORD origin = {0, 0};
2695 DWORD count;
2696 BOOL ret;
2697 int i;
2699 const struct
2701 HANDLE hConsoleOutput;
2702 WORD attr;
2703 DWORD length;
2704 COORD coord;
2705 LPDWORD lpNumAttrsWritten;
2706 DWORD last_error;
2707 int win7_crash;
2708 } invalid_table[] =
2710 {NULL, FOREGROUND_BLUE, 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2711 {NULL, FOREGROUND_BLUE, 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2712 {NULL, FOREGROUND_BLUE, 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2713 {NULL, FOREGROUND_BLUE, 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2714 {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2715 {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2716 {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2717 {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2718 {output_handle, FOREGROUND_BLUE, 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2719 {output_handle, FOREGROUND_BLUE, 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2722 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2724 if (invalid_table[i].win7_crash)
2725 continue;
2727 SetLastError(0xdeadbeef);
2728 if (invalid_table[i].lpNumAttrsWritten) count = 0xdeadbeef;
2729 ret = FillConsoleOutputAttribute(invalid_table[i].hConsoleOutput,
2730 invalid_table[i].attr,
2731 invalid_table[i].length,
2732 invalid_table[i].coord,
2733 invalid_table[i].lpNumAttrsWritten);
2734 ok(!ret, "[%d] Expected FillConsoleOutputAttribute to return FALSE, got %d\n", i, ret);
2735 ok(GetLastError() == invalid_table[i].last_error,
2736 "[%d] Expected last error to be %u, got %u\n",
2737 i, invalid_table[i].last_error, GetLastError());
2740 count = 0xdeadbeef;
2741 ret = FillConsoleOutputAttribute(output_handle, FOREGROUND_BLUE, 0, origin, &count);
2742 ok(ret == TRUE, "Expected FillConsoleOutputAttribute to return TRUE, got %d\n", ret);
2743 ok(count == 0, "Expected count to be 0, got %u\n", count);
2745 count = 0xdeadbeef;
2746 ret = FillConsoleOutputAttribute(output_handle, FOREGROUND_BLUE, 1, origin, &count);
2747 ok(ret == TRUE, "Expected FillConsoleOutputAttribute to return TRUE, got %d\n", ret);
2748 ok(count == 1, "Expected count to be 1, got %u\n", count);
2750 count = 0xdeadbeef;
2751 ret = FillConsoleOutputAttribute(output_handle, ~0, 1, origin, &count);
2752 ok(ret == TRUE, "Expected FillConsoleOutputAttribute to return TRUE, got %d\n", ret);
2753 ok(count == 1, "Expected count to be 1, got %u\n", count);
2756 static void test_ReadConsoleOutputCharacterA(HANDLE output_handle)
2758 CHAR read;
2759 COORD origin = {0, 0};
2760 DWORD count;
2761 BOOL ret;
2762 int i;
2764 const struct
2766 HANDLE hConsoleOutput;
2767 LPSTR lpstr;
2768 DWORD length;
2769 COORD coord;
2770 LPDWORD read_count;
2771 DWORD expected_count;
2772 DWORD last_error;
2773 int win7_crash;
2774 } invalid_table[] =
2776 {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2777 {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2778 {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2779 {NULL, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
2780 {NULL, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2781 {NULL, &read, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2782 {NULL, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2783 {NULL, &read, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2784 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2785 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2786 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2787 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
2788 {INVALID_HANDLE_VALUE, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2789 {INVALID_HANDLE_VALUE, &read, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2790 {INVALID_HANDLE_VALUE, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2791 {INVALID_HANDLE_VALUE, &read, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2792 {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2793 {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2794 {output_handle, NULL, 1, {0, 0}, &count, 1, ERROR_INVALID_ACCESS, 1},
2795 {output_handle, NULL, 10, {0, 0}, &count, 10, ERROR_INVALID_ACCESS, 1},
2796 {output_handle, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2797 {output_handle, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2800 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2802 if (invalid_table[i].win7_crash)
2803 continue;
2805 SetLastError(0xdeadbeef);
2806 if (invalid_table[i].read_count) count = 0xdeadbeef;
2807 ret = ReadConsoleOutputCharacterA(invalid_table[i].hConsoleOutput,
2808 invalid_table[i].lpstr,
2809 invalid_table[i].length,
2810 invalid_table[i].coord,
2811 invalid_table[i].read_count);
2812 ok(!ret, "[%d] Expected ReadConsoleOutputCharacterA to return FALSE, got %d\n", i, ret);
2813 if (invalid_table[i].read_count)
2815 ok(count == invalid_table[i].expected_count,
2816 "[%d] Expected count to be %u, got %u\n",
2817 i, invalid_table[i].expected_count, count);
2819 ok(GetLastError() == invalid_table[i].last_error,
2820 "[%d] Expected last error to be %u, got %u\n",
2821 i, invalid_table[i].last_error, GetLastError());
2824 count = 0xdeadbeef;
2825 ret = ReadConsoleOutputCharacterA(output_handle, NULL, 0, origin, &count);
2826 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2827 ok(count == 0, "Expected count to be 0, got %u\n", count);
2829 count = 0xdeadbeef;
2830 ret = ReadConsoleOutputCharacterA(output_handle, &read, 0, origin, &count);
2831 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2832 ok(count == 0, "Expected count to be 0, got %u\n", count);
2834 count = 0xdeadbeef;
2835 ret = ReadConsoleOutputCharacterA(output_handle, &read, 1, origin, &count);
2836 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2837 ok(count == 1, "Expected count to be 1, got %u\n", count);
2839 count = 0xdeadbeef;
2840 origin.X = 200;
2841 ret = ReadConsoleOutputCharacterA(output_handle, &read, 1, origin, &count);
2842 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2843 ok(count == 0, "Expected count to be 0, got %u\n", count);
2846 static void test_ReadConsoleOutputCharacterW(HANDLE output_handle)
2848 WCHAR read;
2849 COORD origin = {0, 0};
2850 DWORD count;
2851 BOOL ret;
2852 int i;
2854 const struct
2856 HANDLE hConsoleOutput;
2857 LPWSTR buffer;
2858 DWORD length;
2859 COORD coord;
2860 LPDWORD read_count;
2861 DWORD expected_count;
2862 DWORD last_error;
2863 int win7_crash;
2864 } invalid_table[] =
2866 {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2867 {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2868 {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2869 {NULL, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
2870 {NULL, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2871 {NULL, &read, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2872 {NULL, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2873 {NULL, &read, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2874 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2875 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2876 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2877 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
2878 {INVALID_HANDLE_VALUE, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2879 {INVALID_HANDLE_VALUE, &read, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2880 {INVALID_HANDLE_VALUE, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2881 {INVALID_HANDLE_VALUE, &read, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2882 {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2883 {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2884 {output_handle, NULL, 1, {0, 0}, &count, 1, ERROR_INVALID_ACCESS, 1},
2885 {output_handle, NULL, 10, {0, 0}, &count, 10, ERROR_INVALID_ACCESS, 1},
2886 {output_handle, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2887 {output_handle, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2890 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2892 if (invalid_table[i].win7_crash)
2893 continue;
2895 SetLastError(0xdeadbeef);
2896 if (invalid_table[i].read_count) count = 0xdeadbeef;
2897 ret = ReadConsoleOutputCharacterW(invalid_table[i].hConsoleOutput,
2898 invalid_table[i].buffer,
2899 invalid_table[i].length,
2900 invalid_table[i].coord,
2901 invalid_table[i].read_count);
2902 ok(!ret, "[%d] Expected ReadConsoleOutputCharacterW to return FALSE, got %d\n", i, ret);
2903 if (invalid_table[i].read_count)
2905 ok(count == invalid_table[i].expected_count,
2906 "[%d] Expected count to be %u, got %u\n",
2907 i, invalid_table[i].expected_count, count);
2909 ok(GetLastError() == invalid_table[i].last_error,
2910 "[%d] Expected last error to be %u, got %u\n",
2911 i, invalid_table[i].last_error, GetLastError());
2914 count = 0xdeadbeef;
2915 ret = ReadConsoleOutputCharacterW(output_handle, NULL, 0, origin, &count);
2916 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2917 ok(count == 0, "Expected count to be 0, got %u\n", count);
2919 count = 0xdeadbeef;
2920 ret = ReadConsoleOutputCharacterW(output_handle, &read, 0, origin, &count);
2921 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2922 ok(count == 0, "Expected count to be 0, got %u\n", count);
2924 count = 0xdeadbeef;
2925 ret = ReadConsoleOutputCharacterW(output_handle, &read, 1, origin, &count);
2926 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2927 ok(count == 1, "Expected count to be 1, got %u\n", count);
2929 count = 0xdeadbeef;
2930 origin.X = 200;
2931 ret = ReadConsoleOutputCharacterW(output_handle, &read, 1, origin, &count);
2932 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2933 ok(count == 0, "Expected count to be 0, got %u\n", count);
2936 static void test_ReadConsoleOutputAttribute(HANDLE output_handle)
2938 WORD attr;
2939 COORD origin = {0, 0};
2940 DWORD count;
2941 BOOL ret;
2942 int i;
2944 const struct
2946 HANDLE hConsoleOutput;
2947 LPWORD lpAttribute;
2948 DWORD length;
2949 COORD coord;
2950 LPDWORD read_count;
2951 DWORD expected_count;
2952 DWORD last_error;
2953 int win7_crash;
2954 } invalid_table[] =
2956 {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2957 {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2958 {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2959 {NULL, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
2960 {NULL, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2961 {NULL, &attr, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2962 {NULL, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2963 {NULL, &attr, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2964 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2965 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2966 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2967 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
2968 {INVALID_HANDLE_VALUE, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2969 {INVALID_HANDLE_VALUE, &attr, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2970 {INVALID_HANDLE_VALUE, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2971 {INVALID_HANDLE_VALUE, &attr, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2972 {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2973 {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2974 {output_handle, NULL, 1, {0, 0}, &count, 1, ERROR_INVALID_ACCESS, 1},
2975 {output_handle, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2976 {output_handle, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2979 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2981 if (invalid_table[i].win7_crash)
2982 continue;
2984 SetLastError(0xdeadbeef);
2985 if (invalid_table[i].read_count) count = 0xdeadbeef;
2986 ret = ReadConsoleOutputAttribute(invalid_table[i].hConsoleOutput,
2987 invalid_table[i].lpAttribute,
2988 invalid_table[i].length,
2989 invalid_table[i].coord,
2990 invalid_table[i].read_count);
2991 ok(!ret, "[%d] Expected ReadConsoleOutputAttribute to return FALSE, got %d\n", i, ret);
2992 if (invalid_table[i].read_count)
2994 ok(count == invalid_table[i].expected_count,
2995 "[%d] Expected count to be %u, got %u\n",
2996 i, invalid_table[i].expected_count, count);
2998 ok(GetLastError() == invalid_table[i].last_error,
2999 "[%d] Expected last error to be %u, got %u\n",
3000 i, invalid_table[i].last_error, GetLastError());
3003 count = 0xdeadbeef;
3004 ret = ReadConsoleOutputAttribute(output_handle, NULL, 0, origin, &count);
3005 ok(ret == TRUE, "Expected ReadConsoleOutputAttribute to return TRUE, got %d\n", ret);
3006 ok(count == 0, "Expected count to be 0, got %u\n", count);
3008 count = 0xdeadbeef;
3009 ret = ReadConsoleOutputAttribute(output_handle, &attr, 0, origin, &count);
3010 ok(ret == TRUE, "Expected ReadConsoleOutputAttribute to return TRUE, got %d\n", ret);
3011 ok(count == 0, "Expected count to be 0, got %u\n", count);
3013 count = 0xdeadbeef;
3014 ret = ReadConsoleOutputAttribute(output_handle, &attr, 1, origin, &count);
3015 ok(ret == TRUE, "Expected ReadConsoleOutputAttribute to return TRUE, got %d\n", ret);
3016 ok(count == 1, "Expected count to be 1, got %u\n", count);
3018 count = 0xdeadbeef;
3019 origin.X = 200;
3020 ret = ReadConsoleOutputAttribute(output_handle, &attr, 1, origin, &count);
3021 ok(ret == TRUE, "Expected ReadConsoleOutputAttribute to return TRUE, got %d\n", ret);
3022 ok(count == 0, "Expected count to be 1, got %u\n", count);
3025 static void test_ReadConsoleOutput(HANDLE console)
3027 CONSOLE_SCREEN_BUFFER_INFO info;
3028 CHAR_INFO char_info_buf[2048];
3029 SMALL_RECT region;
3030 COORD size, coord;
3031 DWORD count;
3032 WCHAR ch;
3033 BOOL ret;
3035 if (skip_nt) return;
3037 ret = GetConsoleScreenBufferInfo(console, &info);
3038 ok(ret, "GetConsoleScreenBufferInfo failed: %u\n", GetLastError());
3040 size.X = 23;
3041 size.Y = 17;
3042 coord.X = 2;
3043 coord.Y = 3;
3044 set_region(&region, 10, 7, 15, 11);
3045 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region);
3046 ok(ret, "ReadConsoleOutputW failed: %u\n", GetLastError());
3047 check_region(&region, 10, 7, 15, 11);
3049 size.X = 23;
3050 size.Y = 17;
3051 coord.X = 2;
3052 coord.Y = 3;
3053 set_region(&region, 200, 7, 15, 211);
3054 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region);
3055 ok(!ret, "ReadConsoleOutputW returned: %x(%u)\n", ret, GetLastError());
3056 check_region(&region, 200, 7, -15, 0);
3058 size.X = 23;
3059 size.Y = 17;
3060 coord.X = 2;
3061 coord.Y = 3;
3062 set_region(&region, 200, 7, 211, 8);
3063 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region);
3064 ok((!ret && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_INVALID_FUNCTION)) || broken(ret /* win8 */),
3065 "ReadConsoleOutputW returned: %x %u\n", ret, GetLastError());
3066 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER) check_region(&region, 200, 7, -211, -8);
3068 size.X = 23;
3069 size.Y = 17;
3070 coord.X = 2;
3071 coord.Y = 3;
3072 set_region(&region, 10, 7, 9, 11);
3073 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region);
3074 ok((!ret && (GetLastError() == ERROR_INVALID_FUNCTION || GetLastError() == ERROR_NOT_ENOUGH_MEMORY)) || broken(ret /* win8 */),
3075 "ReadConsoleOutputW returned: %x(%u)\n", ret, GetLastError());
3076 check_region(&region, 10, 7, 9, -11);
3078 size.X = 23;
3079 size.Y = 17;
3080 coord.X = 2;
3081 coord.Y = 3;
3082 set_region(&region, 10, 7, 11, 6);
3083 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region);
3084 ok((!ret && (GetLastError() == ERROR_INVALID_FUNCTION || GetLastError() == ERROR_NOT_ENOUGH_MEMORY)) || broken(ret /* win8 */),
3085 "ReadConsoleOutputW returned: %x(%u)\n", ret, GetLastError());
3086 check_region(&region, 10, 7, -11, 6);
3088 size.X = 2;
3089 size.Y = 17;
3090 coord.X = 2;
3091 coord.Y = 3;
3092 set_region(&region, 10, 7, 15, 11);
3093 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region);
3094 ok((!ret && (GetLastError() == ERROR_INVALID_FUNCTION || GetLastError() == ERROR_NOT_ENOUGH_MEMORY)) || broken(ret /* win8 */),
3095 "ReadConsoleOutputW returned: %x(%u)\n", ret, GetLastError());
3096 check_region(&region, 10, 7, -15, -11);
3098 size.X = 23;
3099 size.Y = 3;
3100 coord.X = 2;
3101 coord.Y = 3;
3102 set_region(&region, 10, 7, 15, 11);
3103 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region);
3104 ok((!ret && (GetLastError() == ERROR_INVALID_FUNCTION || GetLastError() == ERROR_NOT_ENOUGH_MEMORY)) || broken(ret /* win8 */),
3105 "ReadConsoleOutputW returned: %x(%u)\n", ret, GetLastError());
3106 check_region(&region, 10, 7, -15, 6);
3108 size.X = 6;
3109 size.Y = 17;
3110 coord.X = 2;
3111 coord.Y = 3;
3112 set_region(&region, 10, 7, 15, 11);
3113 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region);
3114 ok(ret, "ReadConsoleOutputW failed: %u\n", GetLastError());
3115 check_region(&region, 10, 7, 13, 11);
3117 size.X = 6;
3118 size.Y = 17;
3119 coord.X = 2;
3120 coord.Y = 3;
3121 set_region(&region, 10, 7, 15, 11);
3122 ret = ReadConsoleOutputW((HANDLE)0xdeadbeef, char_info_buf, size, coord, &region);
3123 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "ReadConsoleOutputW returned: %x(%u)\n", ret, GetLastError());
3124 if (!skip_nt) check_region(&region, 10, 7, 13, 11);
3126 size.X = 16;
3127 size.Y = 7;
3128 coord.X = 2;
3129 coord.Y = 3;
3130 set_region(&region, 10, 7, 15, 11);
3131 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region);
3132 ok(ret, "ReadConsoleOutputW failed: %u\n", GetLastError());
3133 check_region(&region, 10, 7, 15, 10);
3135 size.X = 16;
3136 size.Y = 7;
3137 coord.X = 2;
3138 coord.Y = 3;
3139 set_region(&region, info.dwSize.X - 2, 7, info.dwSize.X + 2, 7);
3140 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region);
3141 ok(ret || GetLastError() == ERROR_INVALID_PARAMETER, "ReadConsoleOutputW failed: %u\n", GetLastError());
3142 if (ret) check_region(&region, info.dwSize.X - 2, 7, info.dwSize.X - 1, 7);
3144 coord.X = 2;
3145 coord.Y = 3;
3146 ret = WriteConsoleOutputCharacterW(console, L"xyz", 3, coord, &count);
3147 ok(ret, "WriteConsoleOutputCharacterW failed: %u\n", GetLastError());
3148 ok(count == 3, "count = %u\n", count);
3150 memset(char_info_buf, 0xc0, sizeof(char_info_buf));
3151 size.X = 16;
3152 size.Y = 7;
3153 coord.X = 5;
3154 coord.Y = 6;
3155 set_region(&region, 2, 3, 5, 3);
3156 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region);
3157 ok(ret, "ReadConsoleOutputW failed: %u\n", GetLastError());
3158 check_region(&region, 2, 3, 5, 3);
3159 ch = char_info_buf[coord.Y * size.X + coord.X].Char.UnicodeChar;
3160 ok(ch == 'x', "unexpected char %c/%x\n", ch, ch);
3161 ch = char_info_buf[coord.Y * size.X + coord.X + 1].Char.UnicodeChar;
3162 ok(ch == 'y', "unexpected char %c/%x\n", ch, ch);
3163 ch = char_info_buf[coord.Y * size.X + coord.X + 2].Char.UnicodeChar;
3164 ok(ch == 'z', "unexpected char %c/%x\n", ch, ch);
3167 static void test_ReadConsole(HANDLE input)
3169 DWORD ret, bytes;
3170 char buf[1024];
3171 HANDLE output;
3173 SetLastError(0xdeadbeef);
3174 ret = GetFileSize(input, NULL);
3175 ok(ret == INVALID_FILE_SIZE, "expected INVALID_FILE_SIZE, got %#x\n", ret);
3176 ok(GetLastError() == ERROR_INVALID_HANDLE ||
3177 GetLastError() == ERROR_INVALID_FUNCTION, /* Win 8, 10 */
3178 "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
3180 bytes = 0xdeadbeef;
3181 SetLastError(0xdeadbeef);
3182 ret = ReadFile(input, buf, -128, &bytes, NULL);
3183 ok(!ret, "expected 0, got %u\n", ret);
3184 ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
3185 GetLastError() == ERROR_NOACCESS, /* Win 8, 10 */
3186 "expected ERROR_NOT_ENOUGH_MEMORY, got %d\n", GetLastError());
3187 ok(!bytes, "expected 0, got %u\n", bytes);
3189 bytes = 0xdeadbeef;
3190 SetLastError(0xdeadbeef);
3191 ret = ReadConsoleA(input, buf, -128, &bytes, NULL);
3192 ok(!ret, "expected 0, got %u\n", ret);
3193 ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
3194 GetLastError() == ERROR_NOACCESS, /* Win 8, 10 */
3195 "expected ERROR_NOT_ENOUGH_MEMORY, got %d\n", GetLastError());
3196 ok(bytes == 0xdeadbeef, "expected 0xdeadbeef, got %#x\n", bytes);
3198 bytes = 0xdeadbeef;
3199 SetLastError(0xdeadbeef);
3200 ret = ReadConsoleW(input, buf, -128, &bytes, NULL);
3201 ok(!ret, "expected 0, got %u\n", ret);
3202 ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
3203 GetLastError() == ERROR_NOACCESS, /* Win 8, 10 */
3204 "expected ERROR_NOT_ENOUGH_MEMORY, got %d\n", GetLastError());
3205 ok(bytes == 0xdeadbeef, "expected 0xdeadbeef, got %#x\n", bytes);
3207 output = CreateFileA("CONOUT$", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
3208 ok(output != INVALID_HANDLE_VALUE, "Could not open console\n");
3210 ret = ReadConsoleW(output, buf, sizeof(buf) / sizeof(WCHAR), &bytes, NULL);
3211 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
3212 "ReadConsoleW returned %x(%u)\n", ret, GetLastError());
3214 ret = ReadConsoleA(output, buf, sizeof(buf), &bytes, NULL);
3215 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
3216 "ReadConsoleA returned %x(%u)\n", ret, GetLastError());
3218 ret = ReadFile(output, buf, sizeof(buf), &bytes, NULL);
3219 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
3220 "ReadFile returned %x(%u)\n", ret, GetLastError());
3222 CloseHandle(output);
3225 static void test_GetCurrentConsoleFont(HANDLE std_output)
3227 BOOL ret;
3228 CONSOLE_FONT_INFO cfi;
3229 CONSOLE_SCREEN_BUFFER_INFO csbi;
3230 short int width, height;
3231 HANDLE pipe1, pipe2;
3232 COORD c;
3234 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3235 SetLastError(0xdeadbeef);
3236 ret = GetCurrentConsoleFont(NULL, FALSE, &cfi);
3237 ok(!ret, "got %d, expected 0\n", ret);
3238 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3239 ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
3240 ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
3242 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3243 SetLastError(0xdeadbeef);
3244 ret = GetCurrentConsoleFont(NULL, TRUE, &cfi);
3245 ok(!ret, "got %d, expected 0\n", ret);
3246 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3247 ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
3248 ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
3250 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3251 SetLastError(0xdeadbeef);
3252 ret = GetCurrentConsoleFont(GetStdHandle(STD_INPUT_HANDLE), FALSE, &cfi);
3253 ok(!ret, "got %d, expected 0\n", ret);
3254 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3255 ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
3256 ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
3258 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3259 SetLastError(0xdeadbeef);
3260 ret = GetCurrentConsoleFont(GetStdHandle(STD_INPUT_HANDLE), TRUE, &cfi);
3261 ok(!ret, "got %d, expected 0\n", ret);
3262 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3263 ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
3264 ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
3266 CreatePipe(&pipe1, &pipe2, NULL, 0);
3267 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3268 SetLastError(0xdeadbeef);
3269 ret = GetCurrentConsoleFont(pipe1, TRUE, &cfi);
3270 ok(!ret, "got %d, expected 0\n", ret);
3271 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3272 ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
3273 ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
3274 CloseHandle(pipe1);
3275 CloseHandle(pipe2);
3277 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3278 SetLastError(0xdeadbeef);
3279 ret = GetCurrentConsoleFont(std_output, FALSE, &cfi);
3280 ok(ret, "got %d, expected non-zero\n", ret);
3281 ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
3282 GetConsoleScreenBufferInfo(std_output, &csbi);
3283 width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
3284 height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
3285 c = GetConsoleFontSize(std_output, cfi.nFont);
3286 ok(cfi.dwFontSize.X == width || cfi.dwFontSize.X == c.X /* Vista and higher */,
3287 "got %d, expected %d\n", cfi.dwFontSize.X, width);
3288 ok(cfi.dwFontSize.Y == height || cfi.dwFontSize.Y == c.Y /* Vista and higher */,
3289 "got %d, expected %d\n", cfi.dwFontSize.Y, height);
3291 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3292 SetLastError(0xdeadbeef);
3293 ret = GetCurrentConsoleFont(std_output, TRUE, &cfi);
3294 ok(ret, "got %d, expected non-zero\n", ret);
3295 ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
3296 ok(cfi.dwFontSize.X == csbi.dwMaximumWindowSize.X,
3297 "got %d, expected %d\n", cfi.dwFontSize.X, csbi.dwMaximumWindowSize.X);
3298 ok(cfi.dwFontSize.Y == csbi.dwMaximumWindowSize.Y,
3299 "got %d, expected %d\n", cfi.dwFontSize.Y, csbi.dwMaximumWindowSize.Y);
3302 static void test_GetCurrentConsoleFontEx(HANDLE std_output)
3304 HANDLE hmod;
3305 BOOL (WINAPI *pGetCurrentConsoleFontEx)(HANDLE, BOOL, CONSOLE_FONT_INFOEX *);
3306 CONSOLE_FONT_INFO cfi;
3307 CONSOLE_FONT_INFOEX cfix;
3308 BOOL ret;
3309 HANDLE std_input = GetStdHandle(STD_INPUT_HANDLE);
3310 HANDLE pipe1, pipe2;
3312 hmod = GetModuleHandleA("kernel32.dll");
3313 pGetCurrentConsoleFontEx = (void *)GetProcAddress(hmod, "GetCurrentConsoleFontEx");
3314 if (!pGetCurrentConsoleFontEx)
3316 win_skip("GetCurrentConsoleFontEx is not available\n");
3317 return;
3320 SetLastError(0xdeadbeef);
3321 ret = pGetCurrentConsoleFontEx(NULL, FALSE, &cfix);
3322 ok(!ret, "got %d, expected 0\n", ret);
3323 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError());
3325 SetLastError(0xdeadbeef);
3326 ret = pGetCurrentConsoleFontEx(NULL, TRUE, &cfix);
3327 ok(!ret, "got %d, expected 0\n", ret);
3328 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError());
3330 SetLastError(0xdeadbeef);
3331 ret = pGetCurrentConsoleFontEx(std_input, FALSE, &cfix);
3332 ok(!ret, "got %d, expected 0\n", ret);
3333 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError());
3335 SetLastError(0xdeadbeef);
3336 ret = pGetCurrentConsoleFontEx(std_input, TRUE, &cfix);
3337 ok(!ret, "got %d, expected 0\n", ret);
3338 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError());
3340 SetLastError(0xdeadbeef);
3341 ret = pGetCurrentConsoleFontEx(std_output, FALSE, &cfix);
3342 ok(!ret, "got %d, expected 0\n", ret);
3343 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError());
3345 SetLastError(0xdeadbeef);
3346 ret = pGetCurrentConsoleFontEx(std_output, TRUE, &cfix);
3347 ok(!ret, "got %d, expected 0\n", ret);
3348 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError());
3350 cfix.cbSize = sizeof(CONSOLE_FONT_INFOEX);
3352 SetLastError(0xdeadbeef);
3353 ret = pGetCurrentConsoleFontEx(NULL, FALSE, &cfix);
3354 ok(!ret, "got %d, expected 0\n", ret);
3355 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3357 SetLastError(0xdeadbeef);
3358 ret = pGetCurrentConsoleFontEx(NULL, TRUE, &cfix);
3359 ok(!ret, "got %d, expected 0\n", ret);
3360 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3362 SetLastError(0xdeadbeef);
3363 ret = pGetCurrentConsoleFontEx(std_input, FALSE, &cfix);
3364 ok(!ret, "got %d, expected 0\n", ret);
3365 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3367 SetLastError(0xdeadbeef);
3368 ret = pGetCurrentConsoleFontEx(std_input, TRUE, &cfix);
3369 ok(!ret, "got %d, expected 0\n", ret);
3370 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3372 CreatePipe(&pipe1, &pipe2, NULL, 0);
3373 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3374 SetLastError(0xdeadbeef);
3375 ret = pGetCurrentConsoleFontEx(pipe1, TRUE, &cfix);
3376 ok(!ret, "got %d, expected 0\n", ret);
3377 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3378 CloseHandle(pipe1);
3379 CloseHandle(pipe2);
3381 SetLastError(0xdeadbeef);
3382 ret = pGetCurrentConsoleFontEx(std_output, FALSE, &cfix);
3383 ok(ret, "got %d, expected non-zero\n", ret);
3384 ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
3386 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3387 SetLastError(0xdeadbeef);
3388 ret = GetCurrentConsoleFont(std_output, FALSE, &cfi);
3389 ok(ret, "got %d, expected non-zero\n", ret);
3390 ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
3392 ok(cfix.dwFontSize.X == cfi.dwFontSize.X, "expected values to match\n");
3393 ok(cfix.dwFontSize.Y == cfi.dwFontSize.Y, "expected values to match\n");
3395 SetLastError(0xdeadbeef);
3396 ret = pGetCurrentConsoleFontEx(std_output, TRUE, &cfix);
3397 ok(ret, "got %d, expected non-zero\n", ret);
3398 ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
3400 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3401 SetLastError(0xdeadbeef);
3402 ret = GetCurrentConsoleFont(std_output, TRUE, &cfi);
3403 ok(ret, "got %d, expected non-zero\n", ret);
3404 ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
3406 ok(cfix.dwFontSize.X == cfi.dwFontSize.X, "expected values to match\n");
3407 ok(cfix.dwFontSize.Y == cfi.dwFontSize.Y, "expected values to match\n");
3410 static void test_GetConsoleFontSize(HANDLE std_output)
3412 COORD c;
3413 DWORD index = 0;
3414 CONSOLE_FONT_INFO cfi;
3415 RECT r;
3416 CONSOLE_SCREEN_BUFFER_INFO csbi;
3417 LONG font_width, font_height;
3418 HMODULE hmod;
3419 DWORD (WINAPI *pGetNumberOfConsoleFonts)(void);
3420 HANDLE pipe1, pipe2;
3422 memset(&c, 10, sizeof(COORD));
3423 SetLastError(0xdeadbeef);
3424 c = GetConsoleFontSize(NULL, index);
3425 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3426 ok(!c.X, "got %d, expected 0\n", c.X);
3427 ok(!c.Y, "got %d, expected 0\n", c.Y);
3429 memset(&c, 10, sizeof(COORD));
3430 SetLastError(0xdeadbeef);
3431 c = GetConsoleFontSize(GetStdHandle(STD_INPUT_HANDLE), index);
3432 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3433 ok(!c.X, "got %d, expected 0\n", c.X);
3434 ok(!c.Y, "got %d, expected 0\n", c.Y);
3436 CreatePipe(&pipe1, &pipe2, NULL, 0);
3437 memset(&c, 10, sizeof(COORD));
3438 SetLastError(0xdeadbeef);
3439 c = GetConsoleFontSize(pipe1, index);
3440 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3441 ok(!c.X, "got %d, expected 0\n", c.X);
3442 ok(!c.Y, "got %d, expected 0\n", c.Y);
3443 CloseHandle(pipe1);
3444 CloseHandle(pipe2);
3446 GetCurrentConsoleFont(std_output, FALSE, &cfi);
3447 memset(&c, 10, sizeof(COORD));
3448 SetLastError(0xdeadbeef);
3449 c = GetConsoleFontSize(std_output, cfi.nFont);
3450 ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
3451 GetClientRect(GetConsoleWindow(), &r);
3452 GetConsoleScreenBufferInfo(std_output, &csbi);
3453 font_width = (r.right - r.left + 1) / csbi.srWindow.Right;
3454 font_height = (r.bottom - r.top + 1) / csbi.srWindow.Bottom;
3455 ok(c.X == font_width, "got %d, expected %d\n", c.X, font_width);
3456 ok(c.Y == font_height, "got %d, expected %d\n", c.Y, font_height);
3458 hmod = GetModuleHandleA("kernel32.dll");
3459 pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts");
3460 if (!pGetNumberOfConsoleFonts)
3462 win_skip("GetNumberOfConsoleFonts is not available\n");
3463 return;
3465 index = pGetNumberOfConsoleFonts();
3467 memset(&c, 10, sizeof(COORD));
3468 SetLastError(0xdeadbeef);
3469 c = GetConsoleFontSize(std_output, index);
3470 ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef) /* win10 1809 */,
3471 "unexpected last error %u\n", GetLastError());
3472 if (GetLastError() == ERROR_INVALID_PARAMETER)
3474 ok(!c.X, "got %d, expected 0\n", c.X);
3475 ok(!c.Y, "got %d, expected 0\n", c.Y);
3479 static void test_GetLargestConsoleWindowSize(HANDLE std_output)
3481 COORD c, font;
3482 RECT r;
3483 LONG workarea_w, workarea_h, maxcon_w, maxcon_h;
3484 CONSOLE_SCREEN_BUFFER_INFO sbi;
3485 CONSOLE_FONT_INFO cfi;
3486 HANDLE pipe1, pipe2;
3487 DWORD index, i;
3488 HMODULE hmod;
3489 BOOL ret;
3490 DWORD (WINAPI *pGetNumberOfConsoleFonts)(void);
3491 BOOL (WINAPI *pSetConsoleFont)(HANDLE, DWORD);
3493 memset(&c, 10, sizeof(COORD));
3494 SetLastError(0xdeadbeef);
3495 c = GetLargestConsoleWindowSize(NULL);
3496 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3497 ok(!c.X, "got %d, expected 0\n", c.X);
3498 ok(!c.Y, "got %d, expected 0\n", c.Y);
3500 memset(&c, 10, sizeof(COORD));
3501 SetLastError(0xdeadbeef);
3502 c = GetLargestConsoleWindowSize(GetStdHandle(STD_INPUT_HANDLE));
3503 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3504 ok(!c.X, "got %d, expected 0\n", c.X);
3505 ok(!c.Y, "got %d, expected 0\n", c.Y);
3507 CreatePipe(&pipe1, &pipe2, NULL, 0);
3508 memset(&c, 10, sizeof(COORD));
3509 SetLastError(0xdeadbeef);
3510 c = GetLargestConsoleWindowSize(pipe1);
3511 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3512 ok(!c.X, "got %d, expected 0\n", c.X);
3513 ok(!c.Y, "got %d, expected 0\n", c.Y);
3514 CloseHandle(pipe1);
3515 CloseHandle(pipe2);
3517 SystemParametersInfoW(SPI_GETWORKAREA, 0, &r, 0);
3518 workarea_w = r.right - r.left;
3519 workarea_h = r.bottom - r.top - GetSystemMetrics(SM_CYCAPTION);
3521 GetCurrentConsoleFont(std_output, FALSE, &cfi);
3522 index = cfi.nFont; /* save current font index */
3524 hmod = GetModuleHandleA("kernel32.dll");
3525 pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts");
3526 if (!pGetNumberOfConsoleFonts)
3528 win_skip("GetNumberOfConsoleFonts is not available\n");
3529 return;
3531 pSetConsoleFont = (void *)GetProcAddress(hmod, "SetConsoleFont");
3532 if (!pSetConsoleFont)
3534 win_skip("SetConsoleFont is not available\n");
3535 return;
3538 for (i = 0; i < pGetNumberOfConsoleFonts(); i++)
3540 pSetConsoleFont(std_output, i);
3541 memset(&c, 10, sizeof(COORD));
3542 SetLastError(0xdeadbeef);
3543 c = GetLargestConsoleWindowSize(std_output);
3544 ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
3545 GetCurrentConsoleFont(std_output, FALSE, &cfi);
3546 font = GetConsoleFontSize(std_output, cfi.nFont);
3547 maxcon_w = workarea_w / font.X;
3548 maxcon_h = workarea_h / font.Y;
3549 ok(c.X == maxcon_w || c.X == maxcon_w - 1 /* Win10 */, "got %d, expected %d\n", c.X, maxcon_w);
3550 ok(c.Y == maxcon_h || c.Y == maxcon_h - 1 /* Win10 */, "got %d, expected %d\n", c.Y, maxcon_h);
3552 ret = GetConsoleScreenBufferInfo(std_output, &sbi);
3553 ok(ret, "GetConsoleScreenBufferInfo failed %u\n", GetLastError());
3554 ok(sbi.dwMaximumWindowSize.X == min(c.X, sbi.dwSize.X), "got %d, expected %d\n",
3555 sbi.dwMaximumWindowSize.X, min(c.X, sbi.dwSize.X));
3556 ok(sbi.dwMaximumWindowSize.Y == min(c.Y, sbi.dwSize.Y), "got %d, expected %d\n",
3557 sbi.dwMaximumWindowSize.Y, min(c.Y, sbi.dwSize.Y));
3559 pSetConsoleFont(std_output, index); /* restore original font size */
3562 static void test_GetConsoleFontInfo(HANDLE std_output)
3564 HANDLE hmod;
3565 BOOL (WINAPI *pGetConsoleFontInfo)(HANDLE, BOOL, DWORD, CONSOLE_FONT_INFO *);
3566 DWORD (WINAPI *pGetNumberOfConsoleFonts)(void);
3567 DWORD num_fonts, index, i;
3568 int memsize, win_width, win_height, tmp_w, tmp_h;
3569 CONSOLE_FONT_INFO *cfi;
3570 BOOL ret;
3571 CONSOLE_SCREEN_BUFFER_INFO csbi;
3572 COORD orig_sb_size, tmp_sb_size, orig_font, tmp_font;
3574 hmod = GetModuleHandleA("kernel32.dll");
3575 pGetConsoleFontInfo = (void *)GetProcAddress(hmod, "GetConsoleFontInfo");
3576 if (!pGetConsoleFontInfo)
3578 win_skip("GetConsoleFontInfo is not available\n");
3579 return;
3582 pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts");
3583 if (!pGetNumberOfConsoleFonts)
3585 skip("GetNumberOfConsoleFonts is not available\n");
3586 return;
3589 num_fonts = pGetNumberOfConsoleFonts();
3590 memsize = num_fonts * sizeof(CONSOLE_FONT_INFO);
3591 cfi = HeapAlloc(GetProcessHeap(), 0, memsize);
3592 memset(cfi, 0, memsize);
3594 GetConsoleScreenBufferInfo(std_output, &csbi);
3595 orig_sb_size = csbi.dwSize;
3596 tmp_sb_size.X = csbi.dwSize.X + 3;
3597 tmp_sb_size.Y = csbi.dwSize.Y + 5;
3598 SetConsoleScreenBufferSize(std_output, tmp_sb_size);
3600 SetLastError(0xdeadbeef);
3601 ret = pGetConsoleFontInfo(NULL, FALSE, 0, cfi);
3602 ok(!ret, "got %d, expected zero\n", ret);
3603 if (GetLastError() == LOWORD(E_NOTIMPL) /* win10 1709+ */ ||
3604 broken(GetLastError() == ERROR_GEN_FAILURE) /* win10 1607 */)
3606 skip("GetConsoleFontInfo is not implemented\n");
3607 SetConsoleScreenBufferSize(std_output, orig_sb_size);
3608 HeapFree(GetProcessHeap(), 0, cfi);
3609 return;
3611 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3613 SetLastError(0xdeadbeef);
3614 ret = pGetConsoleFontInfo(GetStdHandle(STD_INPUT_HANDLE), FALSE, 0, cfi);
3615 ok(!ret, "got %d, expected zero\n", ret);
3616 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3618 SetLastError(0xdeadbeef);
3619 ret = pGetConsoleFontInfo(std_output, FALSE, 0, cfi);
3620 ok(!ret, "got %d, expected zero\n", ret);
3621 ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
3623 GetConsoleScreenBufferInfo(std_output, &csbi);
3624 win_width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
3625 win_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
3627 GetCurrentConsoleFont(std_output, FALSE, &cfi[0]);
3628 index = cfi[0].nFont;
3629 orig_font = GetConsoleFontSize(std_output, index);
3631 memset(cfi, 0, memsize);
3632 ret = pGetConsoleFontInfo(std_output, FALSE, num_fonts, cfi);
3633 ok(ret, "got %d, expected non-zero\n", ret);
3634 ok(cfi[index].dwFontSize.X == win_width, "got %d, expected %d\n",
3635 cfi[index].dwFontSize.X, win_width);
3636 ok(cfi[index].dwFontSize.Y == win_height, "got %d, expected %d\n",
3637 cfi[index].dwFontSize.Y, win_height);
3639 for (i = 0; i < num_fonts; i++)
3641 ok(cfi[i].nFont == i, "element out of order, got nFont %d, expected %d\n", cfi[i].nFont, i);
3642 tmp_font = GetConsoleFontSize(std_output, cfi[i].nFont);
3643 tmp_w = (double)orig_font.X / tmp_font.X * win_width;
3644 tmp_h = (double)orig_font.Y / tmp_font.Y * win_height;
3645 ok(cfi[i].dwFontSize.X == tmp_w, "got %d, expected %d\n", cfi[i].dwFontSize.X, tmp_w);
3646 ok(cfi[i].dwFontSize.Y == tmp_h, "got %d, expected %d\n", cfi[i].dwFontSize.Y, tmp_h);
3649 SetLastError(0xdeadbeef);
3650 ret = pGetConsoleFontInfo(NULL, TRUE, 0, cfi);
3651 ok(!ret, "got %d, expected zero\n", ret);
3652 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3654 SetLastError(0xdeadbeef);
3655 ret = pGetConsoleFontInfo(GetStdHandle(STD_INPUT_HANDLE), TRUE, 0, cfi);
3656 ok(!ret, "got %d, expected zero\n", ret);
3657 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3659 SetLastError(0xdeadbeef);
3660 ret = pGetConsoleFontInfo(std_output, TRUE, 0, cfi);
3661 ok(!ret, "got %d, expected zero\n", ret);
3662 ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
3664 memset(cfi, 0, memsize);
3665 ret = pGetConsoleFontInfo(std_output, TRUE, num_fonts, cfi);
3666 ok(ret, "got %d, expected non-zero\n", ret);
3667 ok(cfi[index].dwFontSize.X == csbi.dwMaximumWindowSize.X, "got %d, expected %d\n",
3668 cfi[index].dwFontSize.X, csbi.dwMaximumWindowSize.X);
3669 ok(cfi[index].dwFontSize.Y == csbi.dwMaximumWindowSize.Y, "got %d, expected %d\n",
3670 cfi[index].dwFontSize.Y, csbi.dwMaximumWindowSize.Y);
3672 for (i = 0; i < num_fonts; i++)
3674 ok(cfi[i].nFont == i, "element out of order, got nFont %d, expected %d\n", cfi[i].nFont, i);
3675 tmp_font = GetConsoleFontSize(std_output, cfi[i].nFont);
3676 tmp_w = (double)orig_font.X / tmp_font.X * csbi.dwMaximumWindowSize.X;
3677 tmp_h = (double)orig_font.Y / tmp_font.Y * csbi.dwMaximumWindowSize.Y;
3678 ok(cfi[i].dwFontSize.X == tmp_w, "got %d, expected %d\n", cfi[i].dwFontSize.X, tmp_w);
3679 ok(cfi[i].dwFontSize.Y == tmp_h, "got %d, expected %d\n", cfi[i].dwFontSize.Y, tmp_h);
3682 HeapFree(GetProcessHeap(), 0, cfi);
3683 SetConsoleScreenBufferSize(std_output, orig_sb_size);
3686 static void test_SetConsoleFont(HANDLE std_output)
3688 HANDLE hmod;
3689 BOOL (WINAPI *pSetConsoleFont)(HANDLE, DWORD);
3690 BOOL ret;
3691 DWORD (WINAPI *pGetNumberOfConsoleFonts)(void);
3692 DWORD num_fonts;
3694 hmod = GetModuleHandleA("kernel32.dll");
3695 pSetConsoleFont = (void *)GetProcAddress(hmod, "SetConsoleFont");
3696 if (!pSetConsoleFont)
3698 win_skip("SetConsoleFont is not available\n");
3699 return;
3702 SetLastError(0xdeadbeef);
3703 ret = pSetConsoleFont(NULL, 0);
3704 ok(!ret, "got %d, expected zero\n", ret);
3705 if (GetLastError() == LOWORD(E_NOTIMPL) /* win10 1709+ */ ||
3706 broken(GetLastError() == ERROR_GEN_FAILURE) /* win10 1607 */)
3708 skip("SetConsoleFont is not implemented\n");
3709 return;
3711 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3713 SetLastError(0xdeadbeef);
3714 ret = pSetConsoleFont(GetStdHandle(STD_INPUT_HANDLE), 0);
3715 ok(!ret, "got %d, expected zero\n", ret);
3716 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3718 pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts");
3719 if (!pGetNumberOfConsoleFonts)
3721 win_skip("GetNumberOfConsoleFonts is not available\n");
3722 return;
3725 num_fonts = pGetNumberOfConsoleFonts();
3727 SetLastError(0xdeadbeef);
3728 ret = pSetConsoleFont(std_output, num_fonts);
3729 ok(!ret, "got %d, expected zero\n", ret);
3730 todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError());
3733 static void test_GetConsoleScreenBufferInfoEx(HANDLE std_output)
3735 HANDLE hmod;
3736 BOOL (WINAPI *pGetConsoleScreenBufferInfoEx)(HANDLE, CONSOLE_SCREEN_BUFFER_INFOEX *);
3737 CONSOLE_SCREEN_BUFFER_INFOEX csbix;
3738 HANDLE pipe1, pipe2;
3739 BOOL ret;
3740 HANDLE std_input = GetStdHandle(STD_INPUT_HANDLE);
3742 hmod = GetModuleHandleA("kernel32.dll");
3743 pGetConsoleScreenBufferInfoEx = (void *)GetProcAddress(hmod, "GetConsoleScreenBufferInfoEx");
3744 if (!pGetConsoleScreenBufferInfoEx)
3746 win_skip("GetConsoleScreenBufferInfoEx is not available\n");
3747 return;
3750 SetLastError(0xdeadbeef);
3751 ret = pGetConsoleScreenBufferInfoEx(NULL, &csbix);
3752 ok(!ret, "got %d, expected zero\n", ret);
3753 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError());
3755 SetLastError(0xdeadbeef);
3756 ret = pGetConsoleScreenBufferInfoEx(std_input, &csbix);
3757 ok(!ret, "got %d, expected zero\n", ret);
3758 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError());
3760 SetLastError(0xdeadbeef);
3761 ret = pGetConsoleScreenBufferInfoEx(std_output, &csbix);
3762 ok(!ret, "got %d, expected zero\n", ret);
3763 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError());
3765 csbix.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
3767 SetLastError(0xdeadbeef);
3768 ret = pGetConsoleScreenBufferInfoEx(NULL, &csbix);
3769 ok(!ret, "got %d, expected zero\n", ret);
3770 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3772 SetLastError(0xdeadbeef);
3773 ret = pGetConsoleScreenBufferInfoEx(std_input, &csbix);
3774 ok(!ret, "got %d, expected zero\n", ret);
3775 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3777 CreatePipe(&pipe1, &pipe2, NULL, 0);
3778 SetLastError(0xdeadbeef);
3779 ret = pGetConsoleScreenBufferInfoEx(std_input, &csbix);
3780 ok(!ret, "got %d, expected zero\n", ret);
3781 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3782 CloseHandle(pipe1);
3783 CloseHandle(pipe2);
3785 SetLastError(0xdeadbeef);
3786 ret = pGetConsoleScreenBufferInfoEx(std_output, &csbix);
3787 ok(ret, "got %d, expected non-zero\n", ret);
3788 ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
3791 static void test_FreeConsole(void)
3793 HANDLE handle, unbound_output = NULL, unbound_input = NULL;
3794 DWORD size, mode, type;
3795 WCHAR title[16];
3796 char buf[32];
3797 HWND hwnd;
3798 UINT cp;
3799 BOOL ret;
3801 ok(RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle != NULL, "ConsoleHandle is NULL\n");
3802 if (!skip_nt)
3804 unbound_input = create_unbound_handle(FALSE, TRUE);
3805 unbound_output = create_unbound_handle(TRUE, TRUE);
3808 ret = FreeConsole();
3809 ok(ret, "FreeConsole failed: %u\n", GetLastError());
3811 ok(RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle == NULL, "ConsoleHandle = %p\n",
3812 RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle);
3814 handle = CreateFileA("CONOUT$", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
3815 ok(handle == INVALID_HANDLE_VALUE &&
3816 (GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == ERROR_ACCESS_DENIED /* winxp */)),
3817 "CreateFileA failed: %u\n", GetLastError());
3819 handle = CreateFileA("CONIN$", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3820 ok(handle == INVALID_HANDLE_VALUE &&
3821 (GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == ERROR_ACCESS_DENIED /* winxp */)),
3822 "CreateFileA failed: %u\n", GetLastError());
3824 handle = CreateFileA("CON", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3825 ok(handle == INVALID_HANDLE_VALUE &&
3826 (GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == ERROR_ACCESS_DENIED /* winxp */)),
3827 "CreateFileA failed: %u\n", GetLastError());
3829 handle = CreateFileA("CON", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
3830 ok(handle == INVALID_HANDLE_VALUE &&
3831 (GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == ERROR_FILE_NOT_FOUND /* winxp */)),
3832 "CreateFileA failed: %u\n", GetLastError());
3834 handle = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
3835 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
3836 CONSOLE_TEXTMODE_BUFFER, NULL);
3837 ok(handle == INVALID_HANDLE_VALUE && GetLastError() == ERROR_INVALID_HANDLE,
3838 "CreateConsoleScreenBuffer returned: %p (%u)\n", handle, GetLastError());
3840 SetLastError(0xdeadbeef);
3841 cp = GetConsoleCP();
3842 ok(!cp, "cp = %x\n", cp);
3843 ok(GetLastError() == ERROR_INVALID_HANDLE, "last error %u\n", GetLastError());
3845 SetLastError(0xdeadbeef);
3846 cp = GetConsoleOutputCP();
3847 ok(!cp, "cp = %x\n", cp);
3848 ok(GetLastError() == ERROR_INVALID_HANDLE, "last error %u\n", GetLastError());
3850 SetLastError(0xdeadbeef);
3851 ret = SetConsoleCP(GetOEMCP());
3852 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "SetConsoleCP returned %x(%u)\n", ret, GetLastError());
3854 SetLastError(0xdeadbeef);
3855 ret = SetConsoleOutputCP(GetOEMCP());
3856 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "SetConsoleCP returned %x(%u)\n", ret, GetLastError());
3858 if (skip_nt) return;
3860 SetLastError(0xdeadbeef);
3861 memset( title, 0xc0, sizeof(title) );
3862 size = GetConsoleTitleW( title, ARRAY_SIZE(title) );
3863 ok(!size, "GetConsoleTitleW returned %u\n", size);
3864 ok(title[0] == 0xc0c0, "title byffer changed\n");
3865 ok(GetLastError() == ERROR_INVALID_HANDLE, "last error %u\n", GetLastError());
3867 SetLastError(0xdeadbeef);
3868 ret = SetConsoleTitleW( L"test" );
3869 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "SetConsoleTitleW returned %x(%u)\n", ret, GetLastError());
3871 SetLastError(0xdeadbeef);
3872 hwnd = GetConsoleWindow();
3873 ok(!hwnd, "hwnd = %p\n", hwnd);
3874 ok(GetLastError() == ERROR_INVALID_HANDLE, "last error %u\n", GetLastError());
3876 ret = GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
3877 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "GenerateConsoleCtrlEvent returned %x(%u)\n",
3878 ret, GetLastError());
3880 SetStdHandle( STD_INPUT_HANDLE, (HANDLE)0xdeadbeef );
3881 handle = GetConsoleInputWaitHandle();
3882 ok(handle == (HANDLE)0xdeadbeef, "GetConsoleInputWaitHandle returned %p\n", handle);
3883 SetStdHandle( STD_INPUT_HANDLE, NULL );
3884 handle = GetConsoleInputWaitHandle();
3885 ok(!handle, "GetConsoleInputWaitHandle returned %p\n", handle);
3887 ret = ReadFile(unbound_input, buf, sizeof(buf), &size, NULL);
3888 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
3889 "ReadFile returned %x %u\n", ret, GetLastError());
3891 ret = FlushFileBuffers(unbound_input);
3892 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
3893 "ReadFile returned %x %u\n", ret, GetLastError());
3895 ret = WriteFile(unbound_input, "test", 4, &size, NULL);
3896 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
3897 "ReadFile returned %x %u\n", ret, GetLastError());
3899 ret = GetConsoleMode(unbound_input, &mode);
3900 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
3901 "GetConsoleMode returned %x %u\n", ret, GetLastError());
3902 ret = GetConsoleMode(unbound_output, &mode);
3903 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
3904 "GetConsoleMode returned %x %u\n", ret, GetLastError());
3906 type = GetFileType(unbound_input);
3907 ok(type == FILE_TYPE_CHAR, "GetFileType returned %u\n", type);
3908 type = GetFileType(unbound_output);
3909 ok(type == FILE_TYPE_CHAR, "GetFileType returned %u\n", type);
3911 CloseHandle(unbound_input);
3912 CloseHandle(unbound_output);
3915 static void test_SetConsoleScreenBufferInfoEx(HANDLE std_output)
3917 BOOL ret;
3918 HANDLE hmod;
3919 HANDLE std_input = CreateFileA("CONIN$", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3920 BOOL (WINAPI *pSetConsoleScreenBufferInfoEx)(HANDLE, CONSOLE_SCREEN_BUFFER_INFOEX *);
3921 BOOL (WINAPI *pGetConsoleScreenBufferInfoEx)(HANDLE, CONSOLE_SCREEN_BUFFER_INFOEX *);
3922 CONSOLE_SCREEN_BUFFER_INFOEX info;
3924 hmod = GetModuleHandleA("kernel32.dll");
3925 pSetConsoleScreenBufferInfoEx = (void *)GetProcAddress(hmod, "SetConsoleScreenBufferInfoEx");
3926 pGetConsoleScreenBufferInfoEx = (void *)GetProcAddress(hmod, "GetConsoleScreenBufferInfoEx");
3927 if (!pSetConsoleScreenBufferInfoEx || !pGetConsoleScreenBufferInfoEx)
3929 win_skip("SetConsoleScreenBufferInfoEx is not available\n");
3930 return;
3933 memset(&info, 0, sizeof(CONSOLE_SCREEN_BUFFER_INFOEX));
3934 info.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
3935 pGetConsoleScreenBufferInfoEx(std_output, &info);
3937 SetLastError(0xdeadbeef);
3938 ret = pSetConsoleScreenBufferInfoEx(NULL, &info);
3939 ok(!ret, "got %d, expected zero\n", ret);
3940 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
3942 SetLastError(0xdeadbeef);
3943 ret = pSetConsoleScreenBufferInfoEx(std_output, &info);
3944 ok(ret, "got %d, expected one\n", ret);
3945 ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
3947 SetLastError(0xdeadbeef);
3948 ret = pSetConsoleScreenBufferInfoEx(std_input, &info);
3949 ok(!ret, "got %d, expected zero\n", ret);
3950 ok(GetLastError() == ERROR_INVALID_HANDLE || GetLastError() == ERROR_ACCESS_DENIED,
3951 "got %u, expected 5 or 6\n", GetLastError());
3953 info.cbSize = 0;
3954 SetLastError(0xdeadbeef);
3955 ret = pSetConsoleScreenBufferInfoEx(std_output, &info);
3956 ok(!ret, "got %d, expected zero\n", ret);
3957 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %u, expected 87\n", GetLastError());
3959 CloseHandle(std_input);
3962 static void test_console_title(void)
3964 WCHAR buf[64];
3965 BOOL ret;
3967 ret = SetConsoleTitleW(L"test");
3968 ok(ret, "SetConsoleTitleW failed: %u\n", GetLastError());
3970 ret = GetConsoleTitleW(buf, ARRAY_SIZE(buf));
3971 ok(ret, "GetConsoleTitleW failed: %u\n", GetLastError());
3972 ok(!wcscmp(buf, L"test"), "title = %s\n", wine_dbgstr_w(buf));
3974 if (!skip_nt)
3976 ret = GetConsoleTitleW(buf, 2);
3977 ok(ret, "GetConsoleTitleW failed: %u\n", GetLastError());
3978 ok(!wcscmp(buf, L"t"), "title = %s\n", wine_dbgstr_w(buf));
3980 ret = GetConsoleTitleW(buf, 4);
3981 ok(ret, "GetConsoleTitleW failed: %u\n", GetLastError());
3982 ok(!wcscmp(buf, L"tes"), "title = %s\n", wine_dbgstr_w(buf));
3986 static void test_file_info(HANDLE input, HANDLE output)
3988 FILE_STANDARD_INFORMATION std_info;
3989 FILE_FS_DEVICE_INFORMATION fs_info;
3990 LARGE_INTEGER size;
3991 IO_STATUS_BLOCK io;
3992 DWORD type;
3993 NTSTATUS status;
3994 BOOL ret;
3996 if (skip_nt) return;
3998 status = NtQueryInformationFile(input, &io, &std_info, sizeof(std_info), FileStandardInformation);
3999 ok(status == STATUS_INVALID_DEVICE_REQUEST, "NtQueryInformationFile returned: %#x\n", status);
4001 status = NtQueryInformationFile(output, &io, &std_info, sizeof(std_info), FileStandardInformation);
4002 ok(status == STATUS_INVALID_DEVICE_REQUEST, "NtQueryInformationFile returned: %#x\n", status);
4004 ret = GetFileSizeEx(input, &size);
4005 ok(!ret && GetLastError() == ERROR_INVALID_FUNCTION,
4006 "GetFileSizeEx returned %x(%u)\n", ret, GetLastError());
4008 ret = GetFileSizeEx(output, &size);
4009 ok(!ret && GetLastError() == ERROR_INVALID_FUNCTION,
4010 "GetFileSizeEx returned %x(%u)\n", ret, GetLastError());
4012 status = NtQueryVolumeInformationFile(input, &io, &fs_info, sizeof(fs_info), FileFsDeviceInformation);
4013 ok(!status, "NtQueryVolumeInformationFile failed: %#x\n", status);
4014 ok(fs_info.DeviceType == FILE_DEVICE_CONSOLE, "DeviceType = %u\n", fs_info.DeviceType);
4015 ok(fs_info.Characteristics == FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL,
4016 "Characteristics = %x\n", fs_info.Characteristics);
4018 status = NtQueryVolumeInformationFile(output, &io, &fs_info, sizeof(fs_info), FileFsDeviceInformation);
4019 ok(!status, "NtQueryVolumeInformationFile failed: %#x\n", status);
4020 ok(fs_info.DeviceType == FILE_DEVICE_CONSOLE, "DeviceType = %u\n", fs_info.DeviceType);
4021 ok(fs_info.Characteristics == FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL,
4022 "Characteristics = %x\n", fs_info.Characteristics);
4024 type = GetFileType(input);
4025 ok(type == FILE_TYPE_CHAR, "GetFileType returned %u\n", type);
4026 type = GetFileType(output);
4027 ok(type == FILE_TYPE_CHAR, "GetFileType returned %u\n", type);
4030 static void test_AttachConsole_child(DWORD console_pid)
4032 HANDLE pipe_in, pipe_out;
4033 COORD c = {0,0};
4034 HANDLE console;
4035 char buf[32];
4036 DWORD len;
4037 BOOL res;
4039 res = CreatePipe(&pipe_in, &pipe_out, NULL, 0);
4040 ok(res, "CreatePipe failed: %u\n", GetLastError());
4042 res = AttachConsole(console_pid);
4043 ok(!res && GetLastError() == ERROR_ACCESS_DENIED,
4044 "AttachConsole returned: %x(%u)\n", res, GetLastError());
4046 ok(RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle != NULL, "ConsoleHandle is NULL\n");
4047 res = FreeConsole();
4048 ok(res, "FreeConsole failed: %u\n", GetLastError());
4049 ok(RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle == NULL, "ConsoleHandle = %p\n",
4050 RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle);
4052 SetStdHandle(STD_ERROR_HANDLE, pipe_out);
4054 res = AttachConsole(console_pid);
4055 ok(res, "AttachConsole failed: %u\n", GetLastError());
4057 ok(pipe_out != GetStdHandle(STD_ERROR_HANDLE), "std handle not set to console\n");
4058 ok(RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle != NULL, "ConsoleHandle is NULL\n");
4060 console = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
4061 ok(console != INVALID_HANDLE_VALUE, "Could not open console\n");
4063 res = ReadConsoleOutputCharacterA(console, buf, 6, c, &len);
4064 ok(res, "ReadConsoleOutputCharacterA failed: %u\n", GetLastError());
4065 ok(len == 6, "len = %u\n", len);
4066 ok(!memcmp(buf, "Parent", 6), "Unexpected console output\n");
4068 res = FreeConsole();
4069 ok(res, "FreeConsole failed: %u\n", GetLastError());
4071 SetStdHandle(STD_INPUT_HANDLE, pipe_in);
4072 SetStdHandle(STD_OUTPUT_HANDLE, pipe_out);
4074 res = AttachConsole(ATTACH_PARENT_PROCESS);
4075 ok(res, "AttachConsole failed: %u\n", GetLastError());
4077 ok(pipe_in != GetStdHandle(STD_INPUT_HANDLE), "std handle not set to console\n");
4078 ok(pipe_out != GetStdHandle(STD_OUTPUT_HANDLE), "std handle not set to console\n");
4080 console = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
4081 ok(console != INVALID_HANDLE_VALUE, "Could not open console\n");
4083 res = ReadConsoleOutputCharacterA(console, buf, 6, c, &len);
4084 ok(res, "ReadConsoleOutputCharacterA failed: %u\n", GetLastError());
4085 ok(len == 6, "len = %u\n", len);
4086 ok(!memcmp(buf, "Parent", 6), "Unexpected console output\n");
4088 simple_write_console(console, "Child");
4089 CloseHandle(console);
4091 res = FreeConsole();
4092 ok(res, "FreeConsole failed: %u\n", GetLastError());
4094 res = CloseHandle(pipe_in);
4095 ok(res, "pipe_in is no longer valid\n");
4096 res = CloseHandle(pipe_out);
4097 ok(res, "pipe_out is no longer valid\n");
4100 static void test_AttachConsole(HANDLE console)
4102 STARTUPINFOA si = { sizeof(si) };
4103 PROCESS_INFORMATION info;
4104 char **argv, buf[MAX_PATH];
4105 COORD c = {0,0};
4106 DWORD len;
4107 BOOL res;
4109 simple_write_console(console, "Parent console");
4111 winetest_get_mainargs(&argv);
4112 sprintf(buf, "\"%s\" console attach_console %x", argv[0], GetCurrentProcessId());
4113 res = CreateProcessA(NULL, buf, NULL, NULL, TRUE, 0, NULL, NULL, &si, &info);
4114 ok(res, "CreateProcess failed: %u\n", GetLastError());
4115 CloseHandle(info.hThread);
4117 wait_child_process(info.hProcess);
4118 CloseHandle(info.hProcess);
4120 res = ReadConsoleOutputCharacterA(console, buf, 5, c, &len);
4121 ok(res, "ReadConsoleOutputCharacterA failed: %u\n", GetLastError());
4122 ok(len == 5, "len = %u\n", len);
4123 ok(!memcmp(buf, "Child", 5), "Unexpected console output\n");
4126 static void test_AllocConsole_child(void)
4128 HANDLE unbound_output;
4129 HANDLE prev_output, prev_error;
4130 STARTUPINFOW si;
4131 DWORD mode;
4132 BOOL res;
4134 GetStartupInfoW(&si);
4136 prev_output = GetStdHandle(STD_OUTPUT_HANDLE);
4137 res = DuplicateHandle(GetCurrentProcess(), prev_output, GetCurrentProcess(), &unbound_output,
4138 0, FALSE, DUPLICATE_SAME_ACCESS);
4139 ok(res, "DuplicateHandle failed: %u\n", GetLastError());
4141 res = GetConsoleMode(unbound_output, &mode);
4142 ok(res, "GetConsoleMode failed: %u\n", GetLastError());
4144 prev_error = GetStdHandle(STD_ERROR_HANDLE);
4145 if (si.dwFlags & STARTF_USESTDHANDLES)
4147 res = GetConsoleMode(prev_error, &mode);
4148 ok(!res && GetLastError() == ERROR_INVALID_HANDLE, "GetConsoleMode failed: %u\n", GetLastError());
4151 FreeConsole();
4153 ok(GetStdHandle(STD_OUTPUT_HANDLE) == prev_output, "GetStdHandle(STD_OUTPUT_HANDLE) = %p\n", GetStdHandle(STD_OUTPUT_HANDLE));
4154 ok(GetStdHandle(STD_ERROR_HANDLE) == prev_error, "GetStdHandle(STD_ERROR_HANDLE) = %p\n", GetStdHandle(STD_ERROR_HANDLE));
4155 res = GetConsoleMode(unbound_output, &mode);
4156 ok(!res && GetLastError() == ERROR_INVALID_HANDLE, "GetConsoleMode failed: %u\n", GetLastError());
4158 res = AllocConsole();
4159 ok(res, "AllocConsole failed: %u\n", GetLastError());
4161 if (si.dwFlags & STARTF_USESTDHANDLES)
4163 ok(GetStdHandle(STD_OUTPUT_HANDLE) == prev_output, "GetStdHandle(STD_OUTPUT_HANDLE) = %p\n", GetStdHandle(STD_OUTPUT_HANDLE));
4164 ok(GetStdHandle(STD_ERROR_HANDLE) == prev_error, "GetStdHandle(STD_ERROR_HANDLE) = %p\n", GetStdHandle(STD_ERROR_HANDLE));
4167 res = GetConsoleMode(unbound_output, &mode);
4168 ok(res, "GetConsoleMode failed: %u\n", GetLastError());
4170 FreeConsole();
4171 SetStdHandle(STD_OUTPUT_HANDLE, NULL);
4172 SetStdHandle(STD_ERROR_HANDLE, NULL);
4173 res = AllocConsole();
4174 ok(res, "AllocConsole failed: %u\n", GetLastError());
4176 ok(GetStdHandle(STD_OUTPUT_HANDLE) != NULL, "GetStdHandle(STD_OUTPUT_HANDLE) = %p\n", GetStdHandle(STD_OUTPUT_HANDLE));
4177 ok(GetStdHandle(STD_ERROR_HANDLE) != NULL, "GetStdHandle(STD_ERROR_HANDLE) = %p\n", GetStdHandle(STD_ERROR_HANDLE));
4179 res = GetConsoleMode(unbound_output, &mode);
4180 ok(res, "GetConsoleMode failed: %u\n", GetLastError());
4181 res = GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &mode);
4182 ok(res, "GetConsoleMode failed: %u\n", GetLastError());
4183 res = GetConsoleMode(GetStdHandle(STD_ERROR_HANDLE), &mode);
4184 ok(res, "GetConsoleMode failed: %u\n", GetLastError());
4186 res = CloseHandle(unbound_output);
4187 ok(res, "CloseHandle failed: %u\n", GetLastError());
4190 static void test_AllocConsole(void)
4192 SECURITY_ATTRIBUTES inheritable_attr = { sizeof(inheritable_attr), NULL, TRUE };
4193 STARTUPINFOA si = { sizeof(si) };
4194 PROCESS_INFORMATION info;
4195 char **argv, buf[MAX_PATH];
4196 HANDLE pipe_read, pipe_write;
4197 BOOL res;
4199 if (skip_nt) return;
4201 winetest_get_mainargs(&argv);
4202 sprintf(buf, "\"%s\" console alloc_console", argv[0], GetCurrentProcessId());
4203 res = CreateProcessA(NULL, buf, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &info);
4204 ok(res, "CreateProcess failed: %u\n", GetLastError());
4205 CloseHandle(info.hThread);
4206 wait_child_process(info.hProcess);
4207 CloseHandle(info.hProcess);
4209 res = CreatePipe(&pipe_read, &pipe_write, &inheritable_attr, 0);
4210 ok(res, "CreatePipe failed: %u\n", GetLastError());
4212 si.dwFlags = STARTF_USESTDHANDLES;
4213 si.hStdError = pipe_write;
4214 res = CreateProcessA(NULL, buf, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &info);
4215 ok(res, "CreateProcess failed: %u\n", GetLastError());
4216 CloseHandle(info.hThread);
4217 wait_child_process(info.hProcess);
4218 CloseHandle(info.hProcess);
4220 CloseHandle(pipe_read);
4221 CloseHandle(pipe_write);
4224 static void test_pseudo_console_child(HANDLE input, HANDLE output)
4226 CONSOLE_SCREEN_BUFFER_INFO sb_info;
4227 CONSOLE_CURSOR_INFO cursor_info;
4228 DWORD mode;
4229 BOOL ret;
4231 ret = GetConsoleMode(input, &mode);
4232 ok(ret, "GetConsoleMode failed: %u\n", GetLastError());
4233 ok(mode == (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT |
4234 ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS | ENABLE_AUTO_POSITION),
4235 "mode = %x\n", mode);
4237 ret = SetConsoleMode(input, mode & ~ENABLE_AUTO_POSITION);
4238 ok(ret, "SetConsoleMode failed: %u\n", GetLastError());
4240 ret = GetConsoleMode(input, &mode);
4241 ok(ret, "GetConsoleMode failed: %u\n", GetLastError());
4242 ok(mode == (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT |
4243 ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS), "mode = %x\n", mode);
4245 ret = SetConsoleMode(input, mode | ENABLE_AUTO_POSITION);
4246 ok(ret, "SetConsoleMode failed: %u\n", GetLastError());
4248 ret = GetConsoleMode(output, &mode);
4249 ok(ret, "GetConsoleMode failed: %u\n", GetLastError());
4250 mode &= ~ENABLE_VIRTUAL_TERMINAL_PROCESSING;
4251 ok(mode == (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT), "mode = %x\n", mode);
4253 ret = SetConsoleMode(output, mode & ~ENABLE_WRAP_AT_EOL_OUTPUT);
4254 ok(ret, "SetConsoleMode failed: %u\n", GetLastError());
4256 ret = GetConsoleMode(output, &mode);
4257 ok(ret, "GetConsoleMode failed: %u\n", GetLastError());
4258 ok(mode == ENABLE_PROCESSED_OUTPUT, "mode = %x\n", mode);
4260 ret = SetConsoleMode(output, mode | ENABLE_WRAP_AT_EOL_OUTPUT);
4261 ok(ret, "SetConsoleMode failed: %u\n", GetLastError());
4263 ret = GetConsoleScreenBufferInfo(output, &sb_info);
4264 ok(ret, "GetConsoleScreenBufferInfo failed: %u\n", GetLastError());
4265 ok(sb_info.dwSize.X == 40, "dwSize.X = %u\n", sb_info.dwSize.X);
4266 ok(sb_info.dwSize.Y == 30, "dwSize.Y = %u\n", sb_info.dwSize.Y);
4267 ok(sb_info.dwCursorPosition.X == 0, "dwCursorPosition.X = %u\n", sb_info.dwCursorPosition.X);
4268 ok(sb_info.dwCursorPosition.Y == 0, "dwCursorPosition.Y = %u\n", sb_info.dwCursorPosition.Y);
4269 ok(sb_info.wAttributes == 7, "wAttributes = %x\n", sb_info.wAttributes);
4270 ok(sb_info.srWindow.Left == 0, "srWindow.Left = %u\n", sb_info.srWindow.Left);
4271 ok(sb_info.srWindow.Top == 0, "srWindow.Top = %u\n", sb_info.srWindow.Top);
4272 ok(sb_info.srWindow.Right == 39, "srWindow.Right = %u\n", sb_info.srWindow.Right);
4273 ok(sb_info.srWindow.Bottom == 29, "srWindow.Bottom = %u\n", sb_info.srWindow.Bottom);
4274 ok(sb_info.dwMaximumWindowSize.X == 40, "dwMaximumWindowSize.X = %u\n", sb_info.dwMaximumWindowSize.X);
4275 ok(sb_info.dwMaximumWindowSize.Y == 30, "dwMaximumWindowSize.Y = %u\n", sb_info.dwMaximumWindowSize.Y);
4277 ret = GetConsoleCursorInfo(output, &cursor_info);
4278 ok(ret, "GetConsoleCursorInfo failed: %u\n", GetLastError());
4279 ok(cursor_info.dwSize == 25, "dwSize = %u\n", cursor_info.dwSize);
4280 ok(cursor_info.bVisible == TRUE, "bVisible = %x\n", cursor_info.bVisible);
4282 test_console_title();
4283 test_WriteConsoleInputW(input);
4286 static DWORD WINAPI read_pipe_proc( void *handle )
4288 char buf[64];
4289 DWORD size;
4290 while (ReadFile(handle, buf, sizeof(buf), &size, NULL));
4291 ok(GetLastError() == ERROR_BROKEN_PIPE, "ReadFile returned %u\n", GetLastError());
4292 CloseHandle(handle);
4293 return 0;
4296 static void test_pseudo_console(void)
4298 STARTUPINFOEXA startup = {{ sizeof(startup) }};
4299 HANDLE console_pipe, console_pipe2, thread;
4300 char **argv, cmdline[MAX_PATH];
4301 PROCESS_INFORMATION info;
4302 HPCON pseudo_console;
4303 SIZE_T attr_size;
4304 COORD size;
4305 BOOL ret;
4306 HRESULT hres;
4308 if (!pCreatePseudoConsole)
4310 win_skip("CreatePseudoConsole not available\n");
4311 return;
4314 console_pipe = CreateNamedPipeW(L"\\\\.\\pipe\\pseudoconsoleconn", PIPE_ACCESS_DUPLEX,
4315 PIPE_WAIT | PIPE_TYPE_BYTE, 1, 4096, 4096, NMPWAIT_USE_DEFAULT_WAIT, NULL);
4316 ok(console_pipe != INVALID_HANDLE_VALUE, "CreateNamedPipeW failed: %u\n", GetLastError());
4318 console_pipe2 = CreateFileW(L"\\\\.\\pipe\\pseudoconsoleconn", GENERIC_READ | GENERIC_WRITE, 0, NULL,
4319 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
4320 ok(console_pipe2 != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
4322 thread = CreateThread( NULL, 0, read_pipe_proc, console_pipe, 0, NULL );
4323 CloseHandle(thread);
4325 size.X = 0;
4326 size.Y = 30;
4327 hres = pCreatePseudoConsole(size, console_pipe2, console_pipe2, 0, &pseudo_console);
4328 ok(hres == E_INVALIDARG, "CreatePseudoConsole failed: %08x\n", hres);
4330 size.X = 40;
4331 size.Y = 0;
4332 hres = pCreatePseudoConsole(size, console_pipe2, console_pipe2, 0, &pseudo_console);
4333 ok(hres == E_INVALIDARG, "CreatePseudoConsole failed: %08x\n", hres);
4335 size.X = 40;
4336 size.Y = 30;
4337 hres = pCreatePseudoConsole(size, console_pipe2, console_pipe2, 0, &pseudo_console);
4338 ok(hres == S_OK, "CreatePseudoConsole failed: %08x\n", hres);
4339 CloseHandle(console_pipe2);
4341 InitializeProcThreadAttributeList(NULL, 1, 0, &attr_size);
4342 startup.lpAttributeList = HeapAlloc(GetProcessHeap(), 0, attr_size);
4343 InitializeProcThreadAttributeList(startup.lpAttributeList, 1, 0, &attr_size);
4344 UpdateProcThreadAttribute(startup.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, pseudo_console,
4345 sizeof(pseudo_console), NULL, NULL);
4347 winetest_get_mainargs(&argv);
4348 sprintf(cmdline, "\"%s\" %s --pseudo-console", argv[0], argv[1]);
4349 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, &startup.StartupInfo, &info);
4350 ok(ret, "CreateProcessW failed: %u\n", GetLastError());
4352 CloseHandle(info.hThread);
4353 HeapFree(GetProcessHeap(), 0, startup.lpAttributeList);
4354 wait_child_process(info.hProcess);
4355 CloseHandle(info.hProcess);
4357 pClosePseudoConsole(pseudo_console);
4360 START_TEST(console)
4362 HANDLE hConIn, hConOut, revert_output = NULL, unbound_output;
4363 BOOL ret, test_current;
4364 CONSOLE_SCREEN_BUFFER_INFO sbi;
4365 BOOL using_pseudo_console;
4366 DWORD size;
4367 char **argv;
4368 int argc;
4370 init_function_pointers();
4372 argc = winetest_get_mainargs(&argv);
4374 if (argc > 3 && !strcmp(argv[2], "attach_console"))
4376 DWORD parent_pid;
4377 sscanf(argv[3], "%x", &parent_pid);
4378 test_AttachConsole_child(parent_pid);
4379 return;
4382 if (argc == 3 && !strcmp(argv[2], "alloc_console"))
4384 test_AllocConsole_child();
4385 return;
4388 test_current = argc >= 3 && !strcmp(argv[2], "--current");
4389 using_pseudo_console = argc >= 3 && !strcmp(argv[2], "--pseudo-console");
4391 if (!test_current && !using_pseudo_console)
4393 static const char font_name[] = "Lucida Console";
4394 HKEY console_key;
4395 char old_font[LF_FACESIZE];
4396 BOOL delete = FALSE;
4397 LONG err;
4399 /* ReadConsoleOutputW doesn't retrieve characters from the output buffer
4400 * correctly for characters that don't have a glyph in the console font. So,
4401 * we first set the console font to Lucida Console (which has a wider
4402 * selection of glyphs available than the default raster fonts). We want
4403 * to be able to restore the original font afterwards, so don't change
4404 * if we can't read the original font.
4406 err = RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
4407 KEY_QUERY_VALUE | KEY_SET_VALUE, &console_key);
4408 if (err == ERROR_SUCCESS)
4410 size = sizeof(old_font);
4411 err = RegQueryValueExA(console_key, "FaceName", NULL, NULL,
4412 (LPBYTE) old_font, &size);
4413 if (err == ERROR_SUCCESS || err == ERROR_FILE_NOT_FOUND)
4415 delete = (err == ERROR_FILE_NOT_FOUND);
4416 err = RegSetValueExA(console_key, "FaceName", 0, REG_SZ,
4417 (const BYTE *) font_name, sizeof(font_name));
4418 if (err != ERROR_SUCCESS)
4419 trace("Unable to change default console font, error %d\n", err);
4421 else
4423 trace("Unable to query default console font, error %d\n", err);
4424 RegCloseKey(console_key);
4425 console_key = NULL;
4428 else
4430 trace("Unable to open HKCU\\Console, error %d\n", err);
4431 console_key = NULL;
4434 /* Now detach and open a fresh console to play with */
4435 FreeConsole();
4436 ok(AllocConsole(), "Couldn't alloc console\n");
4438 /* Restore default console font if needed */
4439 if (console_key != NULL)
4441 if (delete)
4442 err = RegDeleteValueA(console_key, "FaceName");
4443 else
4444 err = RegSetValueExA(console_key, "FaceName", 0, REG_SZ,
4445 (const BYTE *) old_font, strlen(old_font) + 1);
4446 ok(err == ERROR_SUCCESS, "Unable to restore default console font, error %d\n", err);
4450 unbound_output = create_unbound_handle(TRUE, FALSE);
4451 if (!unbound_output)
4453 win_skip("Skipping NT path tests, not supported on this Windows version\n");
4454 skip_nt = TRUE;
4457 if (test_current)
4459 HANDLE sb;
4460 revert_output = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
4461 sb = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
4462 CONSOLE_TEXTMODE_BUFFER, NULL);
4463 ok(sb != INVALID_HANDLE_VALUE, "Could not allocate screen buffer: %u\n", GetLastError());
4464 SetConsoleActiveScreenBuffer(sb);
4467 hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
4468 hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
4470 /* now verify everything's ok */
4471 ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n");
4472 ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n");
4474 if (using_pseudo_console)
4476 test_pseudo_console_child(hConIn, hConOut);
4477 return;
4480 ret = GetConsoleScreenBufferInfo(hConOut, &sbi);
4481 ok(ret, "Getting sb info\n");
4482 if (!ret) return;
4484 /* Reduce the size of the buffer to the visible area plus 3 lines to speed
4485 * up the tests.
4487 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);
4488 sbi.dwSize.Y = size = (sbi.srWindow.Bottom + 1) + 3;
4489 ret = SetConsoleScreenBufferSize(hConOut, sbi.dwSize);
4490 ok(ret, "Setting sb info\n");
4491 ret = GetConsoleScreenBufferInfo(hConOut, &sbi);
4492 ok(ret, "Getting sb info\n");
4493 ok(sbi.dwSize.Y == size, "Unexpected buffer size: %d instead of %d\n", sbi.dwSize.Y, size);
4494 if (!ret) return;
4496 test_ReadConsole(hConIn);
4497 /* Non interactive tests */
4498 testCursor(hConOut, sbi.dwSize);
4499 /* test parameters (FIXME: test functionality) */
4500 testCursorInfo(hConOut);
4501 /* will test wrapped (on/off) & processed (on/off) strings output */
4502 testWrite(hConOut, sbi.dwSize);
4503 /* will test line scrolling at the bottom of the screen */
4504 /* testBottomScroll(); */
4505 /* will test all the scrolling operations */
4506 testScroll(hConOut, sbi.dwSize);
4507 /* will test sb creation / modification / codepage handling */
4508 if (!test_current) testScreenBuffer(hConOut);
4509 /* Test waiting for a console handle */
4510 testWaitForConsoleInput(hConIn);
4511 test_wait(hConIn, hConOut);
4513 if (!test_current)
4515 /* clear duplicated console font table */
4516 CloseHandle(hConIn);
4517 CloseHandle(hConOut);
4518 FreeConsole();
4519 ok(AllocConsole(), "Couldn't alloc console\n");
4520 hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
4521 hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
4522 ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n");
4523 ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n");
4526 testCtrlHandler();
4527 /* still to be done: access rights & access on objects */
4529 if (!pGetConsoleInputExeNameA || !pSetConsoleInputExeNameA)
4530 win_skip("GetConsoleInputExeNameA and/or SetConsoleInputExeNameA is not available\n");
4531 else
4532 test_GetSetConsoleInputExeName();
4534 if (!test_current) test_GetConsoleProcessList();
4535 test_OpenConsoleW();
4536 test_CreateFileW();
4537 test_OpenCON();
4538 test_VerifyConsoleIoHandle(hConOut);
4539 test_GetSetStdHandle();
4540 test_DuplicateConsoleHandle();
4541 test_GetNumberOfConsoleInputEvents(hConIn);
4542 test_WriteConsoleInputA(hConIn);
4543 test_WriteConsoleInputW(hConIn);
4544 test_FlushConsoleInputBuffer(hConIn, hConOut);
4545 test_WriteConsoleOutputCharacterA(hConOut);
4546 test_WriteConsoleOutputCharacterW(hConOut);
4547 test_WriteConsoleOutputAttribute(hConOut);
4548 test_WriteConsoleOutput(hConOut);
4549 test_FillConsoleOutputCharacterA(hConOut);
4550 test_FillConsoleOutputCharacterW(hConOut);
4551 test_FillConsoleOutputAttribute(hConOut);
4552 test_ReadConsoleOutputCharacterA(hConOut);
4553 test_ReadConsoleOutputCharacterW(hConOut);
4554 test_ReadConsoleOutputAttribute(hConOut);
4555 test_ReadConsoleOutput(hConOut);
4556 if (!test_current)
4558 test_GetCurrentConsoleFont(hConOut);
4559 test_GetCurrentConsoleFontEx(hConOut);
4560 test_GetConsoleFontSize(hConOut);
4561 test_GetLargestConsoleWindowSize(hConOut);
4562 test_GetConsoleFontInfo(hConOut);
4563 test_SetConsoleFont(hConOut);
4565 test_GetConsoleScreenBufferInfoEx(hConOut);
4566 test_SetConsoleScreenBufferInfoEx(hConOut);
4567 test_file_info(hConIn, hConOut);
4568 test_console_title();
4569 if (!test_current)
4571 test_pseudo_console();
4572 test_AttachConsole(hConOut);
4573 test_AllocConsole();
4574 test_FreeConsole();
4576 else if (revert_output) SetConsoleActiveScreenBuffer(revert_output);
4578 CloseHandle(unbound_output);