windowscodecs: Silence fixme for IID_CMetaBitmapRenderTarget.
[wine.git] / dlls / kernel32 / tests / console.c
blob911c976128f3fccbfc0ad71996f5f41f22d4709d
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: %#lx\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 /* dummy console ctrl handler to test reset of ctrl handler's list */
127 static BOOL WINAPI mydummych(DWORD event)
129 return TRUE;
132 static void testCursor(HANDLE hCon, COORD sbSize)
134 COORD c;
136 c.X = c.Y = 0;
137 ok(SetConsoleCursorPosition(0, c) == 0, "No handle\n");
138 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %lu\n",
139 ERROR_INVALID_HANDLE, GetLastError());
141 c.X = c.Y = 0;
142 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
143 okCURSOR(hCon, c);
145 c.X = sbSize.X - 1;
146 c.Y = sbSize.Y - 1;
147 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in lower-right\n");
148 okCURSOR(hCon, c);
150 c.X = sbSize.X;
151 c.Y = sbSize.Y - 1;
152 ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
153 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n",
154 ERROR_INVALID_PARAMETER, GetLastError());
156 c.X = sbSize.X - 1;
157 c.Y = sbSize.Y;
158 ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
159 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n",
160 ERROR_INVALID_PARAMETER, GetLastError());
162 c.X = -1;
163 c.Y = 0;
164 ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
165 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n",
166 ERROR_INVALID_PARAMETER, GetLastError());
168 c.X = 0;
169 c.Y = -1;
170 ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
171 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n",
172 ERROR_INVALID_PARAMETER, GetLastError());
175 static void testCursorInfo(HANDLE hCon)
177 BOOL ret;
178 CONSOLE_CURSOR_INFO info;
179 HANDLE pipe1, pipe2;
181 SetLastError(0xdeadbeef);
182 ret = GetConsoleCursorInfo(NULL, NULL);
183 ok(!ret, "Expected failure\n");
184 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %lu\n",
185 ERROR_INVALID_HANDLE, GetLastError());
187 SetLastError(0xdeadbeef);
188 info.dwSize = -1;
189 ret = GetConsoleCursorInfo(NULL, &info);
190 ok(!ret, "Expected failure\n");
191 ok(info.dwSize == -1, "Expected no change for dwSize\n");
192 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %lu\n",
193 ERROR_INVALID_HANDLE, GetLastError());
195 /* Test the correct call first to distinguish between win9x and the rest */
196 SetLastError(0xdeadbeef);
197 ret = GetConsoleCursorInfo(hCon, &info);
198 ok(ret, "Expected success\n");
199 ok(info.dwSize == 25 ||
200 info.dwSize == 12 /* win9x */,
201 "Expected 12 or 25, got %ld\n", info.dwSize);
202 ok(info.bVisible, "Expected the cursor to be visible\n");
203 ok(GetLastError() == 0xdeadbeef, "GetLastError: expecting %u got %lu\n",
204 0xdeadbeef, GetLastError());
206 CreatePipe(&pipe1, &pipe2, NULL, 0);
207 info.dwSize = -1;
208 ret = GetConsoleCursorInfo(pipe1, &info);
209 ok(!ret, "Expected failure\n");
210 ok(info.dwSize == -1, "Expected no change for dwSize\n");
211 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: %lu\n", GetLastError());
212 CloseHandle(pipe1);
213 CloseHandle(pipe2);
215 /* Don't test NULL CONSOLE_CURSOR_INFO, it crashes on win9x and win7 */
218 static void testEmptyWrite(HANDLE hCon)
220 static const char emptybuf[16];
221 COORD c;
222 DWORD len;
224 c.X = c.Y = 0;
225 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
227 len = -1;
228 ok(WriteConsoleA(hCon, NULL, 0, &len, NULL) != 0 && len == 0, "WriteConsole\n");
229 okCURSOR(hCon, c);
231 /* Passing a NULL lpBuffer with sufficiently large non-zero length succeeds
232 * on native Windows and result in memory-like contents being written to
233 * the console. Calling WriteConsoleW like this will crash on Wine. */
234 if (0)
236 len = -1;
237 ok(!WriteConsoleA(hCon, NULL, 16, &len, NULL) && len == -1, "WriteConsole\n");
238 okCURSOR(hCon, c);
240 /* Cursor advances for this call. */
241 len = -1;
242 ok(WriteConsoleA(hCon, NULL, 128, &len, NULL) != 0 && len == 128, "WriteConsole\n");
245 len = -1;
246 ok(WriteConsoleA(hCon, emptybuf, 0, &len, NULL) != 0 && len == 0, "WriteConsole\n");
247 okCURSOR(hCon, c);
249 /* WriteConsole does not halt on a null terminator and is happy to write
250 * memory contents beyond the actual size of the buffer. */
251 len = -1;
252 ok(WriteConsoleA(hCon, emptybuf, 16, &len, NULL) != 0 && len == 16, "WriteConsole\n");
253 c.X += 16;
254 okCURSOR(hCon, c);
257 static void simple_write_console(HANDLE console, const char *text)
259 DWORD len;
260 COORD c = {0, 0};
261 BOOL ret;
263 /* single line write */
264 c.X = c.Y = 0;
265 ok(SetConsoleCursorPosition(console, c) != 0, "Cursor in upper-left\n");
267 ret = WriteConsoleA(console, text, strlen(text), &len, NULL);
268 ok(ret, "WriteConsoleA failed: %lu\n", GetLastError());
269 ok(len == strlen(text), "unexpected len %lu\n", len);
272 static void testWriteSimple(HANDLE hCon)
274 const char* mytest = "abcdefg";
275 int mylen = strlen(mytest);
276 COORD c = {0, 0};
277 DWORD len;
278 BOOL ret;
280 simple_write_console(hCon, mytest);
282 for (c.X = 0; c.X < mylen; c.X++)
284 okCHAR(hCon, c, mytest[c.X], TEST_ATTRIB);
287 okCURSOR(hCon, c);
288 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
290 ret = WriteFile(hCon, mytest, mylen, &len, NULL);
291 ok(ret, "WriteFile failed: %lu\n", GetLastError());
292 ok(len == mylen, "unexpected len = %lu\n", len);
294 for (c.X = 0; c.X < 2 * mylen; c.X++)
296 okCHAR(hCon, c, mytest[c.X % mylen], TEST_ATTRIB);
299 okCURSOR(hCon, c);
300 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
303 static void testWriteNotWrappedNotProcessed(HANDLE hCon, COORD sbSize)
305 COORD c;
306 DWORD len, mode;
307 const char* mytest = "123";
308 const int mylen = strlen(mytest);
309 char ctrl_buf[32];
310 int ret;
311 int p;
313 ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode & ~(ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT)),
314 "clearing wrap at EOL & processed output\n");
316 /* write line, wrapping disabled, buffer exceeds sb width */
317 c.X = sbSize.X - 3; c.Y = 0;
318 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
320 ret = WriteConsoleA(hCon, mytest, mylen, &len, NULL);
321 ok(ret != 0 && len == mylen, "Couldn't write, ret = %d, len = %ld\n", ret, len);
322 c.Y = 0;
323 for (p = mylen - 3; p < mylen; p++)
325 c.X = sbSize.X - 3 + p % 3;
326 okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
329 c.X = 0; c.Y = 1;
330 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
332 p = sbSize.X - 3 + mylen % 3;
333 c.X = p; c.Y = 0;
335 /* write line, wrapping disabled, strings end on end of line */
336 c.X = sbSize.X - mylen; c.Y = 0;
337 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
339 ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
341 /* test how control chars are handled. */
342 c.X = c.Y = 0;
343 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
344 for (p = 0; p < 32; p++) ctrl_buf[p] = (char)p;
345 ok(WriteConsoleA(hCon, ctrl_buf, 32, &len, NULL) != 0 && len == 32, "WriteConsole\n");
346 for (p = 0; p < 32; p++)
348 c.X = p; c.Y = 0;
349 okCHAR(hCon, c, (char)p, TEST_ATTRIB);
353 static void testWriteNotWrappedProcessed(HANDLE hCon, COORD sbSize)
355 COORD c;
356 DWORD len, mode;
357 const char* mytest = "abcd\nf\tg";
358 const int mylen = strlen(mytest);
359 const int mylen2 = strchr(mytest, '\n') - mytest;
360 int p;
361 WORD attr;
363 ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, (mode | ENABLE_PROCESSED_OUTPUT) &
364 ~(ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING)),
365 "clearing wrap at EOL & setting processed output\n");
367 /* write line, wrapping disabled, buffer exceeds sb width */
368 c.X = sbSize.X - 5; c.Y = 0;
369 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-5\n");
371 ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
372 c.Y = 0;
373 for (c.X = sbSize.X - 5; c.X < sbSize.X - 1; c.X++)
375 okCHAR(hCon, c, mytest[c.X - sbSize.X + 5], TEST_ATTRIB);
378 ReadConsoleOutputAttribute(hCon, &attr, 1, c, &len);
379 /* Win9x and WinMe change the attribs for '\n' up to 'f' */
380 if (attr == TEST_ATTRIB)
382 win_skip("Win9x/WinMe don't respect ~ENABLE_WRAP_AT_EOL_OUTPUT\n");
383 return;
386 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
388 c.X = 0; c.Y++;
389 okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
390 for (c.X = 1; c.X < 8; c.X++)
391 okCHAR(hCon, c, ' ', TEST_ATTRIB);
392 okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
393 c.X++;
394 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
396 okCURSOR(hCon, c);
398 /* write line, wrapping disabled, strings end on end of line */
399 c.X = sbSize.X - 4; c.Y = 0;
400 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-4\n");
402 ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
403 c.Y = 0;
404 for (c.X = sbSize.X - 4; c.X < sbSize.X; c.X++)
406 okCHAR(hCon, c, mytest[c.X - sbSize.X + 4], TEST_ATTRIB);
408 c.X = 0; c.Y++;
409 okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
410 for (c.X = 1; c.X < 8; c.X++)
411 okCHAR(hCon, c, ' ', TEST_ATTRIB);
412 okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
413 c.X++;
414 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
416 okCURSOR(hCon, c);
418 /* write line, wrapping disabled, strings end after end of line */
419 c.X = sbSize.X - 3; c.Y = 0;
420 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-4\n");
422 ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
423 c.Y = 0;
424 for (p = mylen2 - 3; p < mylen2; p++)
426 c.X = sbSize.X - 3 + p % 3;
427 okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
429 c.X = 0; c.Y = 1;
430 okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
431 for (c.X = 1; c.X < 8; c.X++)
432 okCHAR(hCon, c, ' ', TEST_ATTRIB);
433 okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
434 c.X++;
435 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
437 okCURSOR(hCon, c);
440 static void testWriteWrappedNotProcessed(HANDLE hCon, COORD sbSize)
442 COORD c;
443 DWORD len, mode;
444 const char* mytest = "abcd\nf\tg";
445 const int mylen = strlen(mytest);
446 int p;
448 ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon,(mode | ENABLE_WRAP_AT_EOL_OUTPUT) & ~(ENABLE_PROCESSED_OUTPUT)),
449 "setting wrap at EOL & clearing processed output\n");
451 /* write line, wrapping enabled, buffer doesn't exceed sb width */
452 c.X = sbSize.X - 9; c.Y = 0;
453 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-9\n");
455 ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
456 c.Y = 0;
457 for (p = 0; p < mylen; p++)
459 c.X = sbSize.X - 9 + p;
460 okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
462 c.X = sbSize.X - 9 + mylen;
463 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
464 c.X = 0; c.Y = 1;
465 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
467 /* write line, wrapping enabled, buffer does exceed sb width */
468 c.X = sbSize.X - 3; c.Y = 0;
469 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
471 c.Y = 1;
472 c.X = mylen - 3;
473 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
476 static void testWriteWrappedProcessed(HANDLE hCon, COORD sbSize)
478 COORD c;
479 DWORD len, mode;
480 const char* mytest = "abcd\nf\tg";
481 const int mylen = strlen(mytest);
482 int p;
483 WORD attr;
485 ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode | (ENABLE_WRAP_AT_EOL_OUTPUT|ENABLE_PROCESSED_OUTPUT)),
486 "setting wrap at EOL & processed output\n");
488 /* write line, wrapping enabled, buffer doesn't exceed sb width */
489 c.X = sbSize.X - 9; c.Y = 0;
490 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-9\n");
492 ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
493 for (p = 0; p < 4; p++)
495 c.X = sbSize.X - 9 + p;
496 okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
498 c.X = sbSize.X - 9 + p;
499 ReadConsoleOutputAttribute(hCon, &attr, 1, c, &len);
500 if (attr == TEST_ATTRIB)
501 win_skip("Win9x/WinMe changes attribs for '\\n' up to 'f'\n");
502 else
503 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
504 c.X = 0; c.Y++;
505 okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
506 for (c.X = 1; c.X < 8; c.X++)
507 okCHAR(hCon, c, ' ', TEST_ATTRIB);
508 okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
509 c.X++;
510 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
511 okCURSOR(hCon, c);
513 /* write line, wrapping enabled, buffer does exceed sb width */
514 c.X = sbSize.X - 3; c.Y = 2;
515 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
517 ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
518 for (p = 0; p < 3; p++)
520 c.X = sbSize.X - 3 + p;
521 okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
523 c.X = 0; c.Y++;
524 okCHAR(hCon, c, mytest[3], TEST_ATTRIB);
525 c.X++;
526 ReadConsoleOutputAttribute(hCon, &attr, 1, c, &len);
527 if (attr == TEST_ATTRIB)
528 win_skip("Win9x/WinMe changes attribs for '\\n' up to 'f'\n");
529 else
530 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
532 c.X = 0; c.Y++;
533 okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
534 for (c.X = 1; c.X < 8; c.X++)
535 okCHAR(hCon, c, ' ', TEST_ATTRIB);
536 okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
537 c.X++;
538 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
539 okCURSOR(hCon, c);
542 static void testWrite(HANDLE hCon, COORD sbSize)
544 /* FIXME: should in fact ensure that the sb is at least 10 characters wide */
545 ok(SetConsoleTextAttribute(hCon, TEST_ATTRIB), "Setting default text color\n");
546 resetContent(hCon, sbSize, FALSE);
547 testEmptyWrite(hCon);
548 resetContent(hCon, sbSize, FALSE);
549 testWriteSimple(hCon);
550 resetContent(hCon, sbSize, FALSE);
551 testWriteNotWrappedNotProcessed(hCon, sbSize);
552 resetContent(hCon, sbSize, FALSE);
553 testWriteNotWrappedProcessed(hCon, sbSize);
554 resetContent(hCon, sbSize, FALSE);
555 testWriteWrappedNotProcessed(hCon, sbSize);
556 resetContent(hCon, sbSize, FALSE);
557 testWriteWrappedProcessed(hCon, sbSize);
560 static void testScroll(HANDLE hCon, COORD sbSize)
562 SMALL_RECT scroll, clip;
563 COORD dst, c, tc;
564 CHAR_INFO ci;
565 BOOL ret;
567 #define W 11
568 #define H 7
570 #define IN_SRECT(r,c) ((r).Left <= (c).X && (c).X <= (r).Right && (r).Top <= (c).Y && (c).Y <= (r).Bottom)
571 #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)
573 /* no clipping, src & dst rect don't overlap */
574 resetContent(hCon, sbSize, TRUE);
576 scroll.Left = 0;
577 scroll.Right = W - 1;
578 scroll.Top = 0;
579 scroll.Bottom = H - 1;
580 dst.X = W + 3;
581 dst.Y = H + 3;
582 ci.Char.UnicodeChar = '#';
583 ci.Attributes = TEST_ATTRIB;
585 clip.Left = 0;
586 clip.Right = sbSize.X - 1;
587 clip.Top = 0;
588 clip.Bottom = sbSize.Y - 1;
590 ok(ScrollConsoleScreenBufferA(hCon, &scroll, NULL, dst, &ci), "Scrolling SB\n");
592 for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
594 for (c.X = 0; c.X < sbSize.X; c.X++)
596 if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
598 tc.X = c.X - dst.X;
599 tc.Y = c.Y - dst.Y;
600 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
602 else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
603 okCHAR(hCon, c, '#', TEST_ATTRIB);
604 else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
608 /* no clipping, src & dst rect do overlap */
609 resetContent(hCon, sbSize, TRUE);
611 scroll.Left = 0;
612 scroll.Right = W - 1;
613 scroll.Top = 0;
614 scroll.Bottom = H - 1;
615 dst.X = W /2;
616 dst.Y = H / 2;
617 ci.Char.UnicodeChar = '#';
618 ci.Attributes = TEST_ATTRIB;
620 clip.Left = 0;
621 clip.Right = sbSize.X - 1;
622 clip.Top = 0;
623 clip.Bottom = sbSize.Y - 1;
625 ok(ScrollConsoleScreenBufferA(hCon, &scroll, NULL, dst, &ci), "Scrolling SB\n");
627 for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
629 for (c.X = 0; c.X < sbSize.X; c.X++)
631 if (dst.X <= c.X && c.X < dst.X + W && dst.Y <= c.Y && c.Y < dst.Y + H)
633 tc.X = c.X - dst.X;
634 tc.Y = c.Y - dst.Y;
635 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
637 else if (c.X < W && c.Y < H) okCHAR(hCon, c, '#', TEST_ATTRIB);
638 else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
642 /* clipping, src & dst rect don't overlap */
643 resetContent(hCon, sbSize, TRUE);
645 scroll.Left = 0;
646 scroll.Right = W - 1;
647 scroll.Top = 0;
648 scroll.Bottom = H - 1;
649 dst.X = W + 3;
650 dst.Y = H + 3;
651 ci.Char.UnicodeChar = '#';
652 ci.Attributes = TEST_ATTRIB;
654 clip.Left = W / 2;
655 clip.Right = min(W + W / 2, sbSize.X - 1);
656 clip.Top = H / 2;
657 clip.Bottom = min(H + H / 2, sbSize.Y - 1);
659 SetLastError(0xdeadbeef);
660 ret = ScrollConsoleScreenBufferA(hCon, &scroll, &clip, dst, &ci);
661 if (ret)
663 for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
665 for (c.X = 0; c.X < sbSize.X; c.X++)
667 if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
669 tc.X = c.X - dst.X;
670 tc.Y = c.Y - dst.Y;
671 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
673 else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
674 okCHAR(hCon, c, '#', TEST_ATTRIB);
675 else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
679 else
681 /* Win9x will fail, Only accept ERROR_NOT_ENOUGH_MEMORY */
682 ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY,
683 "Expected ERROR_NOT_ENOUGH_MEMORY, got %lu\n", GetLastError());
686 /* no clipping, src & dst rect do overlap */
687 scroll.Left = 0;
688 scroll.Right = W - 1;
689 scroll.Top = 0;
690 scroll.Bottom = H - 1;
691 dst.X = W / 2 - 3;
692 dst.Y = H / 2 - 3;
693 ci.Char.UnicodeChar = '#';
694 ci.Attributes = TEST_ATTRIB;
696 ret = ScrollConsoleScreenBufferA(hCon, &scroll, NULL, dst, &ci);
697 ok(ret, "ScrollConsoleScreenBufferA failed: %lu\n", GetLastError());
698 /* no win10 1909 error here, only check the result of the clipped case */
700 /* clipping, src & dst rect do overlap */
701 resetContent(hCon, sbSize, TRUE);
703 scroll.Left = 0;
704 scroll.Right = W - 1;
705 scroll.Top = 0;
706 scroll.Bottom = H - 1;
707 dst.X = W / 2 - 3;
708 dst.Y = H / 2 - 3;
709 ci.Char.UnicodeChar = '#';
710 ci.Attributes = TEST_ATTRIB;
712 clip.Left = W / 2;
713 clip.Right = min(W + W / 2, sbSize.X - 1);
714 clip.Top = H / 2;
715 clip.Bottom = min(H + H / 2, sbSize.Y - 1);
717 /* Windows 10 1909 fails if the destination is not in the clip rect
718 * but the result is still ok!
720 SetLastError(0xdeadbeef);
721 ret = ScrollConsoleScreenBufferA(hCon, &scroll, &clip, dst, &ci);
722 ok((ret && GetLastError() == 0xdeadbeef) ||
723 broken(!ret && GetLastError() == ERROR_INVALID_PARAMETER),
724 "ScrollConsoleScreenBufferA failed: %lu\n", GetLastError());
726 for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
728 for (c.X = 0; c.X < sbSize.X; c.X++)
730 if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
732 tc.X = c.X - dst.X;
733 tc.Y = c.Y - dst.Y;
734 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
736 else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
737 okCHAR(hCon, c, '#', TEST_ATTRIB);
738 else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
743 static int mch_count;
744 /* we need the event as Wine console event generation isn't synchronous
745 * (ie GenerateConsoleCtrlEvent returns before all ctrl-handlers in all
746 * processes have been called).
748 static HANDLE mch_event;
749 static BOOL WINAPI mch(DWORD event)
751 mch_count++;
752 SetEvent(mch_event);
753 return TRUE;
756 static void testCtrlHandler(void)
758 ok(!SetConsoleCtrlHandler(mch, FALSE), "Shouldn't succeed\n");
759 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %lu\n", GetLastError());
760 ok(SetConsoleCtrlHandler(mch, TRUE), "Couldn't set handler\n");
761 /* wine requires the event for the test, as we cannot ensure, so far, that
762 * events are processed synchronously in GenerateConsoleCtrlEvent()
764 mch_event = CreateEventA(NULL, TRUE, FALSE, NULL);
765 mch_count = 0;
766 ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n");
767 /* FIXME: it isn't synchronous on wine but it can still happen before we test */
768 if (0) ok(mch_count == 1, "Event isn't synchronous\n");
769 ok(WaitForSingleObject(mch_event, 3000) == WAIT_OBJECT_0, "event sending didn't work\n");
770 CloseHandle(mch_event);
772 ok(SetConsoleCtrlHandler(NULL, FALSE), "Couldn't turn on ctrl-c handling\n");
773 ok((RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags & 1) == 0,
774 "Unexpect ConsoleFlags value %lx\n", RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags);
776 /* Turning off ctrl-c handling doesn't work on win9x such way ... */
777 ok(SetConsoleCtrlHandler(NULL, TRUE), "Couldn't turn off ctrl-c handling\n");
778 ok((RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags & 1) != 0,
779 "Unexpect ConsoleFlags value %lx\n", RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags);
780 mch_event = CreateEventA(NULL, TRUE, FALSE, NULL);
781 mch_count = 0;
782 if(!(GetVersion() & 0x80000000))
783 /* ... and next line leads to an unhandled exception on 9x. Avoid it on 9x. */
784 ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n");
785 ok(WaitForSingleObject(mch_event, 3000) == WAIT_TIMEOUT && mch_count == 0, "Event shouldn't have been sent\n");
786 CloseHandle(mch_event);
787 ok(SetConsoleCtrlHandler(mch, FALSE), "Couldn't remove handler\n");
788 ok(!SetConsoleCtrlHandler(mch, FALSE), "Shouldn't succeed\n");
789 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %lu\n", GetLastError());
793 * Test console screen buffer:
794 * 1) Try to set invalid handle.
795 * 2) Try to set non-console handles.
796 * 3) Use CONOUT$ file as active SB.
797 * 4) Test cursor.
798 * 5) Test output codepage to show it is not a property of SB.
799 * 6) Test switching to old SB if we close all handles to current SB - works
800 * in Windows, TODO in wine.
802 * What is not tested but should be:
803 * 1) ScreenBufferInfo
805 static void testScreenBuffer(HANDLE hConOut)
807 HANDLE hConOutRW, hConOutRO, hConOutWT;
808 HANDLE hFileOutRW, hFileOutRO, hFileOutWT;
809 HANDLE hConOutNew;
810 char test_str1[] = "Test for SB1";
811 char test_str2[] = "Test for SB2";
812 char test_cp866[] = {0xe2, 0xa5, 0xe1, 0xe2, 0};
813 char test_cp1251[] = {0xf2, 0xe5, 0xf1, 0xf2, 0};
814 WCHAR test_unicode[] = {0x0442, 0x0435, 0x0441, 0x0442, 0};
815 WCHAR str_wbuf[20];
816 char str_buf[20];
817 DWORD len, error;
818 COORD c;
819 BOOL ret;
820 DWORD oldcp;
822 if (!IsValidCodePage(866))
824 skip("Codepage 866 not available\n");
825 return;
828 /* In the beginning set output codepage to 866 */
829 oldcp = GetConsoleOutputCP();
830 SetLastError(0xdeadbeef);
831 ret = SetConsoleOutputCP(866);
832 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
834 win_skip("SetConsoleOutputCP is not implemented\n");
835 return;
837 ok(ret, "Cannot set output codepage to 866\n");
839 hConOutRW = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
840 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
841 CONSOLE_TEXTMODE_BUFFER, NULL);
842 ok(hConOutRW != INVALID_HANDLE_VALUE,
843 "Cannot create a new screen buffer for ReadWrite\n");
844 hConOutRO = CreateConsoleScreenBuffer(GENERIC_READ,
845 FILE_SHARE_READ, NULL,
846 CONSOLE_TEXTMODE_BUFFER, NULL);
847 ok(hConOutRO != INVALID_HANDLE_VALUE,
848 "Cannot create a new screen buffer for ReadOnly\n");
849 hConOutWT = CreateConsoleScreenBuffer(GENERIC_WRITE,
850 FILE_SHARE_WRITE, NULL,
851 CONSOLE_TEXTMODE_BUFFER, NULL);
852 ok(hConOutWT != INVALID_HANDLE_VALUE,
853 "Cannot create a new screen buffer for WriteOnly\n");
855 hFileOutRW = CreateFileA("NUL", GENERIC_READ | GENERIC_WRITE,
856 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
857 OPEN_EXISTING, 0, NULL);
858 ok(hFileOutRW != INVALID_HANDLE_VALUE, "Cannot open NUL for ReadWrite\n");
859 hFileOutRO = CreateFileA("NUL", GENERIC_READ, FILE_SHARE_READ,
860 NULL, OPEN_EXISTING, 0, NULL);
861 ok(hFileOutRO != INVALID_HANDLE_VALUE, "Cannot open NUL for ReadOnly\n");
862 hFileOutWT = CreateFileA("NUL", GENERIC_WRITE, FILE_SHARE_WRITE,
863 NULL, OPEN_EXISTING, 0, NULL);
864 ok(hFileOutWT != INVALID_HANDLE_VALUE, "Cannot open NUL for WriteOnly\n");
866 /* Trying to set invalid handle */
867 SetLastError(0);
868 ok(!SetConsoleActiveScreenBuffer(INVALID_HANDLE_VALUE),
869 "Shouldn't succeed\n");
870 ok(GetLastError() == ERROR_INVALID_HANDLE,
871 "GetLastError: expecting %u got %lu\n",
872 ERROR_INVALID_HANDLE, GetLastError());
874 /* Trying to set non-console handles */
875 SetLastError(0);
876 ok(!SetConsoleActiveScreenBuffer(hFileOutRW), "Shouldn't succeed\n");
877 ok(GetLastError() == ERROR_INVALID_HANDLE,
878 "GetLastError: expecting %u got %lu\n",
879 ERROR_INVALID_HANDLE, GetLastError());
881 SetLastError(0);
882 ok(!SetConsoleActiveScreenBuffer(hFileOutRO), "Shouldn't succeed\n");
883 ok(GetLastError() == ERROR_INVALID_HANDLE,
884 "GetLastError: expecting %u got %lu\n",
885 ERROR_INVALID_HANDLE, GetLastError());
887 SetLastError(0);
888 ok(!SetConsoleActiveScreenBuffer(hFileOutWT), "Shouldn't succeed\n");
889 ok(GetLastError() == ERROR_INVALID_HANDLE,
890 "GetLastError: expecting %u got %lu\n",
891 ERROR_INVALID_HANDLE, GetLastError());
893 /* trying to write non-console handle */
894 SetLastError(0xdeadbeef);
895 ret = WriteConsoleA(hFileOutRW, test_str1, lstrlenA(test_str1), &len, NULL);
896 error = GetLastError();
897 ok(!ret, "Shouldn't succeed\n");
898 ok(error == ERROR_INVALID_HANDLE || error == ERROR_INVALID_FUNCTION,
899 "GetLastError: got %lu\n", error);
901 SetLastError(0xdeadbeef);
902 ret = WriteConsoleA(hFileOutRO, test_str1, lstrlenA(test_str1), &len, NULL);
903 error = GetLastError();
904 ok(!ret, "Shouldn't succeed\n");
905 ok(error == ERROR_INVALID_HANDLE || error == ERROR_INVALID_FUNCTION,
906 "GetLastError: got %lu\n", error);
908 SetLastError(0xdeadbeef);
909 ret = WriteConsoleA(hFileOutWT, test_str1, lstrlenA(test_str1), &len, NULL);
910 error = GetLastError();
911 ok(!ret, "Shouldn't succeed\n");
912 ok(error == ERROR_INVALID_HANDLE || error == ERROR_INVALID_FUNCTION,
913 "GetLastError: got %lu\n", error);
915 CloseHandle(hFileOutRW);
916 CloseHandle(hFileOutRO);
917 CloseHandle(hFileOutWT);
919 /* Trying to set SB handles with various access modes */
920 SetLastError(0);
921 ok(!SetConsoleActiveScreenBuffer(hConOutRO), "Shouldn't succeed\n");
922 ok(GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == ERROR_ACCESS_DENIED) /* win10 1809 */,
923 "unexpected last error %lu\n", GetLastError());
925 ok(SetConsoleActiveScreenBuffer(hConOutWT), "Couldn't set new WriteOnly SB\n");
927 ok(SetConsoleActiveScreenBuffer(hConOutRW), "Couldn't set new ReadWrite SB\n");
929 CloseHandle(hConOutWT);
930 CloseHandle(hConOutRO);
932 /* Now we have two ReadWrite SB, active must be hConOutRW */
933 /* Open current SB via CONOUT$ */
934 hConOutNew = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0,
935 NULL, OPEN_EXISTING, 0, 0);
936 ok(hConOutNew != INVALID_HANDLE_VALUE, "CONOUT$ is not opened\n");
939 /* test cursor */
940 c.X = c.Y = 10;
941 SetConsoleCursorPosition(hConOut, c);
942 c.X = c.Y = 5;
943 SetConsoleCursorPosition(hConOutRW, c);
944 okCURSOR(hConOutNew, c);
945 c.X = c.Y = 10;
946 okCURSOR(hConOut, c);
949 c.X = c.Y = 0;
951 /* Write using hConOutNew... */
952 SetConsoleCursorPosition(hConOutNew, c);
953 ret = WriteConsoleA(hConOutNew, test_str2, lstrlenA(test_str2), &len, NULL);
954 ok (ret && len == lstrlenA(test_str2), "WriteConsoleA failed\n");
955 /* ... and read it back via hConOutRW */
956 ret = ReadConsoleOutputCharacterA(hConOutRW, str_buf, lstrlenA(test_str2), c, &len);
957 ok(ret && len == lstrlenA(test_str2), "ReadConsoleOutputCharacterA failed\n");
958 str_buf[lstrlenA(test_str2)] = 0;
959 ok(!lstrcmpA(str_buf, test_str2), "got '%s' expected '%s'\n", str_buf, test_str2);
962 /* Now test output codepage handling. Current is 866 as we set earlier. */
963 SetConsoleCursorPosition(hConOutRW, c);
964 ret = WriteConsoleA(hConOutRW, test_cp866, lstrlenA(test_cp866), &len, NULL);
965 ok(ret && len == lstrlenA(test_cp866), "WriteConsoleA failed\n");
966 ret = ReadConsoleOutputCharacterW(hConOutRW, str_wbuf, lstrlenW(test_unicode), c, &len);
967 /* Work around some broken results under Windows with some locale (ja, cn, ko...)
968 * Looks like a real bug in Win10 (at least).
970 if (ret && broken(len == lstrlenW(test_unicode) / sizeof(WCHAR)))
971 ret = ReadConsoleOutputCharacterW(hConOutRW, str_wbuf, lstrlenW(test_unicode) * sizeof(WCHAR), c, &len);
972 ok(ret, "ReadConsoleOutputCharacterW failed\n");
973 ok(len == lstrlenW(test_unicode), "unexpected len %lu %u\n", len, lstrlenW(test_unicode));
974 ok(!memcmp(str_wbuf, test_unicode, lstrlenW(test_unicode) * sizeof(WCHAR)),
975 "string does not match the pattern\n");
978 * cp866 is OK, let's switch to cp1251.
979 * We expect that this codepage will be used in every SB - active and not.
981 ok(SetConsoleOutputCP(1251), "Cannot set output cp to 1251\n");
982 SetConsoleCursorPosition(hConOutRW, c);
983 ret = WriteConsoleA(hConOutRW, test_cp1251, lstrlenA(test_cp1251), &len, NULL);
984 ok(ret && len == lstrlenA(test_cp1251), "WriteConsoleA failed\n");
985 ret = ReadConsoleOutputCharacterW(hConOutRW, str_wbuf, lstrlenA(test_cp1251), c, &len);
986 ok(ret && len == lstrlenA(test_cp1251), "ReadConsoleOutputCharacterW failed\n");
987 str_wbuf[lstrlenA(test_cp1251)] = 0;
988 ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n");
990 /* Check what has happened to hConOut. */
991 SetConsoleCursorPosition(hConOut, c);
992 ret = WriteConsoleA(hConOut, test_cp1251, lstrlenA(test_cp1251), &len, NULL);
993 ok(ret && len == lstrlenA(test_cp1251), "WriteConsoleA failed\n");
994 ret = ReadConsoleOutputCharacterW(hConOut, str_wbuf, lstrlenA(test_cp1251), c, &len);
995 ok(ret && len == lstrlenA(test_cp1251), "ReadConsoleOutputCharacterW failed\n");
996 str_wbuf[lstrlenA(test_cp1251)] = 0;
997 ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n");
999 /* Close all handles of current console SB */
1000 CloseHandle(hConOutNew);
1001 CloseHandle(hConOutRW);
1003 /* Now active SB should be hConOut */
1004 hConOutNew = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0,
1005 NULL, OPEN_EXISTING, 0, 0);
1006 ok(hConOutNew != INVALID_HANDLE_VALUE, "CONOUT$ is not opened\n");
1008 /* Write using hConOutNew... */
1009 SetConsoleCursorPosition(hConOutNew, c);
1010 ret = WriteConsoleA(hConOutNew, test_str1, lstrlenA(test_str1), &len, NULL);
1011 ok (ret && len == lstrlenA(test_str1), "WriteConsoleA failed\n");
1012 /* ... and read it back via hConOut */
1013 ret = ReadConsoleOutputCharacterA(hConOut, str_buf, lstrlenA(test_str1), c, &len);
1014 ok(ret && len == lstrlenA(test_str1), "ReadConsoleOutputCharacterA failed\n");
1015 str_buf[lstrlenA(test_str1)] = 0;
1016 todo_wine ok(!lstrcmpA(str_buf, test_str1), "got '%s' expected '%s'\n", str_buf, test_str1);
1017 CloseHandle(hConOutNew);
1019 /* This is not really needed under Windows */
1020 SetConsoleActiveScreenBuffer(hConOut);
1022 /* restore codepage */
1023 SetConsoleOutputCP(oldcp);
1026 static void test_new_screen_buffer_properties(HANDLE hConOut)
1028 BOOL ret;
1029 HANDLE hConOut2;
1030 CONSOLE_FONT_INFOEX cfi, cfi2;
1031 CONSOLE_SCREEN_BUFFER_INFO csbi, csbi2;
1033 /* Font information */
1034 cfi.cbSize = cfi2.cbSize = sizeof(CONSOLE_FONT_INFOEX);
1036 ret = GetCurrentConsoleFontEx(hConOut, FALSE, &cfi);
1037 ok(ret, "GetCurrentConsoleFontEx failed: error %lu\n", GetLastError());
1039 hConOut2 = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, 0, NULL,
1040 CONSOLE_TEXTMODE_BUFFER, NULL);
1041 ok(hConOut2 != INVALID_HANDLE_VALUE, "CreateConsoleScreenBuffer failed: error %lu\n", GetLastError());
1043 ret = GetCurrentConsoleFontEx(hConOut2, FALSE, &cfi2);
1044 ok(ret, "GetCurrentConsoleFontEx failed: error %lu\n", GetLastError());
1045 CloseHandle(hConOut2);
1047 ok(cfi2.nFont == cfi.nFont, "Font index should match: "
1048 "got %lu, expected %lu\n", cfi2.nFont, cfi.nFont);
1049 ok(cfi2.dwFontSize.X == cfi.dwFontSize.X, "Font width should match: "
1050 "got %d, expected %d\n", cfi2.dwFontSize.X, cfi.dwFontSize.X);
1051 ok(cfi2.dwFontSize.Y == cfi.dwFontSize.Y, "Font height should match: "
1052 "got %d, expected %d\n", cfi2.dwFontSize.Y, cfi.dwFontSize.Y);
1053 ok(cfi2.FontFamily == cfi.FontFamily, "Font family should match: "
1054 "got %u, expected %u\n", cfi2.FontFamily, cfi.FontFamily);
1055 ok(cfi2.FontWeight == cfi.FontWeight, "Font weight should match: "
1056 "got %u, expected %u\n", cfi2.FontWeight, cfi.FontWeight);
1057 ok(!lstrcmpW(cfi2.FaceName, cfi.FaceName), "Font name should match: "
1058 "got %s, expected %s\n", wine_dbgstr_w(cfi2.FaceName), wine_dbgstr_w(cfi.FaceName));
1060 /* Display window size */
1061 ret = GetConsoleScreenBufferInfo(hConOut, &csbi);
1062 ok(ret, "GetConsoleScreenBufferInfo failed: error %lu\n", GetLastError());
1064 hConOut2 = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, 0, NULL,
1065 CONSOLE_TEXTMODE_BUFFER, NULL);
1066 ok(hConOut2 != INVALID_HANDLE_VALUE, "CreateConsoleScreenBuffer failed: error %lu\n", GetLastError());
1068 ret = GetConsoleScreenBufferInfo(hConOut2, &csbi2);
1069 ok(ret, "GetConsoleScreenBufferInfo failed: error %lu\n", GetLastError());
1070 CloseHandle(hConOut2);
1072 ok(csbi2.srWindow.Left == csbi.srWindow.Left, "Left coordinate should match\n");
1073 ok(csbi2.srWindow.Top == csbi.srWindow.Top, "Top coordinate should match\n");
1074 ok(csbi2.srWindow.Right == csbi.srWindow.Right, "Right coordinate should match\n");
1075 ok(csbi2.srWindow.Bottom == csbi.srWindow.Bottom, "Bottom coordinate should match\n");
1078 static void test_new_screen_buffer_color_attributes(HANDLE hConOut)
1080 CONSOLE_SCREEN_BUFFER_INFOEX csbi, csbi2;
1081 BOOL ret;
1082 HANDLE hConOut2;
1083 WORD orig_attr, orig_popup, attr;
1085 csbi.cbSize = csbi2.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
1087 ret = GetConsoleScreenBufferInfoEx(hConOut, &csbi);
1088 ok(ret, "GetConsoleScreenBufferInfoEx failed: error %lu\n", GetLastError());
1089 orig_attr = csbi.wAttributes;
1090 orig_popup = csbi.wPopupAttributes;
1092 hConOut2 = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, 0, NULL,
1093 CONSOLE_TEXTMODE_BUFFER, NULL);
1094 ok(hConOut2 != INVALID_HANDLE_VALUE, "CreateConsoleScreenBuffer failed: error %lu\n", GetLastError());
1096 ret = GetConsoleScreenBufferInfoEx(hConOut2, &csbi2);
1097 ok(ret, "GetConsoleScreenBufferInfoEx failed: error %lu\n", GetLastError());
1098 CloseHandle(hConOut2);
1100 ok(csbi2.wAttributes == orig_attr, "Character Attributes should have been copied: "
1101 "got %#x, expected %#x\n", csbi2.wAttributes, orig_attr);
1102 ok(csbi2.wPopupAttributes != orig_popup, "Popup Attributes should not match original value\n");
1103 ok(csbi2.wPopupAttributes == orig_attr, "Popup Attributes should match Character Attributes\n");
1105 /* Test different Character Attributes */
1106 attr = FOREGROUND_BLUE|BACKGROUND_GREEN;
1107 ret = SetConsoleTextAttribute(hConOut, attr);
1108 ok(ret, "SetConsoleTextAttribute failed: error %lu\n", GetLastError());
1110 hConOut2 = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, 0, NULL,
1111 CONSOLE_TEXTMODE_BUFFER, NULL);
1112 ok(hConOut2 != INVALID_HANDLE_VALUE, "CreateConsoleScreenBuffer failed: error %lu\n", GetLastError());
1114 memset(&csbi2, 0, sizeof(CONSOLE_SCREEN_BUFFER_INFOEX));
1115 csbi2.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
1117 ret = GetConsoleScreenBufferInfoEx(hConOut2, &csbi2);
1118 ok(ret, "GetConsoleScreenBufferInfoEx failed: error %lu\n", GetLastError());
1119 CloseHandle(hConOut2);
1121 ok(csbi2.wAttributes == attr, "Character Attributes should have been copied: "
1122 "got %#x, expected %#x\n", csbi2.wAttributes, attr);
1123 ok(csbi2.wPopupAttributes != orig_popup, "Popup Attributes should not match original value\n");
1124 ok(csbi2.wPopupAttributes == attr, "Popup Attributes should match Character Attributes\n");
1126 ret = SetConsoleTextAttribute(hConOut, orig_attr);
1127 ok(ret, "SetConsoleTextAttribute failed: error %lu\n", GetLastError());
1129 /* Test inheritance of different Popup Attributes */
1130 csbi.wPopupAttributes = attr;
1131 ret = SetConsoleScreenBufferInfoEx(hConOut, &csbi);
1132 ok(ret, "SetConsoleScreenBufferInfoEx failed: error %lu\n", GetLastError());
1134 hConOut2 = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, 0, NULL,
1135 CONSOLE_TEXTMODE_BUFFER, NULL);
1136 ok(hConOut2 != INVALID_HANDLE_VALUE, "CreateConsoleScreenBuffer failed: error %lu\n", GetLastError());
1138 memset(&csbi2, 0, sizeof(CONSOLE_SCREEN_BUFFER_INFOEX));
1139 csbi2.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
1141 ret = GetConsoleScreenBufferInfoEx(hConOut2, &csbi2);
1142 ok(ret, "GetConsoleScreenBufferInfoEx failed: error %lu\n", GetLastError());
1143 CloseHandle(hConOut2);
1145 ok(csbi2.wAttributes == orig_attr, "Character Attributes should have been copied: "
1146 "got %#x, expected %#x\n", csbi2.wAttributes, orig_attr);
1147 ok(csbi2.wPopupAttributes != orig_popup, "Popup Attributes should not match original value\n");
1148 ok(csbi2.wPopupAttributes == orig_attr, "Popup Attributes should match Character Attributes\n");
1150 csbi.wPopupAttributes = orig_popup;
1151 ret = SetConsoleScreenBufferInfoEx(hConOut, &csbi);
1152 ok(ret, "SetConsoleScreenBufferInfoEx failed: error %lu\n", GetLastError());
1155 static void CALLBACK signaled_function(void *p, BOOLEAN timeout)
1157 HANDLE event = p;
1158 SetEvent(event);
1159 ok(!timeout, "wait shouldn't have timed out\n");
1162 static void testWaitForConsoleInput(HANDLE input_handle)
1164 HANDLE wait_handle;
1165 HANDLE complete_event;
1166 INPUT_RECORD record;
1167 DWORD events_written;
1168 DWORD wait_ret;
1169 BOOL ret;
1171 complete_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1173 /* Test success case */
1174 ret = RegisterWaitForSingleObject(&wait_handle, input_handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
1175 ok(ret == TRUE, "Expected RegisterWaitForSingleObject to return TRUE, got %d\n", ret);
1176 /* give worker thread a chance to start up */
1177 Sleep(100);
1178 record.EventType = KEY_EVENT;
1179 record.Event.KeyEvent.bKeyDown = 1;
1180 record.Event.KeyEvent.wRepeatCount = 1;
1181 record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
1182 record.Event.KeyEvent.wVirtualScanCode = VK_RETURN;
1183 record.Event.KeyEvent.uChar.UnicodeChar = '\r';
1184 record.Event.KeyEvent.dwControlKeyState = 0;
1185 ret = WriteConsoleInputW(input_handle, &record, 1, &events_written);
1186 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1187 wait_ret = WaitForSingleObject(complete_event, INFINITE);
1188 ok(wait_ret == WAIT_OBJECT_0, "Expected the handle to be signaled\n");
1189 ret = UnregisterWait(wait_handle);
1190 /* If the callback is still running, this fails with ERROR_IO_PENDING, but
1191 that's ok and expected. */
1192 ok(ret != 0 || GetLastError() == ERROR_IO_PENDING,
1193 "UnregisterWait failed with error %ld\n", GetLastError());
1195 /* Test timeout case */
1196 FlushConsoleInputBuffer(input_handle);
1197 ret = RegisterWaitForSingleObject(&wait_handle, input_handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
1198 wait_ret = WaitForSingleObject(complete_event, 100);
1199 ok(wait_ret == WAIT_TIMEOUT, "Expected the wait to time out\n");
1200 ret = UnregisterWait(wait_handle);
1201 ok(ret, "UnregisterWait failed with error %ld\n", GetLastError());
1203 /* Clean up */
1204 CloseHandle(complete_event);
1207 static BOOL filter_spurious_event(HANDLE input)
1209 INPUT_RECORD ir;
1210 DWORD r;
1212 if (!ReadConsoleInputW(input, &ir, 1, &r) || r != 1) return FALSE;
1214 switch (ir.EventType)
1216 case MOUSE_EVENT:
1217 if (ir.Event.MouseEvent.dwEventFlags == MOUSE_MOVED) return TRUE;
1218 ok(0, "Unexcepted mouse message: state=%lx ctrl=%lx flags=%lx (%u, %u)\n",
1219 ir.Event.MouseEvent.dwButtonState,
1220 ir.Event.MouseEvent.dwControlKeyState,
1221 ir.Event.MouseEvent.dwEventFlags,
1222 ir.Event.MouseEvent.dwMousePosition.X,
1223 ir.Event.MouseEvent.dwMousePosition.Y);
1224 break;
1225 case WINDOW_BUFFER_SIZE_EVENT:
1226 return TRUE;
1227 default:
1228 ok(0, "Unexpected message %u\n", ir.EventType);
1230 return FALSE;
1233 static void test_wait(HANDLE input, HANDLE orig_output)
1235 HANDLE output, unbound_output, unbound_input;
1236 LARGE_INTEGER zero;
1237 INPUT_RECORD ir;
1238 DWORD res, count;
1239 NTSTATUS status;
1240 BOOL ret;
1242 if (skip_nt) return;
1244 memset(&ir, 0, sizeof(ir));
1245 ir.EventType = MOUSE_EVENT;
1246 ir.Event.MouseEvent.dwEventFlags = MOUSE_MOVED;
1247 zero.QuadPart = 0;
1249 output = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
1250 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1251 CONSOLE_TEXTMODE_BUFFER, NULL);
1252 ok(output != INVALID_HANDLE_VALUE, "CreateConsoleScreenBuffer failed: %lu\n", GetLastError());
1254 ret = SetConsoleActiveScreenBuffer(output);
1255 ok(ret, "SetConsoleActiveScreenBuffer failed: %lu\n", GetLastError());
1256 ret = FlushConsoleInputBuffer(input);
1257 ok(ret, "FlushConsoleInputBuffer failed: %lu\n", GetLastError());
1259 unbound_output = create_unbound_handle(TRUE, TRUE);
1260 unbound_input = create_unbound_handle(FALSE, TRUE);
1262 while ((res = WaitForSingleObject(input, 0)) == WAIT_OBJECT_0)
1264 if (!filter_spurious_event(input)) break;
1266 ok(res == WAIT_TIMEOUT, "WaitForSingleObject returned %lx\n", res);
1267 while ((res = WaitForSingleObject(output, 0)) == WAIT_OBJECT_0)
1269 if (!filter_spurious_event(input)) break;
1271 ok(res == WAIT_TIMEOUT, "WaitForSingleObject returned %lx\n", res);
1272 while ((res = WaitForSingleObject(orig_output, 0)) == WAIT_OBJECT_0)
1274 if (!filter_spurious_event(input)) break;
1276 ok(res == WAIT_TIMEOUT, "WaitForSingleObject returned %lx\n", res);
1277 while ((res = WaitForSingleObject(unbound_output, 0)) == WAIT_OBJECT_0)
1279 if (!filter_spurious_event(unbound_input)) break;
1281 ok(res == WAIT_TIMEOUT, "WaitForSingleObject returned %lx\n", res);
1282 while ((res = WaitForSingleObject(unbound_input, 0)) == WAIT_OBJECT_0)
1284 if (!filter_spurious_event(unbound_input)) break;
1286 ok(res == WAIT_TIMEOUT, "WaitForSingleObject returned %lx\n", res);
1287 while ((status = NtWaitForSingleObject(input, FALSE, &zero)) == STATUS_SUCCESS)
1289 if (!filter_spurious_event(input)) break;
1291 ok(status == STATUS_TIMEOUT || broken(status == STATUS_ACCESS_DENIED /* win2k8 */),
1292 "NtWaitForSingleObject returned %lx\n", status);
1293 while ((status = NtWaitForSingleObject(output, FALSE, &zero)) == STATUS_SUCCESS)
1295 if (!filter_spurious_event(input)) break;
1297 ok(status == STATUS_TIMEOUT || broken(status == STATUS_ACCESS_DENIED /* win2k8 */),
1298 "NtWaitForSingleObject returned %lx\n", status);
1300 ret = WriteConsoleInputW(input, &ir, 1, &count);
1301 ok(ret, "WriteConsoleInputW failed: %lu\n", GetLastError());
1303 res = WaitForSingleObject(input, 0);
1304 ok(!res, "WaitForSingleObject returned %lx\n", res);
1305 res = WaitForSingleObject(output, 0);
1306 ok(!res, "WaitForSingleObject returned %lx\n", res);
1307 res = WaitForSingleObject(orig_output, 0);
1308 ok(!res, "WaitForSingleObject returned %lx\n", res);
1309 res = WaitForSingleObject(unbound_output, 0);
1310 ok(!res, "WaitForSingleObject returned %lx\n", res);
1311 res = WaitForSingleObject(unbound_input, 0);
1312 ok(!res, "WaitForSingleObject returned %lx\n", res);
1313 status = NtWaitForSingleObject(input, FALSE, &zero);
1314 ok(!status || broken(status == STATUS_ACCESS_DENIED /* win2k8 */),
1315 "NtWaitForSingleObject returned %lx\n", status);
1316 status = NtWaitForSingleObject(output, FALSE, &zero);
1317 ok(!status || broken(status == STATUS_ACCESS_DENIED /* win2k8 */),
1318 "NtWaitForSingleObject returned %lx\n", status);
1320 ret = SetConsoleActiveScreenBuffer(orig_output);
1321 ok(ret, "SetConsoleActiveScreenBuffer failed: %lu\n", GetLastError());
1323 CloseHandle(unbound_input);
1324 CloseHandle(unbound_output);
1325 CloseHandle(output);
1328 static void test_GetSetConsoleInputExeName(void)
1330 BOOL ret;
1331 DWORD error;
1332 char buffer[MAX_PATH], module[MAX_PATH], *p;
1333 static char input_exe[MAX_PATH] = "winetest.exe";
1335 SetLastError(0xdeadbeef);
1336 ret = pGetConsoleInputExeNameA(0, NULL);
1337 error = GetLastError();
1338 ok(ret, "GetConsoleInputExeNameA failed\n");
1339 ok(error == ERROR_BUFFER_OVERFLOW, "got %lu expected ERROR_BUFFER_OVERFLOW\n", error);
1341 SetLastError(0xdeadbeef);
1342 ret = pGetConsoleInputExeNameA(0, buffer);
1343 error = GetLastError();
1344 ok(ret, "GetConsoleInputExeNameA failed\n");
1345 ok(error == ERROR_BUFFER_OVERFLOW, "got %lu expected ERROR_BUFFER_OVERFLOW\n", error);
1347 GetModuleFileNameA(GetModuleHandleA(NULL), module, sizeof(module));
1348 p = strrchr(module, '\\') + 1;
1350 ret = pGetConsoleInputExeNameA(ARRAY_SIZE(buffer), buffer);
1351 ok(ret, "GetConsoleInputExeNameA failed\n");
1352 todo_wine ok(!lstrcmpA(buffer, p), "got %s expected %s\n", buffer, p);
1354 SetLastError(0xdeadbeef);
1355 ret = pSetConsoleInputExeNameA(NULL);
1356 error = GetLastError();
1357 ok(!ret, "SetConsoleInputExeNameA failed\n");
1358 ok(error == ERROR_INVALID_PARAMETER, "got %lu expected ERROR_INVALID_PARAMETER\n", error);
1360 SetLastError(0xdeadbeef);
1361 ret = pSetConsoleInputExeNameA("");
1362 error = GetLastError();
1363 ok(!ret, "SetConsoleInputExeNameA failed\n");
1364 ok(error == ERROR_INVALID_PARAMETER, "got %lu expected ERROR_INVALID_PARAMETER\n", error);
1366 ret = pSetConsoleInputExeNameA(input_exe);
1367 ok(ret, "SetConsoleInputExeNameA failed\n");
1369 ret = pGetConsoleInputExeNameA(ARRAY_SIZE(buffer), buffer);
1370 ok(ret, "GetConsoleInputExeNameA failed\n");
1371 ok(!lstrcmpA(buffer, input_exe), "got %s expected %s\n", buffer, input_exe);
1374 static void test_GetConsoleProcessList(void)
1376 DWORD ret, *list = NULL;
1378 if (!pGetConsoleProcessList)
1380 win_skip("GetConsoleProcessList is not available\n");
1381 return;
1384 SetLastError(0xdeadbeef);
1385 ret = pGetConsoleProcessList(NULL, 0);
1386 ok(ret == 0, "Expected failure\n");
1387 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1388 "Expected ERROR_INVALID_PARAMETER, got %ld\n",
1389 GetLastError());
1391 SetLastError(0xdeadbeef);
1392 ret = pGetConsoleProcessList(NULL, 1);
1393 ok(ret == 0, "Expected failure\n");
1394 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1395 "Expected ERROR_INVALID_PARAMETER, got %ld\n",
1396 GetLastError());
1398 /* We should only have 1 process but only for these specific unit tests as
1399 * we created our own console. An AttachConsole(ATTACH_PARENT_PROCESS)
1400 * gives us two processes - see test_AttachConsole.
1402 list = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD));
1404 SetLastError(0xdeadbeef);
1405 ret = pGetConsoleProcessList(list, 0);
1406 ok(ret == 0, "Expected failure\n");
1407 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1408 "Expected ERROR_INVALID_PARAMETER, got %ld\n",
1409 GetLastError());
1411 SetLastError(0xdeadbeef);
1412 ret = pGetConsoleProcessList(list, 1);
1413 ok(ret == 1, "Expected 1, got %ld\n", ret);
1415 HeapFree(GetProcessHeap(), 0, list);
1417 list = HeapAlloc(GetProcessHeap(), 0, ret * sizeof(DWORD));
1419 SetLastError(0xdeadbeef);
1420 ret = pGetConsoleProcessList(list, ret);
1421 ok(ret == 1, "Expected 1, got %ld\n", ret);
1423 if (ret == 1)
1425 DWORD pid = GetCurrentProcessId();
1426 ok(list[0] == pid, "Expected %ld, got %ld\n", pid, list[0]);
1429 HeapFree(GetProcessHeap(), 0, list);
1432 static void test_OpenCON(void)
1434 static const WCHAR conW[] = {'C','O','N',0};
1435 static const DWORD accesses[] = {CREATE_NEW, CREATE_ALWAYS, OPEN_EXISTING,
1436 OPEN_ALWAYS, TRUNCATE_EXISTING};
1437 unsigned i;
1438 HANDLE h;
1440 for (i = 0; i < ARRAY_SIZE(accesses); i++)
1442 h = CreateFileW(conW, GENERIC_WRITE, 0, NULL, accesses[i], 0, NULL);
1443 ok(h != INVALID_HANDLE_VALUE || broken(accesses[i] == TRUNCATE_EXISTING /* Win8 */),
1444 "Expected to open the CON device on write (%lx)\n", accesses[i]);
1445 CloseHandle(h);
1447 h = CreateFileW(conW, GENERIC_READ, 0, NULL, accesses[i], 0, NULL);
1448 /* Windows versions differ here:
1449 * MSDN states in CreateFile that TRUNCATE_EXISTING requires GENERIC_WRITE
1450 * NT, XP, Vista comply, but Win7 doesn't and allows opening CON with TRUNCATE_EXISTING
1451 * So don't test when disposition is TRUNCATE_EXISTING
1453 ok(h != INVALID_HANDLE_VALUE || broken(accesses[i] == TRUNCATE_EXISTING /* Win7+ */),
1454 "Expected to open the CON device on read (%lx)\n", accesses[i]);
1455 CloseHandle(h);
1456 h = CreateFileW(conW, GENERIC_READ|GENERIC_WRITE, 0, NULL, accesses[i], 0, NULL);
1457 ok(h == INVALID_HANDLE_VALUE, "Expected not to open the CON device on read-write (%lx)\n", accesses[i]);
1458 ok(GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_INVALID_PARAMETER,
1459 "Unexpected error %lx\n", GetLastError());
1463 static void test_OpenConsoleW(void)
1465 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
1466 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
1467 static const WCHAR emptyW[] = {0};
1468 static const WCHAR invalidW[] = {'I','N','V','A','L','I','D',0};
1469 DWORD gle;
1471 static const struct
1473 LPCWSTR name;
1474 DWORD access;
1475 BOOL inherit;
1476 DWORD creation;
1477 DWORD gle, gle2;
1478 } invalid_table[] = {
1479 {NULL, 0, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1480 {NULL, 0, FALSE, 0xdeadbeef, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1481 {NULL, 0xdeadbeef, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1482 {NULL, 0xdeadbeef, TRUE, 0xdeadbeef, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1483 {NULL, 0, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1484 {NULL, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1485 {NULL, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1486 {NULL, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1487 {emptyW, 0, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1488 {emptyW, 0, FALSE, 0xdeadbeef, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1489 {emptyW, 0xdeadbeef, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1490 {emptyW, 0xdeadbeef, TRUE, 0xdeadbeef, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1491 {emptyW, 0, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1492 {emptyW, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1493 {emptyW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1494 {emptyW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1495 {invalidW, 0, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1496 {invalidW, 0, FALSE, 0xdeadbeef, ERROR_INVALID_PARAMETER, 0},
1497 {invalidW, 0xdeadbeef, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1498 {invalidW, 0xdeadbeef, TRUE, 0xdeadbeef, ERROR_INVALID_PARAMETER, 0},
1499 {invalidW, 0, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1500 {invalidW, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1501 {invalidW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1502 {invalidW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING, ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1503 {coninW, 0, FALSE, 0xdeadbeef, ERROR_INVALID_PARAMETER, 0},
1504 {coninW, 0xdeadbeef, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_ACCESS_DENIED},
1505 {coninW, 0xdeadbeef, TRUE, 0xdeadbeef, ERROR_INVALID_PARAMETER, 0},
1506 {conoutW, 0, FALSE, 0xdeadbeef, ERROR_INVALID_PARAMETER, 0},
1507 {conoutW, 0xceadbeef, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_ACCESS_DENIED},
1508 {conoutW, 0xdeadbeef, TRUE, 0xdeadbeef, ERROR_INVALID_PARAMETER, 0},
1510 static const struct
1512 LPCWSTR name;
1513 DWORD access;
1514 BOOL inherit;
1515 DWORD creation;
1516 } valid_table[] = {
1517 {coninW, 0, FALSE, 0 },
1518 {coninW, 0, TRUE, 0 },
1519 {coninW, GENERIC_EXECUTE, TRUE, 0 },
1520 {coninW, GENERIC_ALL, TRUE, 0 },
1521 {coninW, 0, FALSE, OPEN_ALWAYS },
1522 {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, 0 },
1523 {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_NEW },
1524 {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_ALWAYS },
1525 {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS },
1526 {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, TRUNCATE_EXISTING},
1527 {conoutW, 0, FALSE, 0 },
1528 {conoutW, 0, FALSE, OPEN_ALWAYS },
1529 {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, 0 },
1530 {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_NEW, },
1531 {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_ALWAYS },
1532 {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS },
1533 {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, TRUNCATE_EXISTING},
1536 int index;
1537 HANDLE ret;
1539 if (!pOpenConsoleW)
1541 win_skip("OpenConsoleW is not available\n");
1542 return;
1545 for (index = 0; index < ARRAY_SIZE(invalid_table); index++)
1547 SetLastError(0xdeadbeef);
1548 ret = pOpenConsoleW(invalid_table[index].name, invalid_table[index].access,
1549 invalid_table[index].inherit, invalid_table[index].creation);
1550 gle = GetLastError();
1551 ok(ret == INVALID_HANDLE_VALUE,
1552 "Expected OpenConsoleW to return INVALID_HANDLE_VALUE for index %d, got %p\n",
1553 index, ret);
1554 ok(gle == invalid_table[index].gle || (gle != 0 && gle == invalid_table[index].gle2),
1555 "Expected GetLastError() to return %lu/%lu for index %d, got %lu\n",
1556 invalid_table[index].gle, invalid_table[index].gle2, index, gle);
1559 for (index = 0; index < ARRAY_SIZE(valid_table); index++)
1561 ret = pOpenConsoleW(valid_table[index].name, valid_table[index].access,
1562 valid_table[index].inherit, valid_table[index].creation);
1563 todo_wine
1564 ok(ret != INVALID_HANDLE_VALUE || broken(ret == INVALID_HANDLE_VALUE /* until Win7 */),
1565 "Expected OpenConsoleW to succeed for index %d, got %p\n", index, ret);
1566 if (ret != INVALID_HANDLE_VALUE)
1567 CloseHandle(ret);
1570 ret = pOpenConsoleW(coninW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING);
1571 ok(ret != INVALID_HANDLE_VALUE, "Expected OpenConsoleW to return a valid handle\n");
1572 if (ret != INVALID_HANDLE_VALUE)
1573 CloseHandle(ret);
1575 ret = pOpenConsoleW(conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING);
1576 ok(ret != INVALID_HANDLE_VALUE, "Expected OpenConsoleW to return a valid handle\n");
1577 if (ret != INVALID_HANDLE_VALUE)
1578 CloseHandle(ret);
1581 static void test_CreateFileW(void)
1583 static const struct
1585 BOOL input;
1586 DWORD access;
1587 BOOL inherit;
1588 DWORD creation;
1589 DWORD gle;
1590 BOOL is_broken;
1591 } cf_table[] = {
1592 {TRUE, 0, FALSE, OPEN_ALWAYS, 0, FALSE},
1593 {TRUE, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_INVALID_PARAMETER, TRUE},
1594 {TRUE, 0, FALSE, 0, ERROR_INVALID_PARAMETER, TRUE},
1595 {TRUE, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_NEW, 0, FALSE},
1596 {TRUE, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_ALWAYS, 0, FALSE},
1597 {TRUE, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, 0, FALSE},
1598 {FALSE, 0, FALSE, 0, ERROR_INVALID_PARAMETER, TRUE},
1599 {FALSE, 0, FALSE, OPEN_ALWAYS, 0, FALSE},
1600 {FALSE, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_INVALID_PARAMETER, TRUE},
1601 {FALSE, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_NEW, 0, FALSE},
1602 {FALSE, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_ALWAYS, 0, FALSE},
1603 {FALSE, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, 0, FALSE},
1604 /* TRUNCATE_EXISTING is forbidden starting with Windows 8 */
1607 static const UINT nt_disposition[5] =
1609 FILE_CREATE, /* CREATE_NEW */
1610 FILE_OVERWRITE_IF, /* CREATE_ALWAYS */
1611 FILE_OPEN, /* OPEN_EXISTING */
1612 FILE_OPEN_IF, /* OPEN_ALWAYS */
1613 FILE_OVERWRITE /* TRUNCATE_EXISTING */
1616 int index;
1617 HANDLE ret;
1618 SECURITY_ATTRIBUTES sa;
1619 OBJECT_ATTRIBUTES attr = {sizeof(attr)};
1620 UNICODE_STRING string;
1621 IO_STATUS_BLOCK iosb;
1622 NTSTATUS status;
1624 for (index = 0; index < ARRAY_SIZE(cf_table); index++)
1626 SetLastError(0xdeadbeef);
1628 sa.nLength = sizeof(sa);
1629 sa.lpSecurityDescriptor = NULL;
1630 sa.bInheritHandle = cf_table[index].inherit;
1632 ret = CreateFileW(cf_table[index].input ? L"CONIN$" : L"CONOUT$", cf_table[index].access,
1633 FILE_SHARE_READ|FILE_SHARE_WRITE, &sa,
1634 cf_table[index].creation, FILE_ATTRIBUTE_NORMAL, NULL);
1635 if (ret == INVALID_HANDLE_VALUE)
1637 ok(cf_table[index].gle,
1638 "Expected CreateFileW not to return INVALID_HANDLE_VALUE for index %d\n", index);
1639 ok(GetLastError() == cf_table[index].gle,
1640 "Expected GetLastError() to return %lu for index %d, got %lu\n",
1641 cf_table[index].gle, index, GetLastError());
1643 else
1645 ok(!cf_table[index].gle || broken(cf_table[index].is_broken) /* Win7 */,
1646 "Expected CreateFileW to succeed for index %d\n", index);
1647 CloseHandle(ret);
1650 if (skip_nt) continue;
1652 SetLastError(0xdeadbeef);
1654 sa.nLength = sizeof(sa);
1655 sa.lpSecurityDescriptor = NULL;
1656 sa.bInheritHandle = cf_table[index].inherit;
1658 ret = CreateFileW(cf_table[index].input ? L"\\??\\CONIN$" : L"\\??\\CONOUT$", cf_table[index].access,
1659 FILE_SHARE_READ|FILE_SHARE_WRITE, &sa,
1660 cf_table[index].creation, FILE_ATTRIBUTE_NORMAL, NULL);
1661 if (cf_table[index].gle)
1662 ok(ret == INVALID_HANDLE_VALUE && GetLastError() == cf_table[index].gle,
1663 "CreateFileW to returned %p %lu for index %d\n", ret, GetLastError(), index);
1664 else
1665 ok(ret != INVALID_HANDLE_VALUE && (!cf_table[index].gle || broken(cf_table[index].is_broken) /* Win7 */),
1666 "CreateFileW to returned %p %lu for index %d\n", ret, GetLastError(), index);
1667 if (ret != INVALID_HANDLE_VALUE) CloseHandle(ret);
1669 if (cf_table[index].gle) continue;
1671 RtlInitUnicodeString(&string, cf_table[index].input
1672 ? L"\\Device\\ConDrv\\CurrentIn" : L"\\Device\\ConDrv\\CurrentOut");
1673 attr.ObjectName = &string;
1674 status = NtCreateFile(&ret, cf_table[index].access | SYNCHRONIZE | FILE_READ_ATTRIBUTES, &attr, &iosb, NULL,
1675 FILE_ATTRIBUTE_NORMAL, 0, nt_disposition[cf_table[index].creation - CREATE_NEW],
1676 FILE_NON_DIRECTORY_FILE, NULL, 0);
1677 ok(!status, "NtCreateFile failed %lx for %u\n", status, index);
1678 CloseHandle(ret);
1680 RtlInitUnicodeString(&string, cf_table[index].input ? L"\\??\\CONIN$" : L"\\??\\CONOUT$");
1681 attr.ObjectName = &string;
1682 status = NtCreateFile(&ret, cf_table[index].access | SYNCHRONIZE | FILE_READ_ATTRIBUTES, &attr, &iosb, NULL,
1683 FILE_ATTRIBUTE_NORMAL, 0, nt_disposition[cf_table[index].creation - CREATE_NEW],
1684 FILE_NON_DIRECTORY_FILE, NULL, 0);
1685 ok(!status, "NtCreateFile failed %lx for %u\n", status, index);
1686 CloseHandle(ret);
1690 static void test_VerifyConsoleIoHandle( HANDLE handle )
1692 BOOL ret;
1693 DWORD error;
1695 if (!pVerifyConsoleIoHandle)
1697 win_skip("VerifyConsoleIoHandle is not available\n");
1698 return;
1701 /* invalid handle */
1702 SetLastError(0xdeadbeef);
1703 ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee0);
1704 error = GetLastError();
1705 ok(!ret, "expected VerifyConsoleIoHandle to fail\n");
1706 ok(error == 0xdeadbeef, "wrong GetLastError() %ld\n", error);
1708 /* invalid handle + 1 */
1709 SetLastError(0xdeadbeef);
1710 ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee1);
1711 error = GetLastError();
1712 ok(!ret, "expected VerifyConsoleIoHandle to fail\n");
1713 ok(error == 0xdeadbeef, "wrong GetLastError() %ld\n", error);
1715 /* invalid handle + 2 */
1716 SetLastError(0xdeadbeef);
1717 ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee2);
1718 error = GetLastError();
1719 ok(!ret, "expected VerifyConsoleIoHandle to fail\n");
1720 ok(error == 0xdeadbeef, "wrong GetLastError() %ld\n", error);
1722 /* invalid handle + 3 */
1723 SetLastError(0xdeadbeef);
1724 ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee3);
1725 error = GetLastError();
1726 ok(!ret, "expected VerifyConsoleIoHandle to fail\n");
1727 ok(error == 0xdeadbeef, "wrong GetLastError() %ld\n", error);
1729 /* valid handle */
1730 SetLastError(0xdeadbeef);
1731 ret = pVerifyConsoleIoHandle(handle);
1732 error = GetLastError();
1733 ok(ret ||
1734 broken(!ret), /* Windows 8 and 10 */
1735 "expected VerifyConsoleIoHandle to succeed\n");
1736 ok(error == 0xdeadbeef, "wrong GetLastError() %ld\n", error);
1739 static void test_GetSetStdHandle(void)
1741 HANDLE handle;
1742 DWORD error;
1743 BOOL ret;
1745 /* get invalid std handle */
1746 SetLastError(0xdeadbeef);
1747 handle = GetStdHandle(42);
1748 error = GetLastError();
1749 ok(error == ERROR_INVALID_HANDLE || broken(error == ERROR_INVALID_FUNCTION)/* Win9x */,
1750 "wrong GetLastError() %ld\n", error);
1751 ok(handle == INVALID_HANDLE_VALUE, "expected INVALID_HANDLE_VALUE\n");
1753 /* get valid */
1754 SetLastError(0xdeadbeef);
1755 handle = GetStdHandle(STD_INPUT_HANDLE);
1756 error = GetLastError();
1757 ok(error == 0xdeadbeef, "wrong GetLastError() %ld\n", error);
1759 /* set invalid std handle */
1760 SetLastError(0xdeadbeef);
1761 ret = SetStdHandle(42, handle);
1762 error = GetLastError();
1763 ok(!ret, "expected SetStdHandle to fail\n");
1764 ok(error == ERROR_INVALID_HANDLE || broken(error == ERROR_INVALID_FUNCTION)/* Win9x */,
1765 "wrong GetLastError() %ld\n", error);
1767 /* set valid (restore old value) */
1768 SetLastError(0xdeadbeef);
1769 ret = SetStdHandle(STD_INPUT_HANDLE, handle);
1770 error = GetLastError();
1771 ok(ret, "expected SetStdHandle to succeed\n");
1772 ok(error == 0xdeadbeef, "wrong GetLastError() %ld\n", error);
1775 static void test_DuplicateConsoleHandle(void)
1777 HANDLE handle, event;
1778 BOOL ret;
1780 if (skip_nt) return;
1782 event = CreateEventW(NULL, TRUE, FALSE, NULL);
1784 /* duplicate an event handle with DuplicateConsoleHandle */
1785 handle = DuplicateConsoleHandle(event, 0, FALSE, DUPLICATE_SAME_ACCESS);
1786 ok(handle != NULL, "DuplicateConsoleHandle failed: %lu\n", GetLastError());
1788 ret = SetEvent(handle);
1789 ok(ret, "SetEvent failed: %lu\n", GetLastError());
1791 ret = CloseConsoleHandle(handle);
1792 ok(ret, "CloseConsoleHandle failed: %lu\n", GetLastError());
1793 ret = CloseConsoleHandle(event);
1794 ok(ret, "CloseConsoleHandle failed: %lu\n", GetLastError());
1796 handle = DuplicateConsoleHandle((HANDLE)0xdeadbeef, 0, FALSE, DUPLICATE_SAME_ACCESS);
1797 ok(handle == INVALID_HANDLE_VALUE, "DuplicateConsoleHandle failed: %lu\n", GetLastError());
1798 ok(GetLastError() == ERROR_INVALID_HANDLE, "last error = %lu\n", GetLastError());
1801 static void test_GetNumberOfConsoleInputEvents(HANDLE input_handle)
1803 DWORD count;
1804 BOOL ret;
1805 int i;
1807 const struct
1809 HANDLE handle;
1810 LPDWORD nrofevents;
1811 DWORD last_error;
1812 } invalid_table[] =
1814 {NULL, NULL, ERROR_INVALID_HANDLE},
1815 {NULL, &count, ERROR_INVALID_HANDLE},
1816 {INVALID_HANDLE_VALUE, NULL, ERROR_INVALID_HANDLE},
1817 {INVALID_HANDLE_VALUE, &count, ERROR_INVALID_HANDLE},
1820 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
1822 SetLastError(0xdeadbeef);
1823 if (invalid_table[i].nrofevents) count = 0xdeadbeef;
1824 ret = GetNumberOfConsoleInputEvents(invalid_table[i].handle,
1825 invalid_table[i].nrofevents);
1826 ok(!ret, "[%d] Expected GetNumberOfConsoleInputEvents to return FALSE, got %d\n", i, ret);
1827 if (invalid_table[i].nrofevents)
1829 ok(count == 0xdeadbeef,
1830 "[%d] Expected output count to be unmodified, got %lu\n", i, count);
1832 ok(GetLastError() == invalid_table[i].last_error,
1833 "[%d] Expected last error to be %lu, got %lu\n",
1834 i, invalid_table[i].last_error, GetLastError());
1837 /* Test crashes on Windows 7. */
1838 if (0)
1840 SetLastError(0xdeadbeef);
1841 ret = GetNumberOfConsoleInputEvents(input_handle, NULL);
1842 ok(!ret, "Expected GetNumberOfConsoleInputEvents to return FALSE, got %d\n", ret);
1843 ok(GetLastError() == ERROR_INVALID_ACCESS,
1844 "Expected last error to be ERROR_INVALID_ACCESS, got %lu\n",
1845 GetLastError());
1848 count = 0xdeadbeef;
1849 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1850 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1851 ok(count != 0xdeadbeef, "Expected output count to initialized\n");
1854 static void test_WriteConsoleInputA(HANDLE input_handle)
1856 INPUT_RECORD event;
1857 INPUT_RECORD event_list[5];
1858 MOUSE_EVENT_RECORD mouse_event = { {0, 0}, 0, 0, MOUSE_MOVED };
1859 KEY_EVENT_RECORD key_event;
1860 DWORD count, console_mode, gle;
1861 BOOL ret;
1862 int i;
1864 const struct
1866 HANDLE handle;
1867 const INPUT_RECORD *buffer;
1868 DWORD count;
1869 LPDWORD written;
1870 DWORD gle, gle2;
1871 int win_crash;
1872 } invalid_table[] =
1874 {NULL, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1875 {NULL, NULL, 0, &count,ERROR_INVALID_HANDLE},
1876 {NULL, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1877 {NULL, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
1878 {NULL, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1879 {NULL, &event, 0, &count, ERROR_INVALID_HANDLE},
1880 {NULL, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1881 {NULL, &event, 1, &count, ERROR_INVALID_HANDLE},
1882 {INVALID_HANDLE_VALUE, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1883 {INVALID_HANDLE_VALUE, NULL, 0, &count, ERROR_INVALID_HANDLE},
1884 {INVALID_HANDLE_VALUE, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1885 {INVALID_HANDLE_VALUE, NULL, 1, &count, ERROR_INVALID_HANDLE, ERROR_INVALID_ACCESS},
1886 {INVALID_HANDLE_VALUE, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1887 {INVALID_HANDLE_VALUE, &event, 0, &count, ERROR_INVALID_HANDLE},
1888 {INVALID_HANDLE_VALUE, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1889 {INVALID_HANDLE_VALUE, &event, 1, &count, ERROR_INVALID_HANDLE},
1890 {input_handle, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1891 {input_handle, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1892 {input_handle, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
1893 {input_handle, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1894 {input_handle, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1897 /* Suppress external sources of input events for the duration of the test. */
1898 ret = GetConsoleMode(input_handle, &console_mode);
1899 ok(ret == TRUE, "Expected GetConsoleMode to return TRUE, got %d\n", ret);
1900 if (!ret)
1902 skip("GetConsoleMode failed with last error %lu\n", GetLastError());
1903 return;
1906 ret = SetConsoleMode(input_handle, console_mode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
1907 ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret);
1908 if (!ret)
1910 skip("SetConsoleMode failed with last error %lu\n", GetLastError());
1911 return;
1914 /* Discard any events queued before the tests. */
1915 ret = FlushConsoleInputBuffer(input_handle);
1916 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1918 event.EventType = MOUSE_EVENT;
1919 event.Event.MouseEvent = mouse_event;
1921 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
1923 if (invalid_table[i].win_crash)
1924 continue;
1926 SetLastError(0xdeadbeef);
1927 if (invalid_table[i].written) count = 0xdeadbeef;
1928 ret = WriteConsoleInputA(invalid_table[i].handle,
1929 invalid_table[i].buffer,
1930 invalid_table[i].count,
1931 invalid_table[i].written);
1932 ok(!ret, "[%d] Expected WriteConsoleInputA to return FALSE, got %d\n", i, ret);
1933 gle = GetLastError();
1934 ok(gle == invalid_table[i].gle || (gle != 0 && gle == invalid_table[i].gle2),
1935 "[%d] Expected last error to be %lu or %lu, got %lu\n",
1936 i, invalid_table[i].gle, invalid_table[i].gle2, gle);
1939 count = 0xdeadbeef;
1940 ret = WriteConsoleInputA(input_handle, NULL, 0, &count);
1941 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1942 ok(count == 0, "Expected count to be 0, got %lu\n", count);
1944 count = 0xdeadbeef;
1945 ret = WriteConsoleInputA(input_handle, &event, 0, &count);
1946 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1947 ok(count == 0, "Expected count to be 0, got %lu\n", count);
1949 count = 0xdeadbeef;
1950 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1951 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1952 ok(count == 1, "Expected count to be 1, got %lu\n", count);
1954 ret = FlushConsoleInputBuffer(input_handle);
1955 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1957 /* Writing a single mouse event doesn't seem to affect the count if an adjacent mouse event is already queued. */
1958 event.EventType = MOUSE_EVENT;
1959 event.Event.MouseEvent = mouse_event;
1961 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1962 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1963 ok(count == 1, "Expected count to be 1, got %lu\n", count);
1965 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1966 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1967 ok(count == 1, "Expected count to be 1, got %lu\n", count);
1969 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1970 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1971 ok(count == 1, "Expected count to be 1, got %lu\n", count);
1973 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1974 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1975 todo_wine
1976 ok(count == 1, "Expected count to be 1, got %lu\n", count);
1978 ret = FlushConsoleInputBuffer(input_handle);
1979 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1981 for (i = 0; i < ARRAY_SIZE(event_list); i++)
1983 event_list[i].EventType = MOUSE_EVENT;
1984 event_list[i].Event.MouseEvent = mouse_event;
1987 /* Writing consecutive chunks of mouse events appears to work. */
1988 ret = WriteConsoleInputA(input_handle, event_list, ARRAY_SIZE(event_list), &count);
1989 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1990 ok(count == ARRAY_SIZE(event_list),
1991 "Expected count to be event list length, got %lu\n", count);
1993 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1994 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1995 ok(count == ARRAY_SIZE(event_list),
1996 "Expected count to be event list length, got %lu\n", count);
1998 ret = WriteConsoleInputA(input_handle, event_list, ARRAY_SIZE(event_list), &count);
1999 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
2000 ok(count == ARRAY_SIZE(event_list),
2001 "Expected count to be event list length, got %lu\n", count);
2003 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2004 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2005 ok(count == 2*ARRAY_SIZE(event_list),
2006 "Expected count to be twice event list length, got %lu\n", count);
2008 /* Again, writing a single mouse event with adjacent mouse events queued doesn't appear to affect the count. */
2009 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
2010 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
2011 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2013 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2014 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2015 todo_wine
2016 ok(count == 2*ARRAY_SIZE(event_list),
2017 "Expected count to be twice event list length, got %lu\n", count);
2019 ret = FlushConsoleInputBuffer(input_handle);
2020 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
2022 key_event.bKeyDown = FALSE;
2023 key_event.wRepeatCount = 0;
2024 key_event.wVirtualKeyCode = VK_SPACE;
2025 key_event.wVirtualScanCode = VK_SPACE;
2026 key_event.uChar.AsciiChar = ' ';
2027 key_event.dwControlKeyState = 0;
2029 event.EventType = KEY_EVENT;
2030 event.Event.KeyEvent = key_event;
2032 /* Key events don't exhibit the same behavior as mouse events. */
2033 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
2034 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
2035 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2037 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2038 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2039 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2041 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
2042 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
2043 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2045 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2046 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2047 ok(count == 2, "Expected count to be 2, got %lu\n", count);
2049 ret = FlushConsoleInputBuffer(input_handle);
2050 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
2052 /* Try interleaving mouse and key events. */
2053 event.EventType = MOUSE_EVENT;
2054 event.Event.MouseEvent = mouse_event;
2056 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
2057 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
2058 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2060 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2061 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2062 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2064 event.EventType = KEY_EVENT;
2065 event.Event.KeyEvent = key_event;
2067 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
2068 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
2069 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2071 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2072 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2073 ok(count == 2, "Expected count to be 2, got %lu\n", count);
2075 event.EventType = MOUSE_EVENT;
2076 event.Event.MouseEvent = mouse_event;
2078 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
2079 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
2080 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2082 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2083 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2084 ok(count == 3, "Expected count to be 3, got %lu\n", count);
2086 /* Restore the old console mode. */
2087 ret = SetConsoleMode(input_handle, console_mode);
2088 ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret);
2091 static void test_WriteConsoleInputW(HANDLE input_handle)
2093 INPUT_RECORD event;
2094 INPUT_RECORD event_list[5];
2095 MOUSE_EVENT_RECORD mouse_event = { {0, 0}, 0, 0, MOUSE_MOVED };
2096 KEY_EVENT_RECORD key_event;
2097 DWORD count, console_mode, gle;
2098 BOOL ret;
2099 int i;
2101 const struct
2103 HANDLE handle;
2104 const INPUT_RECORD *buffer;
2105 DWORD count;
2106 LPDWORD written;
2107 DWORD gle, gle2;
2108 int win_crash;
2109 } invalid_table[] =
2111 {NULL, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
2112 {NULL, NULL, 0, &count, ERROR_INVALID_HANDLE},
2113 {NULL, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
2114 {NULL, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
2115 {NULL, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
2116 {NULL, &event, 0, &count, ERROR_INVALID_HANDLE},
2117 {NULL, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
2118 {NULL, &event, 1, &count, ERROR_INVALID_HANDLE},
2119 {INVALID_HANDLE_VALUE, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
2120 {INVALID_HANDLE_VALUE, NULL, 0, &count, ERROR_INVALID_HANDLE},
2121 {INVALID_HANDLE_VALUE, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
2122 {INVALID_HANDLE_VALUE, NULL, 1, &count, ERROR_INVALID_HANDLE, ERROR_INVALID_ACCESS},
2123 {INVALID_HANDLE_VALUE, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
2124 {INVALID_HANDLE_VALUE, &event, 0, &count, ERROR_INVALID_HANDLE},
2125 {INVALID_HANDLE_VALUE, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
2126 {INVALID_HANDLE_VALUE, &event, 1, &count, ERROR_INVALID_HANDLE},
2127 {input_handle, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
2128 {input_handle, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
2129 {input_handle, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
2130 {input_handle, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
2131 {input_handle, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
2134 /* Suppress external sources of input events for the duration of the test. */
2135 ret = GetConsoleMode(input_handle, &console_mode);
2136 ok(ret == TRUE, "Expected GetConsoleMode to return TRUE, got %d\n", ret);
2137 if (!ret)
2139 skip("GetConsoleMode failed with last error %lu\n", GetLastError());
2140 return;
2143 ret = SetConsoleMode(input_handle, console_mode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
2144 ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret);
2145 if (!ret)
2147 skip("SetConsoleMode failed with last error %lu\n", GetLastError());
2148 return;
2151 /* Discard any events queued before the tests. */
2152 ret = FlushConsoleInputBuffer(input_handle);
2153 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
2155 event.EventType = MOUSE_EVENT;
2156 event.Event.MouseEvent = mouse_event;
2158 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2160 if (invalid_table[i].win_crash)
2161 continue;
2163 SetLastError(0xdeadbeef);
2164 if (invalid_table[i].written) count = 0xdeadbeef;
2165 ret = WriteConsoleInputW(invalid_table[i].handle,
2166 invalid_table[i].buffer,
2167 invalid_table[i].count,
2168 invalid_table[i].written);
2169 ok(!ret, "[%d] Expected WriteConsoleInputW to return FALSE, got %d\n", i, ret);
2170 gle = GetLastError();
2171 ok(gle == invalid_table[i].gle || (gle != 0 && gle == invalid_table[i].gle2),
2172 "[%d] Expected last error to be %lu or %lu, got %lu\n",
2173 i, invalid_table[i].gle, invalid_table[i].gle2, gle);
2176 count = 0xdeadbeef;
2177 ret = WriteConsoleInputW(input_handle, NULL, 0, &count);
2178 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2179 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2181 count = 0xdeadbeef;
2182 ret = WriteConsoleInputW(input_handle, &event, 0, &count);
2183 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2184 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2186 count = 0xdeadbeef;
2187 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2188 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2189 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2191 ret = FlushConsoleInputBuffer(input_handle);
2192 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
2194 /* Writing a single mouse event doesn't seem to affect the count if an adjacent mouse event is already queued. */
2195 event.EventType = MOUSE_EVENT;
2196 event.Event.MouseEvent = mouse_event;
2198 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2199 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2200 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2202 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2203 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2204 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2206 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2207 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2208 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2210 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2211 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2212 todo_wine
2213 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2215 ret = FlushConsoleInputBuffer(input_handle);
2216 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
2218 for (i = 0; i < ARRAY_SIZE(event_list); i++)
2220 event_list[i].EventType = MOUSE_EVENT;
2221 event_list[i].Event.MouseEvent = mouse_event;
2224 /* Writing consecutive chunks of mouse events appears to work. */
2225 ret = WriteConsoleInputW(input_handle, event_list, ARRAY_SIZE(event_list), &count);
2226 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2227 ok(count == ARRAY_SIZE(event_list),
2228 "Expected count to be event list length, got %lu\n", count);
2230 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2231 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2232 ok(count == ARRAY_SIZE(event_list),
2233 "Expected count to be event list length, got %lu\n", count);
2235 ret = WriteConsoleInputW(input_handle, event_list, ARRAY_SIZE(event_list), &count);
2236 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2237 ok(count == ARRAY_SIZE(event_list),
2238 "Expected count to be event list length, got %lu\n", count);
2240 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2241 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2242 ok(count == 2*ARRAY_SIZE(event_list),
2243 "Expected count to be twice event list length, got %lu\n", count);
2245 /* Again, writing a single mouse event with adjacent mouse events queued doesn't appear to affect the count. */
2246 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2247 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2248 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2250 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2251 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2252 todo_wine
2253 ok(count == 2*ARRAY_SIZE(event_list),
2254 "Expected count to be twice event list length, got %lu\n", count);
2256 ret = FlushConsoleInputBuffer(input_handle);
2257 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
2259 key_event.bKeyDown = FALSE;
2260 key_event.wRepeatCount = 0;
2261 key_event.wVirtualKeyCode = VK_SPACE;
2262 key_event.wVirtualScanCode = VK_SPACE;
2263 key_event.uChar.UnicodeChar = ' ';
2264 key_event.dwControlKeyState = 0;
2266 event.EventType = KEY_EVENT;
2267 event.Event.KeyEvent = key_event;
2269 /* Key events don't exhibit the same behavior as mouse events. */
2270 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2271 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2272 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2274 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2275 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2276 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2278 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2279 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2280 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2282 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2283 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2284 ok(count == 2, "Expected count to be 2, got %lu\n", count);
2286 ret = FlushConsoleInputBuffer(input_handle);
2287 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
2289 /* Try interleaving mouse and key events. */
2290 event.EventType = MOUSE_EVENT;
2291 event.Event.MouseEvent = mouse_event;
2293 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2294 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2295 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2297 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2298 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2299 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2301 event.EventType = KEY_EVENT;
2302 event.Event.KeyEvent = key_event;
2304 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2305 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2306 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2308 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2309 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2310 ok(count == 2, "Expected count to be 2, got %lu\n", count);
2312 event.EventType = MOUSE_EVENT;
2313 event.Event.MouseEvent = mouse_event;
2315 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2316 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2317 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2319 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2320 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2321 ok(count == 3, "Expected count to be 3, got %lu\n", count);
2323 /* Restore the old console mode. */
2324 ret = SetConsoleMode(input_handle, console_mode);
2325 ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret);
2328 static void test_FlushConsoleInputBuffer(HANDLE input, HANDLE output)
2330 INPUT_RECORD record;
2331 DWORD count;
2332 BOOL ret;
2334 ret = FlushConsoleInputBuffer(input);
2335 ok(ret, "FlushConsoleInputBuffer failed: %lu\n", GetLastError());
2337 ret = GetNumberOfConsoleInputEvents(input, &count);
2338 ok(ret, "GetNumberOfConsoleInputEvents failed: %lu\n", GetLastError());
2339 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2341 record.EventType = KEY_EVENT;
2342 record.Event.KeyEvent.bKeyDown = 1;
2343 record.Event.KeyEvent.wRepeatCount = 1;
2344 record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
2345 record.Event.KeyEvent.wVirtualScanCode = VK_RETURN;
2346 record.Event.KeyEvent.uChar.UnicodeChar = '\r';
2347 record.Event.KeyEvent.dwControlKeyState = 0;
2348 ret = WriteConsoleInputW(input, &record, 1, &count);
2349 ok(ret, "WriteConsoleInputW failed: %lu\n", GetLastError());
2351 ret = GetNumberOfConsoleInputEvents(input, &count);
2352 ok(ret, "GetNumberOfConsoleInputEvents failed: %lu\n", GetLastError());
2353 ok(count == 1, "Expected count to be 0, got %lu\n", count);
2355 ret = FlushConsoleInputBuffer(input);
2356 ok(ret, "FlushConsoleInputBuffer failed: %lu\n", GetLastError());
2358 ret = GetNumberOfConsoleInputEvents(input, &count);
2359 ok(ret, "GetNumberOfConsoleInputEvents failed: %lu\n", GetLastError());
2360 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2362 ret = WriteConsoleInputW(input, &record, 1, &count);
2363 ok(ret, "WriteConsoleInputW failed: %lu\n", GetLastError());
2365 ret = GetNumberOfConsoleInputEvents(input, &count);
2366 ok(ret, "GetNumberOfConsoleInputEvents failed: %lu\n", GetLastError());
2367 ok(count == 1, "Expected count to be 0, got %lu\n", count);
2369 ret = FlushFileBuffers(input);
2370 ok(ret, "FlushFileBuffers failed: %lu\n", GetLastError());
2372 ret = GetNumberOfConsoleInputEvents(input, &count);
2373 ok(ret, "GetNumberOfConsoleInputEvents failed: %lu\n", GetLastError());
2374 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2376 ret = FlushConsoleInputBuffer(output);
2377 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "FlushConsoleInputBuffer returned: %x(%lu)\n",
2378 ret, GetLastError());
2380 ret = FlushFileBuffers(output);
2381 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "FlushFileBuffers returned: %x(%lu)\n",
2382 ret, GetLastError());
2385 static void test_WriteConsoleOutputCharacterA(HANDLE output_handle)
2387 static const char output[] = {'a', 0};
2389 COORD origin = {0, 0};
2390 DWORD count;
2391 BOOL ret;
2392 int i;
2394 const struct
2396 HANDLE hConsoleOutput;
2397 LPCSTR str;
2398 DWORD length;
2399 COORD coord;
2400 LPDWORD lpNumCharsWritten;
2401 DWORD expected_count;
2402 DWORD last_error;
2403 int win7_crash;
2404 } invalid_table[] =
2406 {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2407 {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2408 {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2409 {NULL, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2410 {NULL, output, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2411 {NULL, output, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2412 {NULL, output, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2413 {NULL, output, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2414 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2415 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2416 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2417 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2418 {INVALID_HANDLE_VALUE, output, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2419 {INVALID_HANDLE_VALUE, output, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2420 {INVALID_HANDLE_VALUE, output, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2421 {INVALID_HANDLE_VALUE, output, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2422 {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2423 {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2424 {output_handle, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2425 {output_handle, output, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2426 {output_handle, output, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2429 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2431 if (invalid_table[i].win7_crash)
2432 continue;
2434 SetLastError(0xdeadbeef);
2435 if (invalid_table[i].lpNumCharsWritten) count = 0xdeadbeef;
2436 ret = WriteConsoleOutputCharacterA(invalid_table[i].hConsoleOutput,
2437 invalid_table[i].str,
2438 invalid_table[i].length,
2439 invalid_table[i].coord,
2440 invalid_table[i].lpNumCharsWritten);
2441 ok(!ret, "[%d] Expected WriteConsoleOutputCharacterA to return FALSE, got %d\n", i, ret);
2442 ok(GetLastError() == invalid_table[i].last_error,
2443 "[%d] Expected last error to be %lu, got %lu\n",
2444 i, invalid_table[i].last_error, GetLastError());
2447 count = 0xdeadbeef;
2448 ret = WriteConsoleOutputCharacterA(output_handle, NULL, 0, origin, &count);
2449 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2450 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2452 count = 0xdeadbeef;
2453 ret = WriteConsoleOutputCharacterA(output_handle, output, 0, origin, &count);
2454 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2455 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2457 count = 0xdeadbeef;
2458 ret = WriteConsoleOutputCharacterA(output_handle, output, 1, origin, &count);
2459 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2460 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2462 count = 0xdeadbeef;
2463 origin.X = 200;
2464 ret = WriteConsoleOutputCharacterA(output_handle, output, 0, origin, &count);
2465 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2466 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2468 for (i = 1; i < 32; i++)
2470 CONSOLE_SCREEN_BUFFER_INFO csbi;
2471 char ch = (char)i;
2472 COORD c = {1, 2};
2474 ret = WriteConsoleOutputCharacterA(output_handle, &ch, 1, c, &count);
2475 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2476 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2477 okCHAR(output_handle, c, (char)i, 7);
2478 ret = GetConsoleScreenBufferInfo(output_handle, &csbi);
2482 static void test_WriteConsoleOutputCharacterW(HANDLE output_handle)
2484 static const WCHAR outputW[] = {'a',0};
2486 COORD origin = {0, 0};
2487 DWORD count;
2488 BOOL ret;
2489 int i;
2491 const struct
2493 HANDLE hConsoleOutput;
2494 LPCWSTR str;
2495 DWORD length;
2496 COORD coord;
2497 LPDWORD lpNumCharsWritten;
2498 DWORD expected_count;
2499 DWORD last_error;
2500 int win7_crash;
2501 } invalid_table[] =
2503 {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2504 {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2505 {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2506 {NULL, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2507 {NULL, outputW, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2508 {NULL, outputW, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2509 {NULL, outputW, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2510 {NULL, outputW, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2511 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2512 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2513 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2514 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2515 {INVALID_HANDLE_VALUE, outputW, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2516 {INVALID_HANDLE_VALUE, outputW, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2517 {INVALID_HANDLE_VALUE, outputW, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2518 {INVALID_HANDLE_VALUE, outputW, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2519 {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2520 {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2521 {output_handle, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2522 {output_handle, outputW, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2523 {output_handle, outputW, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2526 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2528 if (invalid_table[i].win7_crash)
2529 continue;
2531 SetLastError(0xdeadbeef);
2532 if (invalid_table[i].lpNumCharsWritten) count = 0xdeadbeef;
2533 ret = WriteConsoleOutputCharacterW(invalid_table[i].hConsoleOutput,
2534 invalid_table[i].str,
2535 invalid_table[i].length,
2536 invalid_table[i].coord,
2537 invalid_table[i].lpNumCharsWritten);
2538 ok(!ret, "[%d] Expected WriteConsoleOutputCharacterW to return FALSE, got %d\n", i, ret);
2539 ok(GetLastError() == invalid_table[i].last_error,
2540 "[%d] Expected last error to be %lu, got %lu\n",
2541 i, invalid_table[i].last_error, GetLastError());
2544 count = 0xdeadbeef;
2545 ret = WriteConsoleOutputCharacterW(output_handle, NULL, 0, origin, &count);
2546 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2547 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2549 count = 0xdeadbeef;
2550 ret = WriteConsoleOutputCharacterW(output_handle, outputW, 0, origin, &count);
2551 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2552 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2554 count = 0xdeadbeef;
2555 ret = WriteConsoleOutputCharacterW(output_handle, outputW, 1, origin, &count);
2556 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2557 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2559 count = 0xdeadbeef;
2560 origin.X = 200;
2561 ret = WriteConsoleOutputCharacterW(output_handle, outputW, 0, origin, &count);
2562 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2563 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2567 static void test_WriteConsoleOutputAttribute(HANDLE output_handle)
2569 WORD attr = FOREGROUND_BLUE;
2570 COORD origin = {0, 0};
2571 DWORD count;
2572 BOOL ret;
2573 int i;
2575 const struct
2577 HANDLE hConsoleOutput;
2578 const WORD *attr;
2579 DWORD length;
2580 COORD coord;
2581 LPDWORD lpNumAttrsWritten;
2582 DWORD expected_count;
2583 DWORD last_error;
2584 int win7_crash;
2585 } invalid_table[] =
2587 {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2588 {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2589 {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2590 {NULL, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2591 {NULL, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2592 {NULL, &attr, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2593 {NULL, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2594 {NULL, &attr, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2595 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2596 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2597 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2598 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2599 {INVALID_HANDLE_VALUE, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2600 {INVALID_HANDLE_VALUE, &attr, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2601 {INVALID_HANDLE_VALUE, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2602 {INVALID_HANDLE_VALUE, &attr, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2603 {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2604 {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2605 {output_handle, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2606 {output_handle, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2607 {output_handle, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2610 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2612 if (invalid_table[i].win7_crash)
2613 continue;
2615 SetLastError(0xdeadbeef);
2616 if (invalid_table[i].lpNumAttrsWritten) count = 0xdeadbeef;
2617 ret = WriteConsoleOutputAttribute(invalid_table[i].hConsoleOutput,
2618 invalid_table[i].attr,
2619 invalid_table[i].length,
2620 invalid_table[i].coord,
2621 invalid_table[i].lpNumAttrsWritten);
2622 ok(!ret, "[%d] Expected WriteConsoleOutputAttribute to return FALSE, got %d\n", i, ret);
2623 ok(GetLastError() == invalid_table[i].last_error,
2624 "[%d] Expected last error to be %lu, got %lu\n",
2625 i, invalid_table[i].last_error, GetLastError());
2628 count = 0xdeadbeef;
2629 ret = WriteConsoleOutputAttribute(output_handle, NULL, 0, origin, &count);
2630 ok(ret == TRUE, "Expected WriteConsoleOutputAttribute to return TRUE, got %d\n", ret);
2631 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2633 count = 0xdeadbeef;
2634 ret = WriteConsoleOutputAttribute(output_handle, &attr, 0, origin, &count);
2635 ok(ret == TRUE, "Expected WriteConsoleOutputAttribute to return TRUE, got %d\n", ret);
2636 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2638 count = 0xdeadbeef;
2639 ret = WriteConsoleOutputAttribute(output_handle, &attr, 1, origin, &count);
2640 ok(ret == TRUE, "Expected WriteConsoleOutputAttribute to return TRUE, got %d\n", ret);
2641 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2643 count = 0xdeadbeef;
2644 origin.X = 200;
2645 ret = WriteConsoleOutputAttribute(output_handle, &attr, 0, origin, &count);
2646 ok(ret == TRUE, "Expected WriteConsoleOutputAttribute to return TRUE, got %d\n", ret);
2647 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2650 static void set_region(SMALL_RECT *region, unsigned int left, unsigned int top, unsigned int right, unsigned int bottom)
2652 region->Left = left;
2653 region->Top = top;
2654 region->Right = right;
2655 region->Bottom = bottom;
2658 #define check_region(a,b,c,d,e) check_region_(__LINE__,a,b,c,d,e)
2659 static void check_region_(unsigned int line, const SMALL_RECT *region, unsigned int left, unsigned int top, int right, int bottom)
2661 ok_(__FILE__,line)(region->Left == left, "Left = %u, expected %u\n", region->Left, left);
2662 ok_(__FILE__,line)(region->Top == top, "Top = %u, expected %u\n", region->Top, top);
2663 /* In multiple places returned region depends on Windows versions: some return right < left, others leave it untouched */
2664 if (right >= 0)
2665 ok_(__FILE__,line)(region->Right == right, "Right = %u, expected %u\n", region->Right, right);
2666 else
2667 ok_(__FILE__,line)(region->Right == -right || region->Right == region->Left - 1,
2668 "Right = %u, expected %d\n", region->Right, right);
2669 if (bottom > 0)
2670 ok_(__FILE__,line)(region->Bottom == bottom, "Bottom = %u, expected %u\n", region->Bottom, bottom);
2671 else if (bottom < 0)
2672 ok_(__FILE__,line)(region->Bottom == -bottom || region->Bottom == region->Top - 1,
2673 "Bottom = %u, expected %d\n", region->Bottom, bottom);
2676 static void test_WriteConsoleOutput(HANDLE console)
2678 CONSOLE_SCREEN_BUFFER_INFO info;
2679 CHAR_INFO char_info_buf[2048];
2680 SMALL_RECT region;
2681 COORD size, coord;
2682 unsigned int i;
2683 BOOL ret;
2685 for (i = 0; i < ARRAY_SIZE(char_info_buf); i++)
2687 char_info_buf[i].Char.UnicodeChar = '0' + i % 10;
2688 char_info_buf[i].Attributes = 0;
2691 ret = GetConsoleScreenBufferInfo(console, &info);
2692 ok(ret, "GetConsoleScreenBufferInfo failed: %lu\n", GetLastError());
2694 size.X = 23;
2695 size.Y = 17;
2696 coord.X = 2;
2697 coord.Y = 3;
2698 set_region(&region, 10, 7, 15, 11);
2699 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region);
2700 ok(ret, "WriteConsoleOutputW failed: %lu\n", GetLastError());
2701 check_region(&region, 10, 7, 15, 11);
2703 size.X = 23;
2704 size.Y = 17;
2705 coord.X = 2;
2706 coord.Y = 3;
2707 set_region(&region, 200, 7, 15, 211);
2708 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region);
2709 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
2710 check_region(&region, 200, 7, 15, 211);
2712 size.X = 23;
2713 size.Y = 17;
2714 coord.X = 2;
2715 coord.Y = 3;
2716 set_region(&region, 200, 7, 211, 8);
2717 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region);
2718 ok(ret, "WriteConsoleOutputW failed: %lu\n", GetLastError());
2719 check_region(&region, 200, 7, 211, 8);
2721 size.X = 23;
2722 size.Y = 17;
2723 coord.X = 2;
2724 coord.Y = 3;
2725 set_region(&region, 10, 7, 9, 11);
2726 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region);
2727 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
2728 check_region(&region, 10, 7, 9, 11);
2730 size.X = 23;
2731 size.Y = 17;
2732 coord.X = 2;
2733 coord.Y = 3;
2734 set_region(&region, 10, 7, 11, 6);
2735 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region);
2736 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
2737 check_region(&region, 10, 7, 11, 6);
2739 size.X = 2;
2740 size.Y = 17;
2741 coord.X = 2;
2742 coord.Y = 3;
2743 set_region(&region, 10, 7, 15, 11);
2744 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region);
2745 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
2746 check_region(&region, 10, 7, 15, 11);
2748 size.X = 23;
2749 size.Y = 3;
2750 coord.X = 2;
2751 coord.Y = 3;
2752 set_region(&region, 10, 7, 15, 11);
2753 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region);
2754 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
2755 check_region(&region, 10, 7, 15, 11);
2757 size.X = 6;
2758 size.Y = 17;
2759 coord.X = 2;
2760 coord.Y = 3;
2761 set_region(&region, 10, 7, 15, 11);
2762 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region);
2763 ok(ret, "WriteConsoleOutputW failed: %lu\n", GetLastError());
2764 check_region(&region, 10, 7, 13, 11);
2766 size.X = 6;
2767 size.Y = 17;
2768 coord.X = 2;
2769 coord.Y = 3;
2770 set_region(&region, 10, 7, 15, 11);
2771 ret = WriteConsoleOutputW((HANDLE)0xdeadbeef, char_info_buf, size, coord, &region);
2772 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
2773 if (!skip_nt) check_region(&region, 10, 7, 13, 11);
2775 size.X = 16;
2776 size.Y = 7;
2777 coord.X = 2;
2778 coord.Y = 3;
2779 set_region(&region, 10, 7, 15, 11);
2780 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region);
2781 ok(ret, "WriteConsoleOutputW failed: %lu\n", GetLastError());
2782 check_region(&region, 10, 7, 15, 10);
2784 size.X = 16;
2785 size.Y = 7;
2786 coord.X = 2;
2787 coord.Y = 3;
2788 set_region(&region, info.dwSize.X - 2, 7, info.dwSize.X + 2, 7);
2789 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region);
2790 ok(ret, "WriteConsoleOutputW failed: %lu\n", GetLastError());
2791 check_region(&region, info.dwSize.X - 2, 7, info.dwSize.X - 1, 7);
2794 static void test_FillConsoleOutputCharacterA(HANDLE output_handle)
2796 COORD origin = {0, 0};
2797 DWORD count;
2798 BOOL ret;
2799 int i;
2801 const struct
2803 HANDLE hConsoleOutput;
2804 CHAR ch;
2805 DWORD length;
2806 COORD coord;
2807 LPDWORD lpNumCharsWritten;
2808 DWORD last_error;
2809 int win7_crash;
2810 } invalid_table[] =
2812 {NULL, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2813 {NULL, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2814 {NULL, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2815 {NULL, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2816 {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2817 {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2818 {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2819 {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2820 {output_handle, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2821 {output_handle, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2824 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2826 if (invalid_table[i].win7_crash)
2827 continue;
2829 SetLastError(0xdeadbeef);
2830 if (invalid_table[i].lpNumCharsWritten) count = 0xdeadbeef;
2831 ret = FillConsoleOutputCharacterA(invalid_table[i].hConsoleOutput,
2832 invalid_table[i].ch,
2833 invalid_table[i].length,
2834 invalid_table[i].coord,
2835 invalid_table[i].lpNumCharsWritten);
2836 ok(!ret, "[%d] Expected FillConsoleOutputCharacterA to return FALSE, got %d\n", i, ret);
2837 ok(GetLastError() == invalid_table[i].last_error,
2838 "[%d] Expected last error to be %lu, got %lu\n",
2839 i, invalid_table[i].last_error, GetLastError());
2842 count = 0xdeadbeef;
2843 ret = FillConsoleOutputCharacterA(output_handle, 'a', 0, origin, &count);
2844 ok(ret == TRUE, "Expected FillConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2845 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2847 count = 0xdeadbeef;
2848 ret = FillConsoleOutputCharacterA(output_handle, 'a', 1, origin, &count);
2849 ok(ret == TRUE, "Expected FillConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2850 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2853 static void test_FillConsoleOutputCharacterW(HANDLE output_handle)
2855 COORD origin = {0, 0};
2856 DWORD count;
2857 BOOL ret;
2858 int i;
2860 const struct
2862 HANDLE hConsoleOutput;
2863 WCHAR ch;
2864 DWORD length;
2865 COORD coord;
2866 LPDWORD lpNumCharsWritten;
2867 DWORD last_error;
2868 int win7_crash;
2869 } invalid_table[] =
2871 {NULL, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2872 {NULL, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2873 {NULL, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2874 {NULL, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2875 {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2876 {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2877 {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2878 {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2879 {output_handle, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2880 {output_handle, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2883 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2885 if (invalid_table[i].win7_crash)
2886 continue;
2888 SetLastError(0xdeadbeef);
2889 if (invalid_table[i].lpNumCharsWritten) count = 0xdeadbeef;
2890 ret = FillConsoleOutputCharacterW(invalid_table[i].hConsoleOutput,
2891 invalid_table[i].ch,
2892 invalid_table[i].length,
2893 invalid_table[i].coord,
2894 invalid_table[i].lpNumCharsWritten);
2895 ok(!ret, "[%d] Expected FillConsoleOutputCharacterW to return FALSE, got %d\n", i, ret);
2896 ok(GetLastError() == invalid_table[i].last_error,
2897 "[%d] Expected last error to be %lu, got %lu\n",
2898 i, invalid_table[i].last_error, GetLastError());
2901 count = 0xdeadbeef;
2902 ret = FillConsoleOutputCharacterW(output_handle, 'a', 0, origin, &count);
2903 ok(ret == TRUE, "Expected FillConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2904 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2906 count = 0xdeadbeef;
2907 ret = FillConsoleOutputCharacterW(output_handle, 'a', 1, origin, &count);
2908 ok(ret == TRUE, "Expected FillConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2909 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2912 static void test_FillConsoleOutputAttribute(HANDLE output_handle)
2914 COORD origin = {0, 0};
2915 DWORD count;
2916 BOOL ret;
2917 int i;
2919 const struct
2921 HANDLE hConsoleOutput;
2922 WORD attr;
2923 DWORD length;
2924 COORD coord;
2925 LPDWORD lpNumAttrsWritten;
2926 DWORD last_error;
2927 int win7_crash;
2928 } invalid_table[] =
2930 {NULL, FOREGROUND_BLUE, 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2931 {NULL, FOREGROUND_BLUE, 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2932 {NULL, FOREGROUND_BLUE, 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2933 {NULL, FOREGROUND_BLUE, 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2934 {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2935 {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2936 {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2937 {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2938 {output_handle, FOREGROUND_BLUE, 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2939 {output_handle, FOREGROUND_BLUE, 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2942 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2944 if (invalid_table[i].win7_crash)
2945 continue;
2947 SetLastError(0xdeadbeef);
2948 if (invalid_table[i].lpNumAttrsWritten) count = 0xdeadbeef;
2949 ret = FillConsoleOutputAttribute(invalid_table[i].hConsoleOutput,
2950 invalid_table[i].attr,
2951 invalid_table[i].length,
2952 invalid_table[i].coord,
2953 invalid_table[i].lpNumAttrsWritten);
2954 ok(!ret, "[%d] Expected FillConsoleOutputAttribute to return FALSE, got %d\n", i, ret);
2955 ok(GetLastError() == invalid_table[i].last_error,
2956 "[%d] Expected last error to be %lu, got %lu\n",
2957 i, invalid_table[i].last_error, GetLastError());
2960 count = 0xdeadbeef;
2961 ret = FillConsoleOutputAttribute(output_handle, FOREGROUND_BLUE, 0, origin, &count);
2962 ok(ret == TRUE, "Expected FillConsoleOutputAttribute to return TRUE, got %d\n", ret);
2963 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2965 count = 0xdeadbeef;
2966 ret = FillConsoleOutputAttribute(output_handle, FOREGROUND_BLUE, 1, origin, &count);
2967 ok(ret == TRUE, "Expected FillConsoleOutputAttribute to return TRUE, got %d\n", ret);
2968 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2970 count = 0xdeadbeef;
2971 ret = FillConsoleOutputAttribute(output_handle, ~0, 1, origin, &count);
2972 ok(ret == TRUE, "Expected FillConsoleOutputAttribute to return TRUE, got %d\n", ret);
2973 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2976 static void test_ReadConsoleOutputCharacterA(HANDLE output_handle)
2978 CHAR read;
2979 COORD origin = {0, 0};
2980 DWORD count;
2981 BOOL ret;
2982 int i;
2984 const struct
2986 HANDLE hConsoleOutput;
2987 LPSTR lpstr;
2988 DWORD length;
2989 COORD coord;
2990 LPDWORD read_count;
2991 DWORD expected_count;
2992 DWORD last_error;
2993 int win7_crash;
2994 } invalid_table[] =
2996 {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2997 {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2998 {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2999 {NULL, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
3000 {NULL, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3001 {NULL, &read, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3002 {NULL, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3003 {NULL, &read, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3004 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3005 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3006 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3007 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
3008 {INVALID_HANDLE_VALUE, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3009 {INVALID_HANDLE_VALUE, &read, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3010 {INVALID_HANDLE_VALUE, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3011 {INVALID_HANDLE_VALUE, &read, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3012 {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3013 {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3014 {output_handle, NULL, 1, {0, 0}, &count, 1, ERROR_INVALID_ACCESS, 1},
3015 {output_handle, NULL, 10, {0, 0}, &count, 10, ERROR_INVALID_ACCESS, 1},
3016 {output_handle, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3017 {output_handle, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3020 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
3022 if (invalid_table[i].win7_crash)
3023 continue;
3025 SetLastError(0xdeadbeef);
3026 if (invalid_table[i].read_count) count = 0xdeadbeef;
3027 ret = ReadConsoleOutputCharacterA(invalid_table[i].hConsoleOutput,
3028 invalid_table[i].lpstr,
3029 invalid_table[i].length,
3030 invalid_table[i].coord,
3031 invalid_table[i].read_count);
3032 ok(!ret, "[%d] Expected ReadConsoleOutputCharacterA to return FALSE, got %d\n", i, ret);
3033 ok(GetLastError() == invalid_table[i].last_error,
3034 "[%d] Expected last error to be %lu, got %lu\n",
3035 i, invalid_table[i].last_error, GetLastError());
3038 count = 0xdeadbeef;
3039 ret = ReadConsoleOutputCharacterA(output_handle, NULL, 0, origin, &count);
3040 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterA to return TRUE, got %d\n", ret);
3041 ok(count == 0, "Expected count to be 0, got %lu\n", count);
3043 count = 0xdeadbeef;
3044 ret = ReadConsoleOutputCharacterA(output_handle, &read, 0, origin, &count);
3045 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterA to return TRUE, got %d\n", ret);
3046 ok(count == 0, "Expected count to be 0, got %lu\n", count);
3048 count = 0xdeadbeef;
3049 ret = ReadConsoleOutputCharacterA(output_handle, &read, 1, origin, &count);
3050 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterA to return TRUE, got %d\n", ret);
3051 ok(count == 1, "Expected count to be 1, got %lu\n", count);
3053 count = 0xdeadbeef;
3054 origin.X = 200;
3055 ret = ReadConsoleOutputCharacterA(output_handle, &read, 1, origin, &count);
3056 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterA to return TRUE, got %d\n", ret);
3057 ok(count == 0, "Expected count to be 0, got %lu\n", count);
3060 static void test_ReadConsoleOutputCharacterW(HANDLE output_handle)
3062 WCHAR read;
3063 COORD origin = {0, 0};
3064 DWORD count;
3065 BOOL ret;
3066 int i;
3068 const struct
3070 HANDLE hConsoleOutput;
3071 LPWSTR buffer;
3072 DWORD length;
3073 COORD coord;
3074 LPDWORD read_count;
3075 DWORD expected_count;
3076 DWORD last_error;
3077 int win7_crash;
3078 } invalid_table[] =
3080 {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3081 {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3082 {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3083 {NULL, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
3084 {NULL, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3085 {NULL, &read, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3086 {NULL, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3087 {NULL, &read, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3088 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3089 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3090 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3091 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
3092 {INVALID_HANDLE_VALUE, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3093 {INVALID_HANDLE_VALUE, &read, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3094 {INVALID_HANDLE_VALUE, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3095 {INVALID_HANDLE_VALUE, &read, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3096 {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3097 {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3098 {output_handle, NULL, 1, {0, 0}, &count, 1, ERROR_INVALID_ACCESS, 1},
3099 {output_handle, NULL, 10, {0, 0}, &count, 10, ERROR_INVALID_ACCESS, 1},
3100 {output_handle, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3101 {output_handle, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3104 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
3106 if (invalid_table[i].win7_crash)
3107 continue;
3109 SetLastError(0xdeadbeef);
3110 if (invalid_table[i].read_count) count = 0xdeadbeef;
3111 ret = ReadConsoleOutputCharacterW(invalid_table[i].hConsoleOutput,
3112 invalid_table[i].buffer,
3113 invalid_table[i].length,
3114 invalid_table[i].coord,
3115 invalid_table[i].read_count);
3116 ok(!ret, "[%d] Expected ReadConsoleOutputCharacterW to return FALSE, got %d\n", i, ret);
3117 ok(GetLastError() == invalid_table[i].last_error,
3118 "[%d] Expected last error to be %lu, got %lu\n",
3119 i, invalid_table[i].last_error, GetLastError());
3122 count = 0xdeadbeef;
3123 ret = ReadConsoleOutputCharacterW(output_handle, NULL, 0, origin, &count);
3124 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterW to return TRUE, got %d\n", ret);
3125 ok(count == 0, "Expected count to be 0, got %lu\n", count);
3127 count = 0xdeadbeef;
3128 ret = ReadConsoleOutputCharacterW(output_handle, &read, 0, origin, &count);
3129 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterW to return TRUE, got %d\n", ret);
3130 ok(count == 0, "Expected count to be 0, got %lu\n", count);
3132 count = 0xdeadbeef;
3133 ret = ReadConsoleOutputCharacterW(output_handle, &read, 1, origin, &count);
3134 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterW to return TRUE, got %d\n", ret);
3135 ok(count == 1, "Expected count to be 1, got %lu\n", count);
3137 count = 0xdeadbeef;
3138 origin.X = 200;
3139 ret = ReadConsoleOutputCharacterW(output_handle, &read, 1, origin, &count);
3140 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterW to return TRUE, got %d\n", ret);
3141 ok(count == 0, "Expected count to be 0, got %lu\n", count);
3144 static void test_ReadConsoleOutputAttribute(HANDLE output_handle)
3146 WORD attr;
3147 COORD origin = {0, 0};
3148 DWORD count;
3149 BOOL ret;
3150 int i;
3152 const struct
3154 HANDLE hConsoleOutput;
3155 LPWORD lpAttribute;
3156 DWORD length;
3157 COORD coord;
3158 LPDWORD read_count;
3159 DWORD expected_count;
3160 DWORD last_error;
3161 int win7_crash;
3162 } invalid_table[] =
3164 {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3165 {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3166 {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3167 {NULL, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
3168 {NULL, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3169 {NULL, &attr, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3170 {NULL, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3171 {NULL, &attr, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3172 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3173 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3174 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3175 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
3176 {INVALID_HANDLE_VALUE, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3177 {INVALID_HANDLE_VALUE, &attr, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3178 {INVALID_HANDLE_VALUE, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3179 {INVALID_HANDLE_VALUE, &attr, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3180 {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3181 {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3182 {output_handle, NULL, 1, {0, 0}, &count, 1, ERROR_INVALID_ACCESS, 1},
3183 {output_handle, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3184 {output_handle, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3187 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
3189 if (invalid_table[i].win7_crash)
3190 continue;
3192 SetLastError(0xdeadbeef);
3193 if (invalid_table[i].read_count) count = 0xdeadbeef;
3194 ret = ReadConsoleOutputAttribute(invalid_table[i].hConsoleOutput,
3195 invalid_table[i].lpAttribute,
3196 invalid_table[i].length,
3197 invalid_table[i].coord,
3198 invalid_table[i].read_count);
3199 ok(!ret, "[%d] Expected ReadConsoleOutputAttribute to return FALSE, got %d\n", i, ret);
3200 ok(GetLastError() == invalid_table[i].last_error,
3201 "[%d] Expected last error to be %lu, got %lu\n",
3202 i, invalid_table[i].last_error, GetLastError());
3205 count = 0xdeadbeef;
3206 ret = ReadConsoleOutputAttribute(output_handle, NULL, 0, origin, &count);
3207 ok(ret == TRUE, "Expected ReadConsoleOutputAttribute to return TRUE, got %d\n", ret);
3208 ok(count == 0, "Expected count to be 0, got %lu\n", count);
3210 count = 0xdeadbeef;
3211 ret = ReadConsoleOutputAttribute(output_handle, &attr, 0, origin, &count);
3212 ok(ret == TRUE, "Expected ReadConsoleOutputAttribute to return TRUE, got %d\n", ret);
3213 ok(count == 0, "Expected count to be 0, got %lu\n", count);
3215 count = 0xdeadbeef;
3216 ret = ReadConsoleOutputAttribute(output_handle, &attr, 1, origin, &count);
3217 ok(ret == TRUE, "Expected ReadConsoleOutputAttribute to return TRUE, got %d\n", ret);
3218 ok(count == 1, "Expected count to be 1, got %lu\n", count);
3220 count = 0xdeadbeef;
3221 origin.X = 200;
3222 ret = ReadConsoleOutputAttribute(output_handle, &attr, 1, origin, &count);
3223 ok(ret == TRUE, "Expected ReadConsoleOutputAttribute to return TRUE, got %d\n", ret);
3224 ok(count == 0, "Expected count to be 1, got %lu\n", count);
3227 static void test_ReadConsoleOutput(HANDLE console)
3229 CONSOLE_SCREEN_BUFFER_INFO info;
3230 CHAR_INFO char_info_buf[2048];
3231 SMALL_RECT region;
3232 COORD size, coord;
3233 DWORD count;
3234 WCHAR ch;
3235 BOOL ret;
3237 if (skip_nt) return;
3239 ret = GetConsoleScreenBufferInfo(console, &info);
3240 ok(ret, "GetConsoleScreenBufferInfo failed: %lu\n", GetLastError());
3242 size.X = 23;
3243 size.Y = 17;
3244 coord.X = 2;
3245 coord.Y = 3;
3246 set_region(&region, 10, 7, 15, 11);
3247 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region);
3248 ok(ret, "ReadConsoleOutputW failed: %lu\n", GetLastError());
3249 check_region(&region, 10, 7, 15, 11);
3251 size.X = 23;
3252 size.Y = 17;
3253 coord.X = 2;
3254 coord.Y = 3;
3255 set_region(&region, 200, 7, 15, 211);
3256 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region);
3257 ok(!ret, "ReadConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
3258 check_region(&region, 200, 7, -15, 0);
3260 size.X = 23;
3261 size.Y = 17;
3262 coord.X = 2;
3263 coord.Y = 3;
3264 set_region(&region, 200, 7, 211, 8);
3265 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region);
3266 ok((!ret && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_INVALID_FUNCTION)) || broken(ret /* win8 */),
3267 "ReadConsoleOutputW returned: %x %lu\n", ret, GetLastError());
3268 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER) check_region(&region, 200, 7, -211, -8);
3270 size.X = 23;
3271 size.Y = 17;
3272 coord.X = 2;
3273 coord.Y = 3;
3274 set_region(&region, 10, 7, 9, 11);
3275 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region);
3276 ok((!ret && (GetLastError() == ERROR_INVALID_FUNCTION || GetLastError() == ERROR_NOT_ENOUGH_MEMORY)) || broken(ret /* win8 */),
3277 "ReadConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
3278 check_region(&region, 10, 7, 9, -11);
3280 size.X = 23;
3281 size.Y = 17;
3282 coord.X = 2;
3283 coord.Y = 3;
3284 set_region(&region, 10, 7, 11, 6);
3285 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region);
3286 ok((!ret && (GetLastError() == ERROR_INVALID_FUNCTION || GetLastError() == ERROR_NOT_ENOUGH_MEMORY)) || broken(ret /* win8 */),
3287 "ReadConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
3288 check_region(&region, 10, 7, -11, 6);
3290 size.X = 2;
3291 size.Y = 17;
3292 coord.X = 2;
3293 coord.Y = 3;
3294 set_region(&region, 10, 7, 15, 11);
3295 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region);
3296 ok((!ret && (GetLastError() == ERROR_INVALID_FUNCTION || GetLastError() == ERROR_NOT_ENOUGH_MEMORY)) || broken(ret /* win8 */),
3297 "ReadConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
3298 check_region(&region, 10, 7, -15, -11);
3300 size.X = 23;
3301 size.Y = 3;
3302 coord.X = 2;
3303 coord.Y = 3;
3304 set_region(&region, 10, 7, 15, 11);
3305 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region);
3306 ok((!ret && (GetLastError() == ERROR_INVALID_FUNCTION || GetLastError() == ERROR_NOT_ENOUGH_MEMORY)) || broken(ret /* win8 */),
3307 "ReadConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
3308 check_region(&region, 10, 7, -15, 6);
3310 size.X = 6;
3311 size.Y = 17;
3312 coord.X = 2;
3313 coord.Y = 3;
3314 set_region(&region, 10, 7, 15, 11);
3315 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region);
3316 ok(ret, "ReadConsoleOutputW failed: %lu\n", GetLastError());
3317 check_region(&region, 10, 7, 13, 11);
3319 size.X = 6;
3320 size.Y = 17;
3321 coord.X = 2;
3322 coord.Y = 3;
3323 set_region(&region, 10, 7, 15, 11);
3324 ret = ReadConsoleOutputW((HANDLE)0xdeadbeef, char_info_buf, size, coord, &region);
3325 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "ReadConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
3326 if (!skip_nt) check_region(&region, 10, 7, 13, 11);
3328 size.X = 16;
3329 size.Y = 7;
3330 coord.X = 2;
3331 coord.Y = 3;
3332 set_region(&region, 10, 7, 15, 11);
3333 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region);
3334 ok(ret, "ReadConsoleOutputW failed: %lu\n", GetLastError());
3335 check_region(&region, 10, 7, 15, 10);
3337 size.X = 16;
3338 size.Y = 7;
3339 coord.X = 2;
3340 coord.Y = 3;
3341 set_region(&region, info.dwSize.X - 2, 7, info.dwSize.X + 2, 7);
3342 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region);
3343 ok(ret || GetLastError() == ERROR_INVALID_PARAMETER, "ReadConsoleOutputW failed: %lu\n", GetLastError());
3344 if (ret) check_region(&region, info.dwSize.X - 2, 7, info.dwSize.X - 1, 7);
3346 coord.X = 2;
3347 coord.Y = 3;
3348 ret = WriteConsoleOutputCharacterW(console, L"xyz", 3, coord, &count);
3349 ok(ret, "WriteConsoleOutputCharacterW failed: %lu\n", GetLastError());
3350 ok(count == 3, "count = %lu\n", count);
3352 memset(char_info_buf, 0xc0, sizeof(char_info_buf));
3353 size.X = 16;
3354 size.Y = 7;
3355 coord.X = 5;
3356 coord.Y = 6;
3357 set_region(&region, 2, 3, 5, 3);
3358 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region);
3359 ok(ret, "ReadConsoleOutputW failed: %lu\n", GetLastError());
3360 check_region(&region, 2, 3, 5, 3);
3361 ch = char_info_buf[coord.Y * size.X + coord.X].Char.UnicodeChar;
3362 ok(ch == 'x', "unexpected char %c/%x\n", ch, ch);
3363 ch = char_info_buf[coord.Y * size.X + coord.X + 1].Char.UnicodeChar;
3364 ok(ch == 'y', "unexpected char %c/%x\n", ch, ch);
3365 ch = char_info_buf[coord.Y * size.X + coord.X + 2].Char.UnicodeChar;
3366 ok(ch == 'z', "unexpected char %c/%x\n", ch, ch);
3369 static void test_ReadConsole(HANDLE input)
3371 DWORD ret, bytes;
3372 char buf[1024];
3373 HANDLE output;
3375 SetLastError(0xdeadbeef);
3376 ret = GetFileSize(input, NULL);
3377 ok(ret == INVALID_FILE_SIZE || broken(TRUE), /* only Win7 pro64 on 64bit returns a valid file size here */
3378 "expected INVALID_FILE_SIZE, got %#lx\n", ret);
3379 if (ret == INVALID_FILE_SIZE)
3380 ok(GetLastError() == ERROR_INVALID_HANDLE ||
3381 GetLastError() == ERROR_INVALID_FUNCTION, /* Win 8, 10 */
3382 "expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
3384 bytes = 0xdeadbeef;
3385 SetLastError(0xdeadbeef);
3386 ret = ReadFile(input, buf, -128, &bytes, NULL);
3387 ok(!ret, "expected 0, got %lu\n", ret);
3388 ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
3389 GetLastError() == ERROR_NOACCESS, /* Win 8, 10 */
3390 "expected ERROR_NOT_ENOUGH_MEMORY, got %ld\n", GetLastError());
3391 ok(!bytes, "expected 0, got %lu\n", bytes);
3393 bytes = 0xdeadbeef;
3394 SetLastError(0xdeadbeef);
3395 ret = ReadConsoleA(input, buf, -128, &bytes, NULL);
3396 ok(!ret, "expected 0, got %lu\n", ret);
3397 ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
3398 GetLastError() == ERROR_NOACCESS, /* Win 8, 10 */
3399 "expected ERROR_NOT_ENOUGH_MEMORY, got %ld\n", GetLastError());
3400 ok(bytes == 0xdeadbeef, "expected 0xdeadbeef, got %#lx\n", bytes);
3402 bytes = 0xdeadbeef;
3403 SetLastError(0xdeadbeef);
3404 ret = ReadConsoleW(input, buf, -128, &bytes, NULL);
3405 ok(!ret, "expected 0, got %lu\n", ret);
3406 ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
3407 GetLastError() == ERROR_NOACCESS, /* Win 8, 10 */
3408 "expected ERROR_NOT_ENOUGH_MEMORY, got %ld\n", GetLastError());
3409 ok(bytes == 0xdeadbeef, "expected 0xdeadbeef, got %#lx\n", bytes);
3411 output = CreateFileA("CONOUT$", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
3412 ok(output != INVALID_HANDLE_VALUE, "Could not open console\n");
3414 ret = ReadConsoleW(output, buf, sizeof(buf) / sizeof(WCHAR), &bytes, NULL);
3415 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
3416 "ReadConsoleW returned %lx(%lu)\n", ret, GetLastError());
3418 ret = ReadConsoleA(output, buf, sizeof(buf), &bytes, NULL);
3419 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
3420 "ReadConsoleA returned %lx(%lu)\n", ret, GetLastError());
3422 ret = ReadFile(output, buf, sizeof(buf), &bytes, NULL);
3423 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
3424 "ReadFile returned %lx(%lu)\n", ret, GetLastError());
3426 CloseHandle(output);
3429 static void test_GetCurrentConsoleFont(HANDLE std_output)
3431 BOOL ret;
3432 CONSOLE_FONT_INFO cfi;
3433 CONSOLE_SCREEN_BUFFER_INFO csbi;
3434 short int width, height;
3435 HANDLE pipe1, pipe2;
3436 COORD c;
3438 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3439 SetLastError(0xdeadbeef);
3440 ret = GetCurrentConsoleFont(NULL, FALSE, &cfi);
3441 ok(!ret, "got %d, expected 0\n", ret);
3442 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3443 ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
3444 ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
3446 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3447 SetLastError(0xdeadbeef);
3448 ret = GetCurrentConsoleFont(NULL, TRUE, &cfi);
3449 ok(!ret, "got %d, expected 0\n", ret);
3450 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3451 ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
3452 ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
3454 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3455 SetLastError(0xdeadbeef);
3456 ret = GetCurrentConsoleFont(GetStdHandle(STD_INPUT_HANDLE), FALSE, &cfi);
3457 ok(!ret, "got %d, expected 0\n", ret);
3458 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3459 ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
3460 ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
3462 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3463 SetLastError(0xdeadbeef);
3464 ret = GetCurrentConsoleFont(GetStdHandle(STD_INPUT_HANDLE), TRUE, &cfi);
3465 ok(!ret, "got %d, expected 0\n", ret);
3466 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3467 ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
3468 ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
3470 CreatePipe(&pipe1, &pipe2, NULL, 0);
3471 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3472 SetLastError(0xdeadbeef);
3473 ret = GetCurrentConsoleFont(pipe1, TRUE, &cfi);
3474 ok(!ret, "got %d, expected 0\n", ret);
3475 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3476 ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
3477 ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
3478 CloseHandle(pipe1);
3479 CloseHandle(pipe2);
3481 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3482 SetLastError(0xdeadbeef);
3483 ret = GetCurrentConsoleFont(std_output, FALSE, &cfi);
3484 ok(ret, "got %d, expected non-zero\n", ret);
3485 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3486 GetConsoleScreenBufferInfo(std_output, &csbi);
3487 width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
3488 height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
3489 c = GetConsoleFontSize(std_output, cfi.nFont);
3490 ok(cfi.dwFontSize.X == width || cfi.dwFontSize.X == c.X /* Vista and higher */,
3491 "got %d, expected %d\n", cfi.dwFontSize.X, width);
3492 ok(cfi.dwFontSize.Y == height || cfi.dwFontSize.Y == c.Y /* Vista and higher */,
3493 "got %d, expected %d\n", cfi.dwFontSize.Y, height);
3495 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3496 SetLastError(0xdeadbeef);
3497 ret = GetCurrentConsoleFont(std_output, TRUE, &cfi);
3498 ok(ret, "got %d, expected non-zero\n", ret);
3499 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3500 ok(cfi.dwFontSize.X == csbi.dwMaximumWindowSize.X,
3501 "got %d, expected %d\n", cfi.dwFontSize.X, csbi.dwMaximumWindowSize.X);
3502 ok(cfi.dwFontSize.Y == csbi.dwMaximumWindowSize.Y,
3503 "got %d, expected %d\n", cfi.dwFontSize.Y, csbi.dwMaximumWindowSize.Y);
3506 static void test_GetCurrentConsoleFontEx(HANDLE std_output)
3508 HANDLE hmod;
3509 BOOL (WINAPI *pGetCurrentConsoleFontEx)(HANDLE, BOOL, CONSOLE_FONT_INFOEX *);
3510 CONSOLE_FONT_INFO cfi;
3511 CONSOLE_FONT_INFOEX cfix;
3512 BOOL ret;
3513 HANDLE std_input = GetStdHandle(STD_INPUT_HANDLE);
3514 HANDLE pipe1, pipe2;
3515 COORD c;
3517 hmod = GetModuleHandleA("kernel32.dll");
3518 pGetCurrentConsoleFontEx = (void *)GetProcAddress(hmod, "GetCurrentConsoleFontEx");
3519 if (!pGetCurrentConsoleFontEx)
3521 win_skip("GetCurrentConsoleFontEx is not available\n");
3522 return;
3525 SetLastError(0xdeadbeef);
3526 ret = pGetCurrentConsoleFontEx(NULL, FALSE, &cfix);
3527 ok(!ret, "got %d, expected 0\n", ret);
3528 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3530 SetLastError(0xdeadbeef);
3531 ret = pGetCurrentConsoleFontEx(NULL, TRUE, &cfix);
3532 ok(!ret, "got %d, expected 0\n", ret);
3533 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3535 SetLastError(0xdeadbeef);
3536 ret = pGetCurrentConsoleFontEx(std_input, FALSE, &cfix);
3537 ok(!ret, "got %d, expected 0\n", ret);
3538 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3540 SetLastError(0xdeadbeef);
3541 ret = pGetCurrentConsoleFontEx(std_input, TRUE, &cfix);
3542 ok(!ret, "got %d, expected 0\n", ret);
3543 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3545 SetLastError(0xdeadbeef);
3546 ret = pGetCurrentConsoleFontEx(std_output, FALSE, &cfix);
3547 ok(!ret, "got %d, expected 0\n", ret);
3548 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3550 SetLastError(0xdeadbeef);
3551 ret = pGetCurrentConsoleFontEx(std_output, TRUE, &cfix);
3552 ok(!ret, "got %d, expected 0\n", ret);
3553 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3555 cfix.cbSize = sizeof(CONSOLE_FONT_INFOEX);
3557 SetLastError(0xdeadbeef);
3558 ret = pGetCurrentConsoleFontEx(NULL, FALSE, &cfix);
3559 ok(!ret, "got %d, expected 0\n", ret);
3560 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3562 SetLastError(0xdeadbeef);
3563 ret = pGetCurrentConsoleFontEx(NULL, TRUE, &cfix);
3564 ok(!ret, "got %d, expected 0\n", ret);
3565 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3567 SetLastError(0xdeadbeef);
3568 ret = pGetCurrentConsoleFontEx(std_input, FALSE, &cfix);
3569 ok(!ret, "got %d, expected 0\n", ret);
3570 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3572 SetLastError(0xdeadbeef);
3573 ret = pGetCurrentConsoleFontEx(std_input, TRUE, &cfix);
3574 ok(!ret, "got %d, expected 0\n", ret);
3575 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3577 CreatePipe(&pipe1, &pipe2, NULL, 0);
3578 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3579 SetLastError(0xdeadbeef);
3580 ret = pGetCurrentConsoleFontEx(pipe1, TRUE, &cfix);
3581 ok(!ret, "got %d, expected 0\n", ret);
3582 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3583 CloseHandle(pipe1);
3584 CloseHandle(pipe2);
3586 SetLastError(0xdeadbeef);
3587 ret = pGetCurrentConsoleFontEx(std_output, FALSE, &cfix);
3588 ok(ret, "got %d, expected non-zero\n", ret);
3589 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3591 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3592 SetLastError(0xdeadbeef);
3593 ret = GetCurrentConsoleFont(std_output, FALSE, &cfi);
3594 ok(ret, "got %d, expected non-zero\n", ret);
3595 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3597 ok(cfix.dwFontSize.X == cfi.dwFontSize.X, "expected values to match\n");
3598 ok(cfix.dwFontSize.Y == cfi.dwFontSize.Y, "expected values to match\n");
3600 SetLastError(0xdeadbeef);
3601 c = GetConsoleFontSize(std_output, cfix.nFont);
3602 ok(c.X && c.Y, "GetConsoleFontSize failed; err = %lu\n", GetLastError());
3603 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3605 ok(cfix.dwFontSize.X == c.X, "Font width doesn't match; got %u, expected %u\n",
3606 cfix.dwFontSize.X, c.X);
3607 ok(cfix.dwFontSize.Y == c.Y, "Font height doesn't match; got %u, expected %u\n",
3608 cfix.dwFontSize.Y, c.Y);
3610 ok(cfi.dwFontSize.X == c.X, "Font width doesn't match; got %u, expected %u\n",
3611 cfi.dwFontSize.X, c.X);
3612 ok(cfi.dwFontSize.Y == c.Y, "Font height doesn't match; got %u, expected %u\n",
3613 cfi.dwFontSize.Y, c.Y);
3615 SetLastError(0xdeadbeef);
3616 ret = pGetCurrentConsoleFontEx(std_output, TRUE, &cfix);
3617 ok(ret, "got %d, expected non-zero\n", ret);
3618 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3620 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3621 SetLastError(0xdeadbeef);
3622 ret = GetCurrentConsoleFont(std_output, TRUE, &cfi);
3623 ok(ret, "got %d, expected non-zero\n", ret);
3624 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3626 ok(cfix.dwFontSize.X == cfi.dwFontSize.X, "expected values to match\n");
3627 ok(cfix.dwFontSize.Y == cfi.dwFontSize.Y, "expected values to match\n");
3630 static void test_SetCurrentConsoleFontEx(HANDLE std_output)
3632 CONSOLE_FONT_INFOEX orig_cfix, cfix;
3633 BOOL ret;
3634 HANDLE pipe1, pipe2;
3635 HANDLE std_input = GetStdHandle(STD_INPUT_HANDLE);
3637 orig_cfix.cbSize = sizeof(CONSOLE_FONT_INFOEX);
3639 ret = GetCurrentConsoleFontEx(std_output, FALSE, &orig_cfix);
3640 ok(ret, "got %d, expected non-zero\n", ret);
3642 cfix = orig_cfix;
3643 cfix.cbSize = 0;
3645 SetLastError(0xdeadbeef);
3646 ret = SetCurrentConsoleFontEx(NULL, FALSE, &cfix);
3647 ok(!ret, "got %d, expected 0\n", ret);
3648 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3650 SetLastError(0xdeadbeef);
3651 ret = SetCurrentConsoleFontEx(NULL, TRUE, &cfix);
3652 ok(!ret, "got %d, expected 0\n", ret);
3653 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3655 CreatePipe(&pipe1, &pipe2, NULL, 0);
3656 SetLastError(0xdeadbeef);
3657 ret = SetCurrentConsoleFontEx(pipe1, FALSE, &cfix);
3658 ok(!ret, "got %d, expected 0\n", ret);
3659 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3660 CloseHandle(pipe1);
3661 CloseHandle(pipe2);
3663 CreatePipe(&pipe1, &pipe2, NULL, 0);
3664 SetLastError(0xdeadbeef);
3665 ret = SetCurrentConsoleFontEx(pipe1, TRUE, &cfix);
3666 ok(!ret, "got %d, expected 0\n", ret);
3667 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3668 CloseHandle(pipe1);
3669 CloseHandle(pipe2);
3671 SetLastError(0xdeadbeef);
3672 ret = SetCurrentConsoleFontEx(std_input, FALSE, &cfix);
3673 ok(!ret, "got %d, expected 0\n", ret);
3674 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3676 SetLastError(0xdeadbeef);
3677 ret = SetCurrentConsoleFontEx(std_input, TRUE, &cfix);
3678 ok(!ret, "got %d, expected 0\n", ret);
3679 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3681 SetLastError(0xdeadbeef);
3682 ret = SetCurrentConsoleFontEx(std_output, FALSE, &cfix);
3683 ok(!ret, "got %d, expected 0\n", ret);
3684 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3686 SetLastError(0xdeadbeef);
3687 ret = SetCurrentConsoleFontEx(std_output, TRUE, &cfix);
3688 ok(!ret, "got %d, expected 0\n", ret);
3689 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3691 cfix = orig_cfix;
3693 SetLastError(0xdeadbeef);
3694 ret = SetCurrentConsoleFontEx(NULL, FALSE, &cfix);
3695 ok(!ret, "got %d, expected 0\n", ret);
3696 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3698 SetLastError(0xdeadbeef);
3699 ret = SetCurrentConsoleFontEx(NULL, TRUE, &cfix);
3700 ok(!ret, "got %d, expected 0\n", ret);
3701 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3703 CreatePipe(&pipe1, &pipe2, NULL, 0);
3704 SetLastError(0xdeadbeef);
3705 ret = SetCurrentConsoleFontEx(pipe1, FALSE, &cfix);
3706 ok(!ret, "got %d, expected 0\n", ret);
3707 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3708 CloseHandle(pipe1);
3709 CloseHandle(pipe2);
3711 CreatePipe(&pipe1, &pipe2, NULL, 0);
3712 SetLastError(0xdeadbeef);
3713 ret = SetCurrentConsoleFontEx(pipe1, TRUE, &cfix);
3714 ok(!ret, "got %d, expected 0\n", ret);
3715 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3716 CloseHandle(pipe1);
3717 CloseHandle(pipe2);
3719 SetLastError(0xdeadbeef);
3720 ret = SetCurrentConsoleFontEx(std_input, FALSE, &cfix);
3721 ok(!ret, "got %d, expected 0\n", ret);
3722 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3724 SetLastError(0xdeadbeef);
3725 ret = SetCurrentConsoleFontEx(std_input, TRUE, &cfix);
3726 ok(!ret, "got %d, expected 0\n", ret);
3727 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3729 SetLastError(0xdeadbeef);
3730 ret = SetCurrentConsoleFontEx(std_output, FALSE, &cfix);
3731 ok(ret, "got %d, expected non-zero\n", ret);
3732 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3734 SetLastError(0xdeadbeef);
3735 ret = SetCurrentConsoleFontEx(std_output, TRUE, &cfix);
3736 ok(ret, "got %d, expected non-zero\n", ret);
3737 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3739 /* Restore original console font parameters */
3740 SetLastError(0xdeadbeef);
3741 ret = SetCurrentConsoleFontEx(std_output, FALSE, &orig_cfix);
3742 ok(ret, "got %d, expected non-zero\n", ret);
3743 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3746 static void test_GetConsoleFontSize(HANDLE std_output)
3748 COORD c;
3749 DWORD index = 0;
3750 CONSOLE_FONT_INFO cfi;
3751 RECT r;
3752 CONSOLE_SCREEN_BUFFER_INFO csbi;
3753 LONG font_width, font_height;
3754 HMODULE hmod;
3755 DWORD (WINAPI *pGetNumberOfConsoleFonts)(void);
3756 HANDLE pipe1, pipe2;
3758 memset(&c, 10, sizeof(COORD));
3759 SetLastError(0xdeadbeef);
3760 c = GetConsoleFontSize(NULL, index);
3761 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3762 ok(!c.X, "got %d, expected 0\n", c.X);
3763 ok(!c.Y, "got %d, expected 0\n", c.Y);
3765 memset(&c, 10, sizeof(COORD));
3766 SetLastError(0xdeadbeef);
3767 c = GetConsoleFontSize(GetStdHandle(STD_INPUT_HANDLE), index);
3768 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3769 ok(!c.X, "got %d, expected 0\n", c.X);
3770 ok(!c.Y, "got %d, expected 0\n", c.Y);
3772 CreatePipe(&pipe1, &pipe2, NULL, 0);
3773 memset(&c, 10, sizeof(COORD));
3774 SetLastError(0xdeadbeef);
3775 c = GetConsoleFontSize(pipe1, index);
3776 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3777 ok(!c.X, "got %d, expected 0\n", c.X);
3778 ok(!c.Y, "got %d, expected 0\n", c.Y);
3779 CloseHandle(pipe1);
3780 CloseHandle(pipe2);
3782 GetCurrentConsoleFont(std_output, FALSE, &cfi);
3783 memset(&c, 10, sizeof(COORD));
3784 SetLastError(0xdeadbeef);
3785 c = GetConsoleFontSize(std_output, cfi.nFont);
3786 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3787 GetClientRect(GetConsoleWindow(), &r);
3788 GetConsoleScreenBufferInfo(std_output, &csbi);
3789 font_width = (r.right - r.left) / (csbi.srWindow.Right - csbi.srWindow.Left + 1);
3790 font_height = (r.bottom - r.top) / (csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
3791 ok(c.X == font_width, "got %d, expected %ld\n", c.X, font_width);
3792 ok(c.Y == font_height, "got %d, expected %ld\n", c.Y, font_height);
3794 hmod = GetModuleHandleA("kernel32.dll");
3795 pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts");
3796 if (!pGetNumberOfConsoleFonts)
3798 win_skip("GetNumberOfConsoleFonts is not available\n");
3799 return;
3801 index = pGetNumberOfConsoleFonts();
3803 memset(&c, 10, sizeof(COORD));
3804 SetLastError(0xdeadbeef);
3805 c = GetConsoleFontSize(std_output, index);
3806 ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef) /* win10 1809 */,
3807 "unexpected last error %lu\n", GetLastError());
3808 if (GetLastError() == ERROR_INVALID_PARAMETER)
3810 ok(!c.X, "got %d, expected 0\n", c.X);
3811 ok(!c.Y, "got %d, expected 0\n", c.Y);
3815 static void test_GetLargestConsoleWindowSize(HANDLE std_output)
3817 COORD c, font;
3818 RECT r;
3819 LONG workarea_w, workarea_h, maxcon_w, maxcon_h;
3820 CONSOLE_SCREEN_BUFFER_INFO sbi;
3821 CONSOLE_FONT_INFO cfi;
3822 HANDLE pipe1, pipe2;
3823 DWORD index, i;
3824 HMODULE hmod;
3825 BOOL ret;
3826 DWORD (WINAPI *pGetNumberOfConsoleFonts)(void);
3827 BOOL (WINAPI *pSetConsoleFont)(HANDLE, DWORD);
3829 memset(&c, 10, sizeof(COORD));
3830 SetLastError(0xdeadbeef);
3831 c = GetLargestConsoleWindowSize(NULL);
3832 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3833 ok(!c.X, "got %d, expected 0\n", c.X);
3834 ok(!c.Y, "got %d, expected 0\n", c.Y);
3836 memset(&c, 10, sizeof(COORD));
3837 SetLastError(0xdeadbeef);
3838 c = GetLargestConsoleWindowSize(GetStdHandle(STD_INPUT_HANDLE));
3839 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3840 ok(!c.X, "got %d, expected 0\n", c.X);
3841 ok(!c.Y, "got %d, expected 0\n", c.Y);
3843 CreatePipe(&pipe1, &pipe2, NULL, 0);
3844 memset(&c, 10, sizeof(COORD));
3845 SetLastError(0xdeadbeef);
3846 c = GetLargestConsoleWindowSize(pipe1);
3847 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3848 ok(!c.X, "got %d, expected 0\n", c.X);
3849 ok(!c.Y, "got %d, expected 0\n", c.Y);
3850 CloseHandle(pipe1);
3851 CloseHandle(pipe2);
3853 SystemParametersInfoW(SPI_GETWORKAREA, 0, &r, 0);
3854 workarea_w = r.right - r.left;
3855 workarea_h = r.bottom - r.top - GetSystemMetrics(SM_CYCAPTION);
3857 GetCurrentConsoleFont(std_output, FALSE, &cfi);
3858 index = cfi.nFont; /* save current font index */
3860 hmod = GetModuleHandleA("kernel32.dll");
3861 pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts");
3862 if (!pGetNumberOfConsoleFonts)
3864 win_skip("GetNumberOfConsoleFonts is not available\n");
3865 return;
3867 pSetConsoleFont = (void *)GetProcAddress(hmod, "SetConsoleFont");
3868 if (!pSetConsoleFont)
3870 win_skip("SetConsoleFont is not available\n");
3871 return;
3874 for (i = 0; i < pGetNumberOfConsoleFonts(); i++)
3876 pSetConsoleFont(std_output, i);
3877 memset(&c, 10, sizeof(COORD));
3878 SetLastError(0xdeadbeef);
3879 c = GetLargestConsoleWindowSize(std_output);
3880 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3881 GetCurrentConsoleFont(std_output, FALSE, &cfi);
3882 font = GetConsoleFontSize(std_output, cfi.nFont);
3883 maxcon_w = workarea_w / font.X;
3884 maxcon_h = workarea_h / font.Y;
3885 ok(c.X == maxcon_w || c.X == maxcon_w - 1 /* Win10 */, "got %d, expected %ld\n", c.X, maxcon_w);
3886 ok(c.Y == maxcon_h || c.Y == maxcon_h - 1 /* Win10 */, "got %d, expected %ld\n", c.Y, maxcon_h);
3888 ret = GetConsoleScreenBufferInfo(std_output, &sbi);
3889 ok(ret, "GetConsoleScreenBufferInfo failed %lu\n", GetLastError());
3890 ok(sbi.dwMaximumWindowSize.X == min(c.X, sbi.dwSize.X), "got %d, expected %d\n",
3891 sbi.dwMaximumWindowSize.X, min(c.X, sbi.dwSize.X));
3892 ok(sbi.dwMaximumWindowSize.Y == min(c.Y, sbi.dwSize.Y), "got %d, expected %d\n",
3893 sbi.dwMaximumWindowSize.Y, min(c.Y, sbi.dwSize.Y));
3895 pSetConsoleFont(std_output, index); /* restore original font size */
3898 static void test_GetConsoleFontInfo(HANDLE std_output)
3900 HANDLE hmod;
3901 BOOL (WINAPI *pGetConsoleFontInfo)(HANDLE, BOOL, DWORD, CONSOLE_FONT_INFO *);
3902 DWORD (WINAPI *pGetNumberOfConsoleFonts)(void);
3903 DWORD num_fonts, index, i;
3904 int memsize, win_width, win_height, tmp_w, tmp_h;
3905 CONSOLE_FONT_INFO *cfi;
3906 BOOL ret;
3907 CONSOLE_SCREEN_BUFFER_INFO csbi;
3908 COORD orig_sb_size, tmp_sb_size, orig_font, tmp_font;
3910 hmod = GetModuleHandleA("kernel32.dll");
3911 pGetConsoleFontInfo = (void *)GetProcAddress(hmod, "GetConsoleFontInfo");
3912 if (!pGetConsoleFontInfo)
3914 win_skip("GetConsoleFontInfo is not available\n");
3915 return;
3918 pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts");
3919 if (!pGetNumberOfConsoleFonts)
3921 win_skip("GetNumberOfConsoleFonts is not available\n");
3922 return;
3925 num_fonts = pGetNumberOfConsoleFonts();
3926 memsize = num_fonts * sizeof(CONSOLE_FONT_INFO);
3927 cfi = HeapAlloc(GetProcessHeap(), 0, memsize);
3928 memset(cfi, 0, memsize);
3930 GetConsoleScreenBufferInfo(std_output, &csbi);
3931 orig_sb_size = csbi.dwSize;
3932 tmp_sb_size.X = csbi.dwSize.X + 3;
3933 tmp_sb_size.Y = csbi.dwSize.Y + 5;
3934 SetConsoleScreenBufferSize(std_output, tmp_sb_size);
3936 SetLastError(0xdeadbeef);
3937 ret = pGetConsoleFontInfo(NULL, FALSE, 0, cfi);
3938 ok(!ret, "got %d, expected zero\n", ret);
3939 if (GetLastError() == LOWORD(E_NOTIMPL) /* win10 1709+ */ ||
3940 broken(GetLastError() == ERROR_GEN_FAILURE) /* win10 1607 */)
3942 skip("GetConsoleFontInfo is not implemented\n");
3943 SetConsoleScreenBufferSize(std_output, orig_sb_size);
3944 HeapFree(GetProcessHeap(), 0, cfi);
3945 return;
3947 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3949 SetLastError(0xdeadbeef);
3950 ret = pGetConsoleFontInfo(GetStdHandle(STD_INPUT_HANDLE), FALSE, 0, cfi);
3951 ok(!ret, "got %d, expected zero\n", ret);
3952 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3954 SetLastError(0xdeadbeef);
3955 ret = pGetConsoleFontInfo(std_output, FALSE, 0, cfi);
3956 ok(!ret, "got %d, expected zero\n", ret);
3957 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3959 GetConsoleScreenBufferInfo(std_output, &csbi);
3960 win_width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
3961 win_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
3963 GetCurrentConsoleFont(std_output, FALSE, &cfi[0]);
3964 index = cfi[0].nFont;
3965 orig_font = GetConsoleFontSize(std_output, index);
3967 memset(cfi, 0, memsize);
3968 ret = pGetConsoleFontInfo(std_output, FALSE, num_fonts, cfi);
3969 ok(ret, "got %d, expected non-zero\n", ret);
3970 ok(cfi[index].dwFontSize.X == win_width, "got %d, expected %d\n",
3971 cfi[index].dwFontSize.X, win_width);
3972 ok(cfi[index].dwFontSize.Y == win_height, "got %d, expected %d\n",
3973 cfi[index].dwFontSize.Y, win_height);
3975 for (i = 0; i < num_fonts; i++)
3977 ok(cfi[i].nFont == i, "element out of order, got nFont %ld, expected %ld\n", cfi[i].nFont, i);
3978 tmp_font = GetConsoleFontSize(std_output, cfi[i].nFont);
3979 tmp_w = (double)orig_font.X / tmp_font.X * win_width;
3980 tmp_h = (double)orig_font.Y / tmp_font.Y * win_height;
3981 ok(cfi[i].dwFontSize.X == tmp_w, "got %d, expected %d\n", cfi[i].dwFontSize.X, tmp_w);
3982 ok(cfi[i].dwFontSize.Y == tmp_h, "got %d, expected %d\n", cfi[i].dwFontSize.Y, tmp_h);
3985 SetLastError(0xdeadbeef);
3986 ret = pGetConsoleFontInfo(NULL, TRUE, 0, cfi);
3987 ok(!ret, "got %d, expected zero\n", ret);
3988 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3990 SetLastError(0xdeadbeef);
3991 ret = pGetConsoleFontInfo(GetStdHandle(STD_INPUT_HANDLE), TRUE, 0, cfi);
3992 ok(!ret, "got %d, expected zero\n", ret);
3993 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3995 SetLastError(0xdeadbeef);
3996 ret = pGetConsoleFontInfo(std_output, TRUE, 0, cfi);
3997 ok(!ret, "got %d, expected zero\n", ret);
3998 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
4000 memset(cfi, 0, memsize);
4001 ret = pGetConsoleFontInfo(std_output, TRUE, num_fonts, cfi);
4002 ok(ret, "got %d, expected non-zero\n", ret);
4003 ok(cfi[index].dwFontSize.X == csbi.dwMaximumWindowSize.X, "got %d, expected %d\n",
4004 cfi[index].dwFontSize.X, csbi.dwMaximumWindowSize.X);
4005 ok(cfi[index].dwFontSize.Y == csbi.dwMaximumWindowSize.Y, "got %d, expected %d\n",
4006 cfi[index].dwFontSize.Y, csbi.dwMaximumWindowSize.Y);
4008 for (i = 0; i < num_fonts; i++)
4010 ok(cfi[i].nFont == i, "element out of order, got nFont %ld, expected %ld\n", cfi[i].nFont, i);
4011 tmp_font = GetConsoleFontSize(std_output, cfi[i].nFont);
4012 tmp_w = (double)orig_font.X / tmp_font.X * csbi.dwMaximumWindowSize.X;
4013 tmp_h = (double)orig_font.Y / tmp_font.Y * csbi.dwMaximumWindowSize.Y;
4014 ok(cfi[i].dwFontSize.X == tmp_w, "got %d, expected %d\n", cfi[i].dwFontSize.X, tmp_w);
4015 ok(cfi[i].dwFontSize.Y == tmp_h, "got %d, expected %d\n", cfi[i].dwFontSize.Y, tmp_h);
4018 HeapFree(GetProcessHeap(), 0, cfi);
4019 SetConsoleScreenBufferSize(std_output, orig_sb_size);
4022 static void test_SetConsoleFont(HANDLE std_output)
4024 HANDLE hmod;
4025 BOOL (WINAPI *pSetConsoleFont)(HANDLE, DWORD);
4026 BOOL ret;
4027 DWORD (WINAPI *pGetNumberOfConsoleFonts)(void);
4028 DWORD num_fonts;
4030 hmod = GetModuleHandleA("kernel32.dll");
4031 pSetConsoleFont = (void *)GetProcAddress(hmod, "SetConsoleFont");
4032 if (!pSetConsoleFont)
4034 win_skip("SetConsoleFont is not available\n");
4035 return;
4038 SetLastError(0xdeadbeef);
4039 ret = pSetConsoleFont(NULL, 0);
4040 ok(!ret, "got %d, expected zero\n", ret);
4041 if (GetLastError() == LOWORD(E_NOTIMPL) /* win10 1709+ */ ||
4042 broken(GetLastError() == ERROR_GEN_FAILURE) /* win10 1607 */)
4044 skip("SetConsoleFont is not implemented\n");
4045 return;
4047 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
4049 SetLastError(0xdeadbeef);
4050 ret = pSetConsoleFont(GetStdHandle(STD_INPUT_HANDLE), 0);
4051 ok(!ret, "got %d, expected zero\n", ret);
4052 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
4054 pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts");
4055 if (!pGetNumberOfConsoleFonts)
4057 win_skip("GetNumberOfConsoleFonts is not available\n");
4058 return;
4061 num_fonts = pGetNumberOfConsoleFonts();
4063 SetLastError(0xdeadbeef);
4064 ret = pSetConsoleFont(std_output, num_fonts);
4065 ok(!ret, "got %d, expected zero\n", ret);
4066 todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
4069 static void test_GetConsoleScreenBufferInfoEx(HANDLE std_output)
4071 HANDLE hmod;
4072 BOOL (WINAPI *pGetConsoleScreenBufferInfoEx)(HANDLE, CONSOLE_SCREEN_BUFFER_INFOEX *);
4073 CONSOLE_SCREEN_BUFFER_INFOEX csbix;
4074 HANDLE pipe1, pipe2;
4075 BOOL ret;
4076 HANDLE std_input = GetStdHandle(STD_INPUT_HANDLE);
4078 hmod = GetModuleHandleA("kernel32.dll");
4079 pGetConsoleScreenBufferInfoEx = (void *)GetProcAddress(hmod, "GetConsoleScreenBufferInfoEx");
4080 if (!pGetConsoleScreenBufferInfoEx)
4082 win_skip("GetConsoleScreenBufferInfoEx is not available\n");
4083 return;
4086 SetLastError(0xdeadbeef);
4087 ret = pGetConsoleScreenBufferInfoEx(NULL, &csbix);
4088 ok(!ret, "got %d, expected zero\n", ret);
4089 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
4091 SetLastError(0xdeadbeef);
4092 ret = pGetConsoleScreenBufferInfoEx(std_input, &csbix);
4093 ok(!ret, "got %d, expected zero\n", ret);
4094 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
4096 SetLastError(0xdeadbeef);
4097 ret = pGetConsoleScreenBufferInfoEx(std_output, &csbix);
4098 ok(!ret, "got %d, expected zero\n", ret);
4099 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
4101 csbix.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
4103 SetLastError(0xdeadbeef);
4104 ret = pGetConsoleScreenBufferInfoEx(NULL, &csbix);
4105 ok(!ret, "got %d, expected zero\n", ret);
4106 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
4108 SetLastError(0xdeadbeef);
4109 ret = pGetConsoleScreenBufferInfoEx(std_input, &csbix);
4110 ok(!ret, "got %d, expected zero\n", ret);
4111 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
4113 CreatePipe(&pipe1, &pipe2, NULL, 0);
4114 SetLastError(0xdeadbeef);
4115 ret = pGetConsoleScreenBufferInfoEx(std_input, &csbix);
4116 ok(!ret, "got %d, expected zero\n", ret);
4117 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
4118 CloseHandle(pipe1);
4119 CloseHandle(pipe2);
4121 SetLastError(0xdeadbeef);
4122 ret = pGetConsoleScreenBufferInfoEx(std_output, &csbix);
4123 ok(ret, "got %d, expected non-zero\n", ret);
4124 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
4127 static void test_FreeConsole(void)
4129 HANDLE handle, unbound_output = NULL, unbound_input = NULL;
4130 DWORD size, mode, type;
4131 WCHAR title[16];
4132 char buf[32];
4133 HWND hwnd;
4134 UINT cp;
4135 BOOL ret;
4137 ok(RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle != NULL, "ConsoleHandle is NULL\n");
4138 ok(!SetConsoleCtrlHandler(mydummych, FALSE), "dummy ctrl handler shouldn't be set\n");
4139 ret = SetConsoleCtrlHandler(mydummych, TRUE);
4140 ok(ret, "SetConsoleCtrlHandler failed: %lu\n", GetLastError());
4141 if (!skip_nt)
4143 unbound_input = create_unbound_handle(FALSE, TRUE);
4144 unbound_output = create_unbound_handle(TRUE, TRUE);
4147 ret = FreeConsole();
4148 ok(ret, "FreeConsole failed: %lu\n", GetLastError());
4150 ok(RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle == NULL, "ConsoleHandle = %p\n",
4151 RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle);
4153 handle = CreateFileA("CONOUT$", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
4154 ok(handle == INVALID_HANDLE_VALUE &&
4155 (GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == ERROR_ACCESS_DENIED /* winxp */)),
4156 "CreateFileA failed: %lu\n", GetLastError());
4158 handle = CreateFileA("CONIN$", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
4159 ok(handle == INVALID_HANDLE_VALUE &&
4160 (GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == ERROR_ACCESS_DENIED /* winxp */)),
4161 "CreateFileA failed: %lu\n", GetLastError());
4163 handle = CreateFileA("CON", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
4164 ok(handle == INVALID_HANDLE_VALUE &&
4165 (GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == ERROR_ACCESS_DENIED /* winxp */)),
4166 "CreateFileA failed: %lu\n", GetLastError());
4168 handle = CreateFileA("CON", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
4169 ok(handle == INVALID_HANDLE_VALUE &&
4170 (GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == ERROR_FILE_NOT_FOUND /* winxp */)),
4171 "CreateFileA failed: %lu\n", GetLastError());
4173 handle = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
4174 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
4175 CONSOLE_TEXTMODE_BUFFER, NULL);
4176 ok(handle == INVALID_HANDLE_VALUE && GetLastError() == ERROR_INVALID_HANDLE,
4177 "CreateConsoleScreenBuffer returned: %p (%lu)\n", handle, GetLastError());
4179 SetLastError(0xdeadbeef);
4180 cp = GetConsoleCP();
4181 ok(!cp, "cp = %x\n", cp);
4182 ok(GetLastError() == ERROR_INVALID_HANDLE, "last error %lu\n", GetLastError());
4184 SetLastError(0xdeadbeef);
4185 cp = GetConsoleOutputCP();
4186 ok(!cp, "cp = %x\n", cp);
4187 ok(GetLastError() == ERROR_INVALID_HANDLE, "last error %lu\n", GetLastError());
4189 SetLastError(0xdeadbeef);
4190 ret = SetConsoleCP(GetOEMCP());
4191 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "SetConsoleCP returned %x(%lu)\n", ret, GetLastError());
4193 SetLastError(0xdeadbeef);
4194 ret = SetConsoleOutputCP(GetOEMCP());
4195 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "SetConsoleCP returned %x(%lu)\n", ret, GetLastError());
4197 if (skip_nt) return;
4199 SetLastError(0xdeadbeef);
4200 memset( title, 0xc0, sizeof(title) );
4201 size = GetConsoleTitleW( title, ARRAY_SIZE(title) );
4202 ok(!size, "GetConsoleTitleW returned %lu\n", size);
4203 ok(title[0] == 0xc0c0, "title byffer changed\n");
4204 ok(GetLastError() == ERROR_INVALID_HANDLE, "last error %lu\n", GetLastError());
4206 SetLastError(0xdeadbeef);
4207 ret = SetConsoleTitleW( L"test" );
4208 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "SetConsoleTitleW returned %x(%lu)\n", ret, GetLastError());
4210 SetLastError(0xdeadbeef);
4211 hwnd = GetConsoleWindow();
4212 ok(!hwnd, "hwnd = %p\n", hwnd);
4213 ok(GetLastError() == ERROR_INVALID_HANDLE, "last error %lu\n", GetLastError());
4215 ret = GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
4216 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "GenerateConsoleCtrlEvent returned %x(%lu)\n",
4217 ret, GetLastError());
4219 SetStdHandle( STD_INPUT_HANDLE, (HANDLE)0xdeadbeef );
4220 handle = GetConsoleInputWaitHandle();
4221 ok(handle == (HANDLE)0xdeadbeef, "GetConsoleInputWaitHandle returned %p\n", handle);
4222 SetStdHandle( STD_INPUT_HANDLE, NULL );
4223 handle = GetConsoleInputWaitHandle();
4224 ok(!handle, "GetConsoleInputWaitHandle returned %p\n", handle);
4226 ret = ReadFile(unbound_input, buf, sizeof(buf), &size, NULL);
4227 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
4228 "ReadFile returned %x %lu\n", ret, GetLastError());
4230 ret = FlushFileBuffers(unbound_input);
4231 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
4232 "ReadFile returned %x %lu\n", ret, GetLastError());
4234 ret = WriteFile(unbound_input, "test", 4, &size, NULL);
4235 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
4236 "ReadFile returned %x %lu\n", ret, GetLastError());
4238 ret = GetConsoleMode(unbound_input, &mode);
4239 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
4240 "GetConsoleMode returned %x %lu\n", ret, GetLastError());
4241 ret = GetConsoleMode(unbound_output, &mode);
4242 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
4243 "GetConsoleMode returned %x %lu\n", ret, GetLastError());
4245 type = GetFileType(unbound_input);
4246 ok(type == FILE_TYPE_CHAR, "GetFileType returned %lu\n", type);
4247 type = GetFileType(unbound_output);
4248 ok(type == FILE_TYPE_CHAR, "GetFileType returned %lu\n", type);
4250 todo_wine
4251 ok(!SetConsoleCtrlHandler(mydummych, FALSE), "FreeConsole() should have reset ctrl handlers' list\n");
4253 CloseHandle(unbound_input);
4254 CloseHandle(unbound_output);
4257 static void test_SetConsoleScreenBufferInfoEx(HANDLE std_output)
4259 BOOL ret;
4260 HANDLE hmod;
4261 HANDLE std_input = CreateFileA("CONIN$", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
4262 BOOL (WINAPI *pSetConsoleScreenBufferInfoEx)(HANDLE, CONSOLE_SCREEN_BUFFER_INFOEX *);
4263 BOOL (WINAPI *pGetConsoleScreenBufferInfoEx)(HANDLE, CONSOLE_SCREEN_BUFFER_INFOEX *);
4264 CONSOLE_SCREEN_BUFFER_INFOEX info;
4266 hmod = GetModuleHandleA("kernel32.dll");
4267 pSetConsoleScreenBufferInfoEx = (void *)GetProcAddress(hmod, "SetConsoleScreenBufferInfoEx");
4268 pGetConsoleScreenBufferInfoEx = (void *)GetProcAddress(hmod, "GetConsoleScreenBufferInfoEx");
4269 if (!pSetConsoleScreenBufferInfoEx || !pGetConsoleScreenBufferInfoEx)
4271 win_skip("SetConsoleScreenBufferInfoEx is not available\n");
4272 return;
4275 memset(&info, 0, sizeof(CONSOLE_SCREEN_BUFFER_INFOEX));
4276 info.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
4277 pGetConsoleScreenBufferInfoEx(std_output, &info);
4279 SetLastError(0xdeadbeef);
4280 ret = pSetConsoleScreenBufferInfoEx(NULL, &info);
4281 ok(!ret, "got %d, expected zero\n", ret);
4282 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
4284 SetLastError(0xdeadbeef);
4285 ret = pSetConsoleScreenBufferInfoEx(std_output, &info);
4286 ok(ret, "got %d, expected one\n", ret);
4287 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
4289 SetLastError(0xdeadbeef);
4290 ret = pSetConsoleScreenBufferInfoEx(std_input, &info);
4291 ok(!ret, "got %d, expected zero\n", ret);
4292 ok(GetLastError() == ERROR_INVALID_HANDLE || GetLastError() == ERROR_ACCESS_DENIED,
4293 "got %lu, expected 5 or 6\n", GetLastError());
4295 info.cbSize = 0;
4296 SetLastError(0xdeadbeef);
4297 ret = pSetConsoleScreenBufferInfoEx(std_output, &info);
4298 ok(!ret, "got %d, expected zero\n", ret);
4299 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
4301 CloseHandle(std_input);
4304 static void test_GetConsoleOriginalTitleA(void)
4306 char title[] = "Original Console Title";
4307 char buf[64];
4308 DWORD ret, title_len = strlen(title);
4310 ret = GetConsoleOriginalTitleA(NULL, 0);
4311 ok(!ret, "Unexpected string length; error %lu\n", GetLastError());
4313 ret = GetConsoleOriginalTitleA(buf, 0);
4314 ok(!ret, "Unexpected string length; error %lu\n", GetLastError());
4316 ret = GetConsoleOriginalTitleA(buf, ARRAY_SIZE(buf));
4317 ok(ret, "GetConsoleOriginalTitleA failed: %lu\n", GetLastError());
4318 ok(!strcmp(buf, title), "got %s, expected %s\n", wine_dbgstr_a(buf), wine_dbgstr_a(title));
4319 ok(ret == title_len, "got %lu, expected %lu\n", ret, title_len);
4321 ret = SetConsoleTitleA("test");
4322 ok(ret, "SetConsoleTitleA failed: %lu\n", GetLastError());
4324 ret = GetConsoleOriginalTitleA(buf, ARRAY_SIZE(buf));
4325 ok(ret, "GetConsoleOriginalTitleA failed: %lu\n", GetLastError());
4326 ok(!strcmp(buf, title), "got %s, expected %s\n", wine_dbgstr_a(buf), wine_dbgstr_a(title));
4327 ok(ret == title_len, "got %lu, expected %lu\n", ret, title_len);
4330 static void test_GetConsoleOriginalTitleW(void)
4332 WCHAR title[] = L"Original Console Title";
4333 WCHAR buf[64];
4334 DWORD ret, title_len = lstrlenW(title);
4336 ret = GetConsoleOriginalTitleW(NULL, 0);
4337 ok(!ret, "Unexpected string length; error %lu\n", GetLastError());
4339 ret = GetConsoleOriginalTitleW(buf, 0);
4340 ok(!ret, "Unexpected string length; error %lu\n", GetLastError());
4342 ret = GetConsoleOriginalTitleW(buf, ARRAY_SIZE(buf));
4343 ok(ret, "GetConsoleOriginalTitleW failed: %lu\n", GetLastError());
4344 buf[ret] = 0;
4345 ok(!wcscmp(buf, title), "got %s, expected %s\n", wine_dbgstr_w(buf), wine_dbgstr_w(title));
4346 ok(ret == title_len, "got %lu, expected %lu\n", ret, title_len);
4348 ret = SetConsoleTitleW(L"test");
4349 ok(ret, "SetConsoleTitleW failed: %lu\n", GetLastError());
4351 ret = GetConsoleOriginalTitleW(buf, ARRAY_SIZE(buf));
4352 ok(ret, "GetConsoleOriginalTitleW failed: %lu\n", GetLastError());
4353 ok(!wcscmp(buf, title), "got %s, expected %s\n", wine_dbgstr_w(buf), wine_dbgstr_w(title));
4354 ok(ret == title_len, "got %lu, expected %lu\n", ret, title_len);
4356 ret = GetConsoleOriginalTitleW(buf, 5);
4357 ok(ret, "GetConsoleOriginalTitleW failed: %lu\n", GetLastError());
4358 ok(!wcscmp(buf, L"Orig"), "got %s, expected 'Orig'\n", wine_dbgstr_w(buf));
4359 ok(ret == title_len, "got %lu, expected %lu\n", ret, title_len);
4362 static void test_GetConsoleOriginalTitleW_empty(void)
4364 WCHAR buf[64];
4365 DWORD ret;
4367 ret = GetConsoleOriginalTitleW(buf, ARRAY_SIZE(buf));
4368 ok(!ret, "GetConsoleOriginalTitleW failed: %lu\n", GetLastError());
4371 static void test_GetConsoleOriginalTitle(void)
4373 STARTUPINFOA si = { sizeof(si) };
4374 PROCESS_INFORMATION info;
4375 char **argv, buf[MAX_PATH];
4376 char title[] = "Original Console Title";
4377 BOOL ret;
4379 winetest_get_mainargs(&argv);
4380 sprintf(buf, "\"%s\" console title_test", argv[0]);
4381 si.lpTitle = title;
4382 ret = CreateProcessA(NULL, buf, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &info);
4383 ok(ret, "CreateProcess failed: %lu\n", GetLastError());
4384 CloseHandle(info.hThread);
4385 wait_child_process(info.hProcess);
4386 CloseHandle(info.hProcess);
4388 strcat(buf, " empty");
4389 title[0] = 0;
4390 ret = CreateProcessA(NULL, buf, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &info);
4391 ok(ret, "CreateProcess failed: %lu\n", GetLastError());
4392 CloseHandle(info.hThread);
4393 wait_child_process(info.hProcess);
4394 CloseHandle(info.hProcess);
4397 static void test_GetConsoleTitleA(void)
4399 char buf[64], str[] = "test";
4400 DWORD ret;
4402 ret = SetConsoleTitleA(str);
4403 ok(ret, "SetConsoleTitleA failed: %lu\n", GetLastError());
4405 ret = GetConsoleTitleA(NULL, 0);
4406 ok(!ret, "Unexpected string length; error %lu\n", GetLastError());
4408 ret = GetConsoleTitleA(buf, 0);
4409 ok(!ret, "Unexpected string length; error %lu\n", GetLastError());
4411 ret = GetConsoleTitleA(buf, ARRAY_SIZE(buf));
4412 ok(ret, "GetConsoleTitleW failed: %lu\n", GetLastError());
4413 ok(ret == strlen(str), "Got string length %lu, expected %Iu\n", ret, strlen(str));
4414 ok(!strcmp(buf, str), "Title = %s\n", wine_dbgstr_a(buf));
4416 ret = SetConsoleTitleA("");
4417 ok(ret, "SetConsoleTitleA failed: %lu\n", GetLastError());
4419 ret = GetConsoleTitleA(buf, ARRAY_SIZE(buf));
4420 ok(!ret, "Unexpected string length; error %lu\n", GetLastError());
4423 static void test_GetConsoleTitleW(void)
4425 WCHAR buf[64], str[] = L"test";
4426 DWORD ret;
4428 ret = SetConsoleTitleW(str);
4429 ok(ret, "SetConsoleTitleW failed: %lu\n", GetLastError());
4431 ret = GetConsoleTitleW(NULL, 0);
4432 ok(!ret, "Unexpected string length; error %lu\n", GetLastError());
4434 ret = GetConsoleTitleW(buf, 0);
4435 ok(!ret, "Unexpected string length; error %lu\n", GetLastError());
4437 ret = GetConsoleTitleW(buf, ARRAY_SIZE(buf));
4438 ok(ret, "GetConsoleTitleW failed: %lu\n", GetLastError());
4439 ok(ret == wcslen(str), "Got string length %lu, expected %Iu\n", ret, wcslen(str));
4440 ok(!wcscmp(buf, str), "Title = %s\n", wine_dbgstr_w(buf));
4442 ret = GetConsoleTitleW(buf, 2);
4443 ok(ret, "GetConsoleTitleW failed: %lu\n", GetLastError());
4444 ok(ret == wcslen(str), "Got string length %lu, expected %Iu\n", ret, wcslen(str));
4445 if (!skip_nt) ok(!wcscmp(buf, L"t"), "Title = %s\n", wine_dbgstr_w(buf));
4447 ret = GetConsoleTitleW(buf, 4);
4448 ok(ret, "GetConsoleTitleW failed: %lu\n", GetLastError());
4449 ok(ret == wcslen(str), "Got string length %lu, expected %Iu\n", ret, wcslen(str));
4450 if (!skip_nt) ok(!wcscmp(buf, L"tes"), "Title = %s\n", wine_dbgstr_w(buf));
4452 ret = SetConsoleTitleW(L"");
4453 ok(ret, "SetConsoleTitleW failed: %lu\n", GetLastError());
4455 ret = GetConsoleTitleW(buf, ARRAY_SIZE(buf));
4456 ok(!ret, "Unexpected string length; error %lu\n", GetLastError());
4459 static void test_file_info(HANDLE input, HANDLE output)
4461 FILE_STANDARD_INFORMATION std_info;
4462 FILE_FS_DEVICE_INFORMATION fs_info;
4463 LARGE_INTEGER size;
4464 IO_STATUS_BLOCK io;
4465 DWORD type;
4466 NTSTATUS status;
4467 BOOL ret;
4469 if (skip_nt) return;
4471 status = NtQueryInformationFile(input, &io, &std_info, sizeof(std_info), FileStandardInformation);
4472 ok(status == STATUS_INVALID_DEVICE_REQUEST, "NtQueryInformationFile returned: %#lx\n", status);
4474 status = NtQueryInformationFile(output, &io, &std_info, sizeof(std_info), FileStandardInformation);
4475 ok(status == STATUS_INVALID_DEVICE_REQUEST, "NtQueryInformationFile returned: %#lx\n", status);
4477 ret = GetFileSizeEx(input, &size);
4478 ok(!ret && GetLastError() == ERROR_INVALID_FUNCTION,
4479 "GetFileSizeEx returned %x(%lu)\n", ret, GetLastError());
4481 ret = GetFileSizeEx(output, &size);
4482 ok(!ret && GetLastError() == ERROR_INVALID_FUNCTION,
4483 "GetFileSizeEx returned %x(%lu)\n", ret, GetLastError());
4485 status = NtQueryVolumeInformationFile(input, &io, &fs_info, sizeof(fs_info), FileFsDeviceInformation);
4486 ok(!status, "NtQueryVolumeInformationFile failed: %#lx\n", status);
4487 ok(fs_info.DeviceType == FILE_DEVICE_CONSOLE, "DeviceType = %lu\n", fs_info.DeviceType);
4488 ok(fs_info.Characteristics == FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL,
4489 "Characteristics = %lx\n", fs_info.Characteristics);
4491 status = NtQueryVolumeInformationFile(output, &io, &fs_info, sizeof(fs_info), FileFsDeviceInformation);
4492 ok(!status, "NtQueryVolumeInformationFile failed: %#lx\n", status);
4493 ok(fs_info.DeviceType == FILE_DEVICE_CONSOLE, "DeviceType = %lu\n", fs_info.DeviceType);
4494 ok(fs_info.Characteristics == FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL,
4495 "Characteristics = %lx\n", fs_info.Characteristics);
4497 type = GetFileType(input);
4498 ok(type == FILE_TYPE_CHAR, "GetFileType returned %lu\n", type);
4499 type = GetFileType(output);
4500 ok(type == FILE_TYPE_CHAR, "GetFileType returned %lu\n", type);
4503 static void test_AttachConsole_child(DWORD console_pid)
4505 HANDLE pipe_in, pipe_out;
4506 COORD c = {0,0};
4507 HANDLE console;
4508 char buf[32];
4509 DWORD len;
4510 BOOL res;
4512 res = CreatePipe(&pipe_in, &pipe_out, NULL, 0);
4513 ok(res, "CreatePipe failed: %lu\n", GetLastError());
4515 res = AttachConsole(console_pid);
4516 ok(!res && GetLastError() == ERROR_ACCESS_DENIED,
4517 "AttachConsole returned: %x(%lu)\n", res, GetLastError());
4519 ok(RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle != NULL, "ConsoleHandle is NULL\n");
4520 res = FreeConsole();
4521 ok(res, "FreeConsole failed: %lu\n", GetLastError());
4522 ok(RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle == NULL, "ConsoleHandle = %p\n",
4523 RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle);
4525 SetStdHandle(STD_ERROR_HANDLE, pipe_out);
4527 ok(!SetConsoleCtrlHandler(mydummych, FALSE), "dummy ctrl handler shouldn't be set\n");
4528 res = SetConsoleCtrlHandler(mydummych, TRUE);
4529 ok(res, "SetConsoleCtrlHandler failed: %lu\n", GetLastError());
4531 res = AttachConsole(console_pid);
4532 ok(res, "AttachConsole failed: %lu\n", GetLastError());
4534 ok(pipe_out != GetStdHandle(STD_ERROR_HANDLE), "std handle not set to console\n");
4535 ok(RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle != NULL, "ConsoleHandle is NULL\n");
4537 console = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
4538 ok(console != INVALID_HANDLE_VALUE, "Could not open console\n");
4540 res = ReadConsoleOutputCharacterA(console, buf, 6, c, &len);
4541 ok(res, "ReadConsoleOutputCharacterA failed: %lu\n", GetLastError());
4542 ok(len == 6, "len = %lu\n", len);
4543 ok(!memcmp(buf, "Parent", 6), "Unexpected console output\n");
4545 todo_wine
4546 ok(!SetConsoleCtrlHandler(mydummych, FALSE), "AttachConsole() should have reset ctrl handlers' list\n");
4548 res = FreeConsole();
4549 ok(res, "FreeConsole failed: %lu\n", GetLastError());
4551 SetStdHandle(STD_INPUT_HANDLE, pipe_in);
4552 SetStdHandle(STD_OUTPUT_HANDLE, pipe_out);
4554 res = AttachConsole(ATTACH_PARENT_PROCESS);
4555 ok(res, "AttachConsole failed: %lu\n", GetLastError());
4557 if (pGetConsoleProcessList)
4559 DWORD list[2] = { 0xbabebabe };
4560 DWORD pid = GetCurrentProcessId();
4562 SetLastError(0xdeadbeef);
4563 len = pGetConsoleProcessList(list, 1);
4564 ok(len == 2, "Expected 2 processes, got %ld\n", len);
4565 ok(list[0] == 0xbabebabe, "Unexpected value in list %lu\n", list[0]);
4567 len = pGetConsoleProcessList(list, 2);
4568 ok(len == 2, "Expected 2 processes, got %ld\n", len);
4569 ok(list[0] == console_pid || list[1] == console_pid, "Parent PID not in list\n");
4570 ok(list[0] == pid || list[1] == pid, "PID not in list\n");
4571 ok(GetLastError() == 0xdeadbeef, "Unexpected last error: %lu\n", GetLastError());
4574 ok(pipe_in != GetStdHandle(STD_INPUT_HANDLE), "std handle not set to console\n");
4575 ok(pipe_out != GetStdHandle(STD_OUTPUT_HANDLE), "std handle not set to console\n");
4577 console = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
4578 ok(console != INVALID_HANDLE_VALUE, "Could not open console\n");
4580 res = ReadConsoleOutputCharacterA(console, buf, 6, c, &len);
4581 ok(res, "ReadConsoleOutputCharacterA failed: %lu\n", GetLastError());
4582 ok(len == 6, "len = %lu\n", len);
4583 ok(!memcmp(buf, "Parent", 6), "Unexpected console output\n");
4585 simple_write_console(console, "Child");
4586 CloseHandle(console);
4588 res = FreeConsole();
4589 ok(res, "FreeConsole failed: %lu\n", GetLastError());
4591 res = CloseHandle(pipe_in);
4592 ok(res, "pipe_in is no longer valid\n");
4593 res = CloseHandle(pipe_out);
4594 ok(res, "pipe_out is no longer valid\n");
4597 static void test_AttachConsole(HANDLE console)
4599 STARTUPINFOA si = { sizeof(si) };
4600 PROCESS_INFORMATION info;
4601 char **argv, buf[MAX_PATH];
4602 COORD c = {0,0};
4603 DWORD len;
4604 BOOL res;
4606 simple_write_console(console, "Parent console");
4608 winetest_get_mainargs(&argv);
4609 sprintf(buf, "\"%s\" console attach_console %lx", argv[0], GetCurrentProcessId());
4610 res = CreateProcessA(NULL, buf, NULL, NULL, TRUE, 0, NULL, NULL, &si, &info);
4611 ok(res, "CreateProcess failed: %lu\n", GetLastError());
4612 CloseHandle(info.hThread);
4614 wait_child_process(info.hProcess);
4615 CloseHandle(info.hProcess);
4617 res = ReadConsoleOutputCharacterA(console, buf, 5, c, &len);
4618 ok(res, "ReadConsoleOutputCharacterA failed: %lu\n", GetLastError());
4619 ok(len == 5, "len = %lu\n", len);
4620 ok(!memcmp(buf, "Child", 5), "Unexpected console output\n");
4623 static void test_AllocConsole_child(void)
4625 HANDLE unbound_output;
4626 HANDLE prev_output, prev_error;
4627 STARTUPINFOW si;
4628 DWORD mode;
4629 BOOL res;
4631 GetStartupInfoW(&si);
4633 prev_output = GetStdHandle(STD_OUTPUT_HANDLE);
4634 res = DuplicateHandle(GetCurrentProcess(), prev_output, GetCurrentProcess(), &unbound_output,
4635 0, FALSE, DUPLICATE_SAME_ACCESS);
4636 ok(res, "DuplicateHandle failed: %lu\n", GetLastError());
4638 res = GetConsoleMode(unbound_output, &mode);
4639 ok(res, "GetConsoleMode failed: %lu\n", GetLastError());
4641 prev_error = GetStdHandle(STD_ERROR_HANDLE);
4642 if (si.dwFlags & STARTF_USESTDHANDLES)
4644 res = GetConsoleMode(prev_error, &mode);
4645 ok(!res && GetLastError() == ERROR_INVALID_HANDLE, "GetConsoleMode failed: %lu\n", GetLastError());
4648 FreeConsole();
4650 ok(GetStdHandle(STD_OUTPUT_HANDLE) == prev_output, "GetStdHandle(STD_OUTPUT_HANDLE) = %p\n", GetStdHandle(STD_OUTPUT_HANDLE));
4651 ok(GetStdHandle(STD_ERROR_HANDLE) == prev_error, "GetStdHandle(STD_ERROR_HANDLE) = %p\n", GetStdHandle(STD_ERROR_HANDLE));
4652 res = GetConsoleMode(unbound_output, &mode);
4653 ok(!res && GetLastError() == ERROR_INVALID_HANDLE, "GetConsoleMode failed: %lu\n", GetLastError());
4655 ok(!SetConsoleCtrlHandler(mydummych, FALSE), "dummy ctrl handler shouldn't be set\n");
4656 res = SetConsoleCtrlHandler(mydummych, TRUE);
4657 ok(res, "SetConsoleCtrlHandler failed: %lu\n", GetLastError());
4658 res = AllocConsole();
4659 ok(res, "AllocConsole failed: %lu\n", GetLastError());
4661 if (si.dwFlags & STARTF_USESTDHANDLES)
4663 ok(GetStdHandle(STD_OUTPUT_HANDLE) == prev_output, "GetStdHandle(STD_OUTPUT_HANDLE) = %p\n", GetStdHandle(STD_OUTPUT_HANDLE));
4664 ok(GetStdHandle(STD_ERROR_HANDLE) == prev_error, "GetStdHandle(STD_ERROR_HANDLE) = %p\n", GetStdHandle(STD_ERROR_HANDLE));
4667 res = GetConsoleMode(unbound_output, &mode);
4668 ok(res, "GetConsoleMode failed: %lu\n", GetLastError());
4670 todo_wine
4671 ok(!SetConsoleCtrlHandler(mydummych, FALSE), "AllocConsole() should have reset ctrl handlers' list\n");
4673 FreeConsole();
4674 SetStdHandle(STD_OUTPUT_HANDLE, NULL);
4675 SetStdHandle(STD_ERROR_HANDLE, NULL);
4676 res = AllocConsole();
4677 ok(res, "AllocConsole failed: %lu\n", GetLastError());
4679 ok(GetStdHandle(STD_OUTPUT_HANDLE) != NULL, "GetStdHandle(STD_OUTPUT_HANDLE) = %p\n", GetStdHandle(STD_OUTPUT_HANDLE));
4680 ok(GetStdHandle(STD_ERROR_HANDLE) != NULL, "GetStdHandle(STD_ERROR_HANDLE) = %p\n", GetStdHandle(STD_ERROR_HANDLE));
4682 res = GetConsoleMode(unbound_output, &mode);
4683 ok(res, "GetConsoleMode failed: %lu\n", GetLastError());
4684 res = GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &mode);
4685 ok(res, "GetConsoleMode failed: %lu\n", GetLastError());
4686 res = GetConsoleMode(GetStdHandle(STD_ERROR_HANDLE), &mode);
4687 ok(res, "GetConsoleMode failed: %lu\n", GetLastError());
4689 res = CloseHandle(unbound_output);
4690 ok(res, "CloseHandle failed: %lu\n", GetLastError());
4693 static void test_AllocConsole(void)
4695 SECURITY_ATTRIBUTES inheritable_attr = { sizeof(inheritable_attr), NULL, TRUE };
4696 STARTUPINFOA si = { sizeof(si) };
4697 PROCESS_INFORMATION info;
4698 char **argv, buf[MAX_PATH];
4699 HANDLE pipe_read, pipe_write;
4700 BOOL res;
4702 if (skip_nt) return;
4704 winetest_get_mainargs(&argv);
4705 sprintf(buf, "\"%s\" console alloc_console", argv[0]);
4706 res = CreateProcessA(NULL, buf, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &info);
4707 ok(res, "CreateProcess failed: %lu\n", GetLastError());
4708 CloseHandle(info.hThread);
4709 wait_child_process(info.hProcess);
4710 CloseHandle(info.hProcess);
4712 res = CreatePipe(&pipe_read, &pipe_write, &inheritable_attr, 0);
4713 ok(res, "CreatePipe failed: %lu\n", GetLastError());
4715 si.dwFlags = STARTF_USESTDHANDLES;
4716 si.hStdError = pipe_write;
4717 res = CreateProcessA(NULL, buf, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &info);
4718 ok(res, "CreateProcess failed: %lu\n", GetLastError());
4719 CloseHandle(info.hThread);
4720 wait_child_process(info.hProcess);
4721 CloseHandle(info.hProcess);
4723 CloseHandle(pipe_read);
4724 CloseHandle(pipe_write);
4727 static void test_pseudo_console_child(HANDLE input, HANDLE output)
4729 CONSOLE_SCREEN_BUFFER_INFO sb_info;
4730 CONSOLE_CURSOR_INFO cursor_info;
4731 DWORD mode;
4732 HWND hwnd;
4733 BOOL ret;
4735 ret = GetConsoleMode(input, &mode);
4736 ok(ret, "GetConsoleMode failed: %lu\n", GetLastError());
4737 ok(mode == (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT |
4738 ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS | ENABLE_AUTO_POSITION),
4739 "mode = %lx\n", mode);
4741 ret = SetConsoleMode(input, mode & ~ENABLE_AUTO_POSITION);
4742 ok(ret, "SetConsoleMode failed: %lu\n", GetLastError());
4744 ret = GetConsoleMode(input, &mode);
4745 ok(ret, "GetConsoleMode failed: %lu\n", GetLastError());
4746 ok(mode == (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT |
4747 ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS), "mode = %lx\n", mode);
4749 ret = SetConsoleMode(input, mode | ENABLE_AUTO_POSITION);
4750 ok(ret, "SetConsoleMode failed: %lu\n", GetLastError());
4752 ret = GetConsoleMode(output, &mode);
4753 ok(ret, "GetConsoleMode failed: %lu\n", GetLastError());
4754 mode &= ~ENABLE_VIRTUAL_TERMINAL_PROCESSING;
4755 ok(mode == (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT), "mode = %lx\n", mode);
4757 ret = SetConsoleMode(output, mode & ~ENABLE_WRAP_AT_EOL_OUTPUT);
4758 ok(ret, "SetConsoleMode failed: %lu\n", GetLastError());
4760 ret = GetConsoleMode(output, &mode);
4761 ok(ret, "GetConsoleMode failed: %lu\n", GetLastError());
4762 ok(mode == ENABLE_PROCESSED_OUTPUT, "mode = %lx\n", mode);
4764 ret = SetConsoleMode(output, mode | ENABLE_WRAP_AT_EOL_OUTPUT);
4765 ok(ret, "SetConsoleMode failed: %lu\n", GetLastError());
4767 ret = GetConsoleScreenBufferInfo(output, &sb_info);
4768 ok(ret, "GetConsoleScreenBufferInfo failed: %lu\n", GetLastError());
4769 ok(sb_info.dwSize.X == 40, "dwSize.X = %u\n", sb_info.dwSize.X);
4770 ok(sb_info.dwSize.Y == 30, "dwSize.Y = %u\n", sb_info.dwSize.Y);
4771 ok(sb_info.dwCursorPosition.X == 0, "dwCursorPosition.X = %u\n", sb_info.dwCursorPosition.X);
4772 ok(sb_info.dwCursorPosition.Y == 0, "dwCursorPosition.Y = %u\n", sb_info.dwCursorPosition.Y);
4773 ok(sb_info.wAttributes == 7, "wAttributes = %x\n", sb_info.wAttributes);
4774 ok(sb_info.srWindow.Left == 0, "srWindow.Left = %u\n", sb_info.srWindow.Left);
4775 ok(sb_info.srWindow.Top == 0, "srWindow.Top = %u\n", sb_info.srWindow.Top);
4776 ok(sb_info.srWindow.Right == 39, "srWindow.Right = %u\n", sb_info.srWindow.Right);
4777 ok(sb_info.srWindow.Bottom == 29, "srWindow.Bottom = %u\n", sb_info.srWindow.Bottom);
4778 ok(sb_info.dwMaximumWindowSize.X == 40, "dwMaximumWindowSize.X = %u\n", sb_info.dwMaximumWindowSize.X);
4779 ok(sb_info.dwMaximumWindowSize.Y == 30, "dwMaximumWindowSize.Y = %u\n", sb_info.dwMaximumWindowSize.Y);
4781 ret = GetConsoleCursorInfo(output, &cursor_info);
4782 ok(ret, "GetConsoleCursorInfo failed: %lu\n", GetLastError());
4783 ok(cursor_info.dwSize == 25, "dwSize = %lu\n", cursor_info.dwSize);
4784 ok(cursor_info.bVisible == TRUE, "bVisible = %x\n", cursor_info.bVisible);
4786 hwnd = GetConsoleWindow();
4787 ok(IsWindow(hwnd), "no console window\n");
4789 test_GetConsoleTitleA();
4790 test_GetConsoleTitleW();
4791 test_WriteConsoleInputW(input);
4794 static DWORD WINAPI read_pipe_proc( void *handle )
4796 char buf[64];
4797 DWORD size;
4798 while (ReadFile(handle, buf, sizeof(buf), &size, NULL));
4799 ok(GetLastError() == ERROR_BROKEN_PIPE, "ReadFile returned %lu\n", GetLastError());
4800 CloseHandle(handle);
4801 return 0;
4804 static void test_pseudo_console(void)
4806 STARTUPINFOEXA startup = {{ sizeof(startup) }};
4807 HANDLE console_pipe, console_pipe2, thread;
4808 char **argv, cmdline[MAX_PATH];
4809 PROCESS_INFORMATION info;
4810 HPCON pseudo_console;
4811 SIZE_T attr_size;
4812 COORD size;
4813 BOOL ret;
4814 HRESULT hres;
4816 if (!pCreatePseudoConsole)
4818 win_skip("CreatePseudoConsole not available\n");
4819 return;
4822 console_pipe = CreateNamedPipeW(L"\\\\.\\pipe\\pseudoconsoleconn", PIPE_ACCESS_DUPLEX,
4823 PIPE_WAIT | PIPE_TYPE_BYTE, 1, 4096, 4096, NMPWAIT_USE_DEFAULT_WAIT, NULL);
4824 ok(console_pipe != INVALID_HANDLE_VALUE, "CreateNamedPipeW failed: %lu\n", GetLastError());
4826 console_pipe2 = CreateFileW(L"\\\\.\\pipe\\pseudoconsoleconn", GENERIC_READ | GENERIC_WRITE, 0, NULL,
4827 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
4828 ok(console_pipe2 != INVALID_HANDLE_VALUE, "CreateFile failed: %lu\n", GetLastError());
4830 thread = CreateThread( NULL, 0, read_pipe_proc, console_pipe, 0, NULL );
4831 CloseHandle(thread);
4833 size.X = 0;
4834 size.Y = 30;
4835 hres = pCreatePseudoConsole(size, console_pipe2, console_pipe2, 0, &pseudo_console);
4836 ok(hres == E_INVALIDARG, "CreatePseudoConsole failed: %08lx\n", hres);
4838 size.X = 40;
4839 size.Y = 0;
4840 hres = pCreatePseudoConsole(size, console_pipe2, console_pipe2, 0, &pseudo_console);
4841 ok(hres == E_INVALIDARG, "CreatePseudoConsole failed: %08lx\n", hres);
4843 size.X = 40;
4844 size.Y = 30;
4845 hres = pCreatePseudoConsole(size, console_pipe2, console_pipe2, 0, &pseudo_console);
4846 ok(hres == S_OK, "CreatePseudoConsole failed: %08lx\n", hres);
4847 CloseHandle(console_pipe2);
4849 InitializeProcThreadAttributeList(NULL, 1, 0, &attr_size);
4850 startup.lpAttributeList = HeapAlloc(GetProcessHeap(), 0, attr_size);
4851 InitializeProcThreadAttributeList(startup.lpAttributeList, 1, 0, &attr_size);
4852 UpdateProcThreadAttribute(startup.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, pseudo_console,
4853 sizeof(pseudo_console), NULL, NULL);
4855 winetest_get_mainargs(&argv);
4856 sprintf(cmdline, "\"%s\" %s --pseudo-console", argv[0], argv[1]);
4857 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, &startup.StartupInfo, &info);
4858 ok(ret, "CreateProcessW failed: %lu\n", GetLastError());
4860 CloseHandle(info.hThread);
4861 HeapFree(GetProcessHeap(), 0, startup.lpAttributeList);
4862 wait_child_process(info.hProcess);
4863 CloseHandle(info.hProcess);
4865 pClosePseudoConsole(pseudo_console);
4868 /* copy an executable, but changing its subsystem */
4869 static void copy_change_subsystem(const char* in, const char* out, DWORD subsyst)
4871 BOOL ret;
4872 HANDLE hFile, hMap;
4873 void* mapping;
4874 IMAGE_NT_HEADERS *nthdr;
4876 ret = CopyFileA(in, out, FALSE);
4877 ok(ret, "Failed to copy executable %s in %s (%lu)\n", in, out, GetLastError());
4879 hFile = CreateFileA(out, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
4880 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
4881 ok(hFile != INVALID_HANDLE_VALUE, "Couldn't open file %s (%lu)\n", out, GetLastError());
4882 hMap = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
4883 ok(hMap != NULL, "Couldn't create map (%lu)\n", GetLastError());
4884 mapping = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
4885 ok(mapping != NULL, "Couldn't map (%lu)\n", GetLastError());
4886 nthdr = RtlImageNtHeader(mapping);
4887 ok(nthdr != NULL, "Cannot get NT headers out of %s\n", out);
4888 if (nthdr) nthdr->OptionalHeader.Subsystem = subsyst;
4889 ret = UnmapViewOfFile(mapping);
4890 ok(ret, "Couldn't unmap (%lu)\n", GetLastError());
4891 CloseHandle(hMap);
4892 CloseHandle(hFile);
4895 enum inheritance_model {NULL_STD, CONSOLE_STD, STARTUPINFO_STD};
4897 static DWORD check_child_console_bits(const char* exec, DWORD flags, enum inheritance_model inherit)
4899 SECURITY_ATTRIBUTES sa = {0, NULL, TRUE};
4900 STARTUPINFOA si = { sizeof(si) };
4901 PROCESS_INFORMATION info;
4902 char buf[MAX_PATH];
4903 HANDLE handle;
4904 DWORD exit_code;
4905 BOOL res;
4906 DWORD ret;
4907 BOOL inherit_handles = FALSE;
4909 sprintf(buf, "\"%s\" console check_console", exec);
4910 switch (inherit)
4912 case NULL_STD:
4913 SetStdHandle(STD_INPUT_HANDLE, NULL);
4914 SetStdHandle(STD_OUTPUT_HANDLE, NULL);
4915 SetStdHandle(STD_ERROR_HANDLE, NULL);
4916 break;
4917 case CONSOLE_STD:
4918 handle = CreateFileA("CONIN$", GENERIC_READ, 0, &sa, OPEN_EXISTING, 0, 0);
4919 ok(handle != INVALID_HANDLE_VALUE, "Couldn't create input to console\n");
4920 SetStdHandle(STD_INPUT_HANDLE, handle);
4921 handle = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
4922 ok(handle != INVALID_HANDLE_VALUE, "Couldn't create input to console\n");
4923 SetStdHandle(STD_OUTPUT_HANDLE, handle);
4924 SetStdHandle(STD_ERROR_HANDLE, handle);
4925 break;
4926 case STARTUPINFO_STD:
4927 si.dwFlags |= STARTF_USESTDHANDLES;
4928 si.hStdInput = CreateFileA("CONIN$", GENERIC_READ, 0, &sa, OPEN_EXISTING, 0, 0);
4929 ok(si.hStdInput != INVALID_HANDLE_VALUE, "Couldn't create input to console\n");
4930 si.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
4931 ok(si.hStdInput != INVALID_HANDLE_VALUE, "Couldn't create output to console\n");
4932 si.hStdError = INVALID_HANDLE_VALUE;
4933 inherit_handles = TRUE;
4934 break;
4936 res = CreateProcessA(NULL, buf, NULL, NULL, inherit_handles, flags, NULL, NULL, &si, &info);
4937 ok(res, "CreateProcess failed: %lu %s\n", GetLastError(), buf);
4938 CloseHandle(info.hThread);
4939 ret = WaitForSingleObject(info.hProcess, 30000);
4940 ok(ret == WAIT_OBJECT_0, "Could not wait for the child process: %ld le=%lu\n",
4941 ret, GetLastError());
4942 res = GetExitCodeProcess(info.hProcess, &exit_code);
4943 ok(res && exit_code <= 255, "Couldn't get exit_code\n");
4944 CloseHandle(info.hProcess);
4945 switch (inherit)
4947 case NULL_STD:
4948 break;
4949 case CONSOLE_STD:
4950 CloseHandle(GetStdHandle(STD_INPUT_HANDLE));
4951 CloseHandle(GetStdHandle(STD_OUTPUT_HANDLE));
4952 break;
4953 case STARTUPINFO_STD:
4954 CloseHandle(si.hStdInput);
4955 CloseHandle(si.hStdOutput);
4956 break;
4958 return exit_code;
4961 #define CP_WITH_CONSOLE 0x01 /* attached to a console */
4962 #define CP_WITH_HANDLE 0x02 /* child has a console handle */
4963 #define CP_WITH_WINDOW 0x04 /* child has a console window */
4964 #define CP_ALONE 0x08 /* whether child is the single process attached to console */
4965 #define CP_GROUP_LEADER 0x10 /* whether the child is the process group leader */
4966 #define CP_INPUT_VALID 0x20 /* whether StdHandle(INPUT) is a valid console handle */
4967 #define CP_OUTPUT_VALID 0x40 /* whether StdHandle(OUTPUT) is a valid console handle */
4968 #define CP_ENABLED_CTRLC 0x80 /* whether the ctrl-c handling isn't blocked */
4970 #define CP_OWN_CONSOLE (CP_WITH_CONSOLE | CP_WITH_HANDLE | CP_INPUT_VALID | CP_OUTPUT_VALID | CP_ALONE)
4971 #define CP_INH_CONSOLE (CP_WITH_CONSOLE | CP_WITH_HANDLE | CP_INPUT_VALID | CP_OUTPUT_VALID)
4973 static void test_CreateProcessCUI(void)
4975 HANDLE hstd[3];
4976 static char guiexec[MAX_PATH];
4977 static char cuiexec[MAX_PATH];
4978 char **argv;
4979 BOOL res;
4980 int i;
4981 BOOL saved_console_flags;
4983 static struct
4985 BOOL use_cui;
4986 DWORD cp_flags;
4987 enum inheritance_model inherit;
4988 DWORD expected;
4989 DWORD is_broken;
4991 no_console_tests[] =
4993 /* 0*/ {FALSE, 0, NULL_STD, 0},
4994 {FALSE, DETACHED_PROCESS, NULL_STD, 0},
4995 {FALSE, CREATE_NEW_CONSOLE, NULL_STD, 0},
4996 {FALSE, CREATE_NO_WINDOW, NULL_STD, 0},
4997 {FALSE, DETACHED_PROCESS | CREATE_NO_WINDOW, NULL_STD, 0},
4998 /* 5*/ {FALSE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, NULL_STD, 0},
5000 {TRUE, 0, NULL_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW},
5001 {TRUE, DETACHED_PROCESS, NULL_STD, 0},
5002 {TRUE, CREATE_NEW_CONSOLE, NULL_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW},
5003 {TRUE, CREATE_NO_WINDOW, NULL_STD, CP_OWN_CONSOLE},
5004 /*10*/ {TRUE, DETACHED_PROCESS | CREATE_NO_WINDOW, NULL_STD, 0},
5005 {TRUE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, NULL_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW},
5007 with_console_tests[] =
5009 /* 0*/ {FALSE, 0, NULL_STD, 0},
5010 {FALSE, DETACHED_PROCESS, NULL_STD, 0},
5011 {FALSE, CREATE_NEW_CONSOLE, NULL_STD, 0},
5012 {FALSE, CREATE_NO_WINDOW, NULL_STD, 0},
5013 {FALSE, DETACHED_PROCESS | CREATE_NO_WINDOW, NULL_STD, 0},
5014 /* 5*/ {FALSE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, NULL_STD, 0},
5016 {FALSE, 0, CONSOLE_STD, 0},
5017 {FALSE, DETACHED_PROCESS, CONSOLE_STD, 0},
5018 {FALSE, CREATE_NEW_CONSOLE, CONSOLE_STD, 0},
5019 {FALSE, CREATE_NO_WINDOW, CONSOLE_STD, 0},
5020 /*10*/ {FALSE, DETACHED_PROCESS | CREATE_NO_WINDOW, CONSOLE_STD, 0},
5021 {FALSE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, CONSOLE_STD, 0},
5023 {FALSE, 0, STARTUPINFO_STD, 0},
5024 {FALSE, DETACHED_PROCESS, STARTUPINFO_STD, 0},
5025 {FALSE, CREATE_NEW_CONSOLE, STARTUPINFO_STD, 0},
5026 /*15*/ {FALSE, CREATE_NO_WINDOW, STARTUPINFO_STD, 0},
5027 {FALSE, DETACHED_PROCESS | CREATE_NO_WINDOW, STARTUPINFO_STD, 0},
5028 {FALSE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, STARTUPINFO_STD, 0},
5030 {TRUE, 0, NULL_STD, CP_WITH_CONSOLE | CP_WITH_HANDLE | CP_WITH_WINDOW},
5031 {TRUE, DETACHED_PROCESS, NULL_STD, 0},
5032 /*20*/ {TRUE, CREATE_NEW_CONSOLE, NULL_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW},
5033 {TRUE, CREATE_NO_WINDOW, NULL_STD, CP_OWN_CONSOLE},
5034 {TRUE, DETACHED_PROCESS | CREATE_NO_WINDOW, NULL_STD, 0},
5035 {TRUE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, NULL_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW},
5037 {TRUE, 0, CONSOLE_STD, CP_INH_CONSOLE | CP_WITH_WINDOW},
5038 /*25*/ {TRUE, DETACHED_PROCESS, CONSOLE_STD, 0},
5039 {TRUE, CREATE_NEW_CONSOLE, CONSOLE_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW},
5040 {TRUE, CREATE_NO_WINDOW, CONSOLE_STD, CP_OWN_CONSOLE},
5041 {TRUE, DETACHED_PROCESS | CREATE_NO_WINDOW, CONSOLE_STD, 0},
5042 {TRUE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, CONSOLE_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW},
5044 /*30*/ {TRUE, 0, STARTUPINFO_STD, CP_INH_CONSOLE | CP_WITH_WINDOW},
5045 {TRUE, DETACHED_PROCESS, STARTUPINFO_STD, CP_INPUT_VALID | CP_OUTPUT_VALID, .is_broken = 0x100},
5046 {TRUE, CREATE_NEW_CONSOLE, STARTUPINFO_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW, .is_broken = CP_WITH_CONSOLE | CP_WITH_HANDLE | CP_WITH_WINDOW | CP_ALONE},
5047 {TRUE, CREATE_NO_WINDOW, STARTUPINFO_STD, CP_OWN_CONSOLE, .is_broken = CP_WITH_CONSOLE | CP_WITH_HANDLE | CP_ALONE},
5048 {TRUE, DETACHED_PROCESS | CREATE_NO_WINDOW, STARTUPINFO_STD, CP_INPUT_VALID | CP_OUTPUT_VALID, .is_broken = 0x100},
5049 /*35*/ {TRUE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, STARTUPINFO_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW, .is_broken = CP_WITH_CONSOLE | CP_WITH_HANDLE | CP_WITH_WINDOW | CP_ALONE},
5051 static struct group_flags_tests
5053 /* input */
5054 BOOL use_cui;
5055 DWORD cp_flags;
5056 enum inheritance_model inherit;
5057 BOOL noctrl_flag;
5058 /* output */
5059 DWORD expected;
5061 group_flags_tests[] =
5063 /* 0 */ {TRUE, 0, CONSOLE_STD, TRUE, CP_INH_CONSOLE | CP_WITH_WINDOW},
5064 {TRUE, CREATE_NEW_PROCESS_GROUP, CONSOLE_STD, TRUE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_GROUP_LEADER},
5065 {TRUE, 0, CONSOLE_STD, FALSE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_ENABLED_CTRLC},
5066 {TRUE, CREATE_NEW_PROCESS_GROUP, CONSOLE_STD, FALSE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_GROUP_LEADER},
5067 {TRUE, 0, STARTUPINFO_STD, TRUE, CP_INH_CONSOLE | CP_WITH_WINDOW},
5068 /* 5 */ {TRUE, CREATE_NEW_PROCESS_GROUP, STARTUPINFO_STD, TRUE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_GROUP_LEADER},
5069 {TRUE, 0, STARTUPINFO_STD, FALSE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_ENABLED_CTRLC},
5070 {TRUE, CREATE_NEW_PROCESS_GROUP, STARTUPINFO_STD, FALSE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_GROUP_LEADER},
5071 {FALSE, 0, CONSOLE_STD, TRUE, 0},
5072 {FALSE, CREATE_NEW_PROCESS_GROUP, CONSOLE_STD, TRUE, CP_GROUP_LEADER},
5073 /* 10 */ {FALSE, 0, CONSOLE_STD, FALSE, CP_ENABLED_CTRLC},
5074 {FALSE, CREATE_NEW_PROCESS_GROUP, CONSOLE_STD, FALSE, CP_GROUP_LEADER},
5075 {FALSE, 0, STARTUPINFO_STD, TRUE, 0},
5076 {FALSE, CREATE_NEW_PROCESS_GROUP, STARTUPINFO_STD, TRUE, CP_GROUP_LEADER},
5077 {FALSE, 0, STARTUPINFO_STD, FALSE, CP_ENABLED_CTRLC},
5078 /* 15 */ {FALSE, CREATE_NEW_PROCESS_GROUP, STARTUPINFO_STD, FALSE, CP_GROUP_LEADER},
5079 {TRUE, CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE, CONSOLE_STD, TRUE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_GROUP_LEADER | CP_ALONE},
5080 {FALSE, CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE, CONSOLE_STD, TRUE, CP_GROUP_LEADER},
5081 {TRUE, CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE, CONSOLE_STD, FALSE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_GROUP_LEADER | CP_ALONE | CP_ENABLED_CTRLC},
5082 {FALSE, CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE, CONSOLE_STD, FALSE, CP_GROUP_LEADER | CP_ENABLED_CTRLC},
5083 /* 20 */ {TRUE, CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, CONSOLE_STD, TRUE, CP_GROUP_LEADER},
5084 {FALSE, CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, CONSOLE_STD, TRUE, CP_GROUP_LEADER},
5085 {TRUE, CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, CONSOLE_STD, FALSE, CP_GROUP_LEADER},
5086 {FALSE, CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, CONSOLE_STD, FALSE, CP_GROUP_LEADER},
5089 hstd[0] = GetStdHandle(STD_INPUT_HANDLE);
5090 hstd[1] = GetStdHandle(STD_OUTPUT_HANDLE);
5091 hstd[2] = GetStdHandle(STD_ERROR_HANDLE);
5093 winetest_get_mainargs(&argv);
5094 GetTempPathA(ARRAY_SIZE(guiexec), guiexec);
5095 strcat(guiexec, "console_gui.exe");
5096 copy_change_subsystem(argv[0], guiexec, IMAGE_SUBSYSTEM_WINDOWS_GUI);
5097 GetTempPathA(ARRAY_SIZE(cuiexec), cuiexec);
5098 strcat(cuiexec, "console_cui.exe");
5099 copy_change_subsystem(argv[0], cuiexec, IMAGE_SUBSYSTEM_WINDOWS_CUI);
5101 FreeConsole();
5103 for (i = 0; i < ARRAY_SIZE(no_console_tests); i++)
5105 res = check_child_console_bits(no_console_tests[i].use_cui ? cuiexec : guiexec,
5106 no_console_tests[i].cp_flags,
5107 no_console_tests[i].inherit);
5108 ok(res == no_console_tests[i].expected, "[%d] Unexpected result %x (%lx)\n",
5109 i, res, no_console_tests[i].expected);
5112 AllocConsole();
5114 for (i = 0; i < ARRAY_SIZE(with_console_tests); i++)
5116 res = check_child_console_bits(with_console_tests[i].use_cui ? cuiexec : guiexec,
5117 with_console_tests[i].cp_flags,
5118 with_console_tests[i].inherit);
5119 ok(res == with_console_tests[i].expected ||
5120 broken(with_console_tests[i].is_broken && res == (with_console_tests[i].is_broken & 0xff)),
5121 "[%d] Unexpected result %x (%lx)\n",
5122 i, res, with_console_tests[i].expected);
5125 saved_console_flags = RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags;
5127 for (i = 0; i < ARRAY_SIZE(group_flags_tests); i++)
5129 res = SetConsoleCtrlHandler(NULL, group_flags_tests[i].noctrl_flag);
5130 ok(res, "Couldn't set ctrl handler\n");
5131 res = check_child_console_bits(group_flags_tests[i].use_cui ? cuiexec : guiexec,
5132 group_flags_tests[i].cp_flags,
5133 group_flags_tests[i].inherit);
5134 ok(res == group_flags_tests[i].expected ||
5135 /* Win7 doesn't report group id */
5136 broken(res == (group_flags_tests[i].expected & ~CP_GROUP_LEADER)),
5137 "[%d] Unexpected result %x (%lx)\n",
5138 i, res, group_flags_tests[i].expected);
5141 RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags = saved_console_flags;
5143 DeleteFileA(guiexec);
5144 DeleteFileA(cuiexec);
5146 SetStdHandle(STD_INPUT_HANDLE, hstd[0]);
5147 SetStdHandle(STD_OUTPUT_HANDLE, hstd[1]);
5148 SetStdHandle(STD_ERROR_HANDLE, hstd[2]);
5151 #define NO_EVENT 0xfe
5153 static HANDLE mch_child_kill_event;
5154 static DWORD mch_child_event = NO_EVENT;
5155 static BOOL WINAPI mch_child(DWORD event)
5157 mch_child_event = event;
5158 SetEvent(mch_child_kill_event);
5159 return TRUE;
5162 static void test_CtrlHandlerSubsystem(void)
5164 static char guiexec[MAX_PATH];
5165 static char cuiexec[MAX_PATH];
5167 static struct
5169 /* input */
5170 BOOL use_cui;
5171 DWORD cp_flags;
5172 enum pgid {PGID_PARENT, PGID_ZERO, PGID_CHILD} pgid_kind;
5173 /* output */
5174 unsigned child_event;
5176 tests[] =
5178 /* 0 */ {FALSE, 0, PGID_PARENT, NO_EVENT},
5179 {FALSE, 0, PGID_ZERO, NO_EVENT},
5180 {FALSE, CREATE_NEW_PROCESS_GROUP, PGID_CHILD, NO_EVENT},
5181 {FALSE, CREATE_NEW_PROCESS_GROUP, PGID_PARENT, NO_EVENT},
5182 {FALSE, CREATE_NEW_PROCESS_GROUP, PGID_ZERO, NO_EVENT},
5183 /* 5 */ {TRUE, 0, PGID_PARENT, CTRL_C_EVENT},
5184 {TRUE, 0, PGID_ZERO, CTRL_C_EVENT},
5185 {TRUE, CREATE_NEW_PROCESS_GROUP, PGID_CHILD, NO_EVENT},
5186 {TRUE, CREATE_NEW_PROCESS_GROUP, PGID_PARENT, NO_EVENT},
5187 {TRUE, CREATE_NEW_PROCESS_GROUP, PGID_ZERO, NO_EVENT},
5188 /* 10 */ {TRUE, CREATE_NEW_CONSOLE, PGID_PARENT, NO_EVENT},
5189 {TRUE, CREATE_NEW_CONSOLE, PGID_ZERO, NO_EVENT},
5190 {TRUE, DETACHED_PROCESS, PGID_PARENT, NO_EVENT},
5191 {TRUE, DETACHED_PROCESS, PGID_ZERO, NO_EVENT},
5193 SECURITY_ATTRIBUTES inheritable_attr = { sizeof(inheritable_attr), NULL, TRUE };
5194 STARTUPINFOA si = { sizeof(si) };
5195 PROCESS_INFORMATION info;
5196 char buf[MAX_PATH];
5197 DWORD exit_code;
5198 HANDLE event_child;
5199 char **argv;
5200 DWORD saved_console_flags;
5201 DWORD pgid;
5202 BOOL ret;
5203 DWORD res;
5204 int i;
5206 winetest_get_mainargs(&argv);
5207 GetTempPathA(ARRAY_SIZE(guiexec), guiexec);
5208 strcat(guiexec, "console_gui.exe");
5209 copy_change_subsystem(argv[0], guiexec, IMAGE_SUBSYSTEM_WINDOWS_GUI);
5210 GetTempPathA(ARRAY_SIZE(cuiexec), cuiexec);
5211 strcat(cuiexec, "console_cui.exe");
5212 copy_change_subsystem(argv[0], cuiexec, IMAGE_SUBSYSTEM_WINDOWS_CUI);
5214 event_child = CreateEventA(&inheritable_attr, FALSE, FALSE, NULL);
5215 ok(event_child != NULL, "Couldn't create event\n");
5217 saved_console_flags = RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags;
5219 /* protect self against ctrl-c, but don't mask it on child */
5220 ret = SetConsoleCtrlHandler(NULL, FALSE);
5221 ret = SetConsoleCtrlHandler(mydummych, TRUE);
5222 ok(ret, "Couldn't set ctrl-c handler flag\n");
5224 for (i = 0; i < ARRAY_SIZE(tests); i++)
5226 winetest_push_context("test #%u", i);
5228 res = snprintf(buf, ARRAY_SIZE(buf), "\"%s\" console ctrl_handler %p", tests[i].use_cui ? cuiexec : guiexec, event_child);
5229 ok((LONG)res >= 0 && res < ARRAY_SIZE(buf), "Truncated string %s (%lu)\n", buf, res);
5231 ret = CreateProcessA(NULL, buf, NULL, NULL, TRUE, tests[i].cp_flags,
5232 NULL, NULL, &si, &info);
5233 ok(ret, "CreateProcess failed: %lu %s\n", GetLastError(), tests[i].use_cui ? cuiexec : guiexec);
5235 res = WaitForSingleObject(event_child, 5000);
5236 ok(res == WAIT_OBJECT_0, "Child didn't init %lu %p\n", res, event_child);
5238 switch (tests[i].pgid_kind)
5240 case PGID_PARENT:
5241 pgid = RtlGetCurrentPeb()->ProcessParameters->ProcessGroupId;
5242 break;
5243 case PGID_CHILD:
5244 ok((tests[i].cp_flags & CREATE_NEW_PROCESS_GROUP) != 0,
5245 "PGID should only be used with new process groupw\n");
5246 pgid = info.dwProcessId;
5247 break;
5248 case PGID_ZERO:
5249 pgid = 0;
5250 break;
5251 default:
5252 ok(0, "Unexpected pgid kind %u\n", tests[i].pgid_kind);
5253 pgid = 0;
5256 ret = GenerateConsoleCtrlEvent(CTRL_C_EVENT, pgid);
5257 ok(ret || broken(GetLastError() == ERROR_INVALID_PARAMETER) /* Win7 */,
5258 "GenerateConsoleCtrlEvent failed: %lu\n", GetLastError());
5260 res = WaitForSingleObject(info.hProcess, 2000);
5261 ok(res == WAIT_OBJECT_0, "Expecting child to be terminated\n");
5263 if (ret)
5265 ret = GetExitCodeProcess(info.hProcess, &exit_code);
5266 ok(ret, "Couldn't get exit code\n");
5268 ok(tests[i].child_event == exit_code, "Unexpected exit code %#lx, instead of %#x\n",
5269 exit_code, tests[i].child_event);
5272 CloseHandle(info.hProcess);
5273 CloseHandle(info.hThread);
5274 winetest_pop_context();
5277 CloseHandle(event_child);
5279 RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags = saved_console_flags;
5280 ret = SetConsoleCtrlHandler(mydummych, FALSE);
5281 ok(ret, "Couldn't remove ctrl-c handler flag\n");
5283 DeleteFileA(guiexec);
5284 DeleteFileA(cuiexec);
5287 START_TEST(console)
5289 HANDLE hConIn, hConOut, revert_output = NULL, unbound_output;
5290 BOOL ret, test_current;
5291 CONSOLE_SCREEN_BUFFER_INFO sbi;
5292 BOOL using_pseudo_console;
5293 DWORD size;
5294 char **argv;
5295 int argc;
5297 init_function_pointers();
5299 argc = winetest_get_mainargs(&argv);
5301 if (argc > 3 && !strcmp(argv[2], "attach_console"))
5303 DWORD parent_pid;
5304 sscanf(argv[3], "%lx", &parent_pid);
5305 test_AttachConsole_child(parent_pid);
5306 return;
5309 if (argc == 3 && !strcmp(argv[2], "alloc_console"))
5311 test_AllocConsole_child();
5312 return;
5315 if (argc == 4 && !strcmp(argv[2], "ctrl_handler"))
5317 HANDLE event;
5319 SetConsoleCtrlHandler(mch_child, TRUE);
5320 mch_child_kill_event = CreateEventA(NULL, FALSE, FALSE, NULL);
5321 ok(mch_child_kill_event != NULL, "Couldn't create event\n");
5322 sscanf(argv[3], "%p", &event);
5323 ret = SetEvent(event);
5324 ok(ret, "SetEvent failed\n");
5326 WaitForSingleObject(mch_child_kill_event, 1000); /* enough for all events to be distributed? */
5327 ExitProcess(mch_child_event);
5330 if (argc == 3 && !strcmp(argv[2], "check_console"))
5332 DWORD exit_code = 0, pcslist;
5333 if (GetConsoleCP() != 0) exit_code |= CP_WITH_CONSOLE;
5334 if (RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle) exit_code |= CP_WITH_HANDLE;
5335 if (IsWindow(GetConsoleWindow())) exit_code |= CP_WITH_WINDOW;
5336 if (pGetConsoleProcessList && GetConsoleProcessList(&pcslist, 1) == 1)
5337 exit_code |= CP_ALONE;
5338 if (RtlGetCurrentPeb()->ProcessParameters->Size >=
5339 offsetof(RTL_USER_PROCESS_PARAMETERS, ProcessGroupId) +
5340 sizeof(RtlGetCurrentPeb()->ProcessParameters->ProcessGroupId) &&
5341 RtlGetCurrentPeb()->ProcessParameters->ProcessGroupId == GetCurrentProcessId())
5342 exit_code |= CP_GROUP_LEADER;
5343 if (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR)
5344 exit_code |= CP_INPUT_VALID;
5345 if (GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)) == FILE_TYPE_CHAR)
5346 exit_code |= CP_OUTPUT_VALID;
5347 if (!(RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags & 1))
5348 exit_code |= CP_ENABLED_CTRLC;
5349 ExitProcess(exit_code);
5352 if (argc >= 3 && !strcmp(argv[2], "title_test"))
5354 if (argc == 3)
5356 test_GetConsoleOriginalTitleA();
5357 test_GetConsoleOriginalTitleW();
5359 else
5360 test_GetConsoleOriginalTitleW_empty();
5361 return;
5364 test_current = argc >= 3 && !strcmp(argv[2], "--current");
5365 using_pseudo_console = argc >= 3 && !strcmp(argv[2], "--pseudo-console");
5367 if (!test_current && !using_pseudo_console)
5369 static const char font_name[] = "Lucida Console";
5370 HKEY console_key;
5371 char old_font[LF_FACESIZE];
5372 BOOL delete = FALSE;
5373 LONG err;
5375 /* ReadConsoleOutputW doesn't retrieve characters from the output buffer
5376 * correctly for characters that don't have a glyph in the console font. So,
5377 * we first set the console font to Lucida Console (which has a wider
5378 * selection of glyphs available than the default raster fonts). We want
5379 * to be able to restore the original font afterwards, so don't change
5380 * if we can't read the original font.
5382 err = RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
5383 KEY_QUERY_VALUE | KEY_SET_VALUE, &console_key);
5384 if (err == ERROR_SUCCESS)
5386 size = sizeof(old_font);
5387 err = RegQueryValueExA(console_key, "FaceName", NULL, NULL,
5388 (LPBYTE) old_font, &size);
5389 if (err == ERROR_SUCCESS || err == ERROR_FILE_NOT_FOUND)
5391 delete = (err == ERROR_FILE_NOT_FOUND);
5392 err = RegSetValueExA(console_key, "FaceName", 0, REG_SZ,
5393 (const BYTE *) font_name, sizeof(font_name));
5394 if (err != ERROR_SUCCESS)
5395 trace("Unable to change default console font, error %ld\n", err);
5397 else
5399 trace("Unable to query default console font, error %ld\n", err);
5400 RegCloseKey(console_key);
5401 console_key = NULL;
5404 else
5406 trace("Unable to open HKCU\\Console, error %ld\n", err);
5407 console_key = NULL;
5410 /* Now detach and open a fresh console to play with */
5411 FreeConsole();
5412 ok(AllocConsole(), "Couldn't alloc console\n");
5414 /* Restore default console font if needed */
5415 if (console_key != NULL)
5417 if (delete)
5418 err = RegDeleteValueA(console_key, "FaceName");
5419 else
5420 err = RegSetValueExA(console_key, "FaceName", 0, REG_SZ,
5421 (const BYTE *) old_font, strlen(old_font) + 1);
5422 ok(err == ERROR_SUCCESS, "Unable to restore default console font, error %ld\n", err);
5426 unbound_output = create_unbound_handle(TRUE, FALSE);
5427 if (!unbound_output)
5429 win_skip("Skipping NT path tests, not supported on this Windows version\n");
5430 skip_nt = TRUE;
5433 if (test_current)
5435 HANDLE sb;
5436 revert_output = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
5437 sb = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
5438 CONSOLE_TEXTMODE_BUFFER, NULL);
5439 ok(sb != INVALID_HANDLE_VALUE, "Could not allocate screen buffer: %lu\n", GetLastError());
5440 SetConsoleActiveScreenBuffer(sb);
5443 hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
5444 hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
5446 /* now verify everything's ok */
5447 ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n");
5448 ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n");
5450 if (using_pseudo_console)
5452 test_pseudo_console_child(hConIn, hConOut);
5453 return;
5456 ret = GetConsoleScreenBufferInfo(hConOut, &sbi);
5457 ok(ret, "Getting sb info\n");
5458 if (!ret) return;
5460 /* Reduce the size of the buffer to the visible area plus 3 lines to speed
5461 * up the tests.
5463 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);
5464 sbi.dwSize.Y = size = (sbi.srWindow.Bottom + 1) + 3;
5465 ret = SetConsoleScreenBufferSize(hConOut, sbi.dwSize);
5466 ok(ret, "Setting sb info\n");
5467 ret = GetConsoleScreenBufferInfo(hConOut, &sbi);
5468 ok(ret, "Getting sb info\n");
5469 ok(sbi.dwSize.Y == size, "Unexpected buffer size: %d instead of %ld\n", sbi.dwSize.Y, size);
5470 if (!ret) return;
5472 test_ReadConsole(hConIn);
5473 /* Non interactive tests */
5474 testCursor(hConOut, sbi.dwSize);
5475 /* test parameters (FIXME: test functionality) */
5476 testCursorInfo(hConOut);
5477 /* will test wrapped (on/off) & processed (on/off) strings output */
5478 testWrite(hConOut, sbi.dwSize);
5479 /* will test line scrolling at the bottom of the screen */
5480 /* testBottomScroll(); */
5481 /* will test all the scrolling operations */
5482 testScroll(hConOut, sbi.dwSize);
5483 /* will test sb creation / modification / codepage handling */
5484 if (!test_current) testScreenBuffer(hConOut);
5485 test_new_screen_buffer_properties(hConOut);
5486 test_new_screen_buffer_color_attributes(hConOut);
5487 /* Test waiting for a console handle */
5488 testWaitForConsoleInput(hConIn);
5489 test_wait(hConIn, hConOut);
5491 if (!test_current)
5493 /* clear duplicated console font table */
5494 CloseHandle(hConIn);
5495 CloseHandle(hConOut);
5496 FreeConsole();
5497 ok(AllocConsole(), "Couldn't alloc console\n");
5498 hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
5499 hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
5500 ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n");
5501 ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n");
5504 testCtrlHandler();
5505 /* still to be done: access rights & access on objects */
5507 if (!pGetConsoleInputExeNameA || !pSetConsoleInputExeNameA)
5508 win_skip("GetConsoleInputExeNameA and/or SetConsoleInputExeNameA is not available\n");
5509 else
5510 test_GetSetConsoleInputExeName();
5512 if (!test_current) test_GetConsoleProcessList();
5513 test_OpenConsoleW();
5514 test_CreateFileW();
5515 test_OpenCON();
5516 test_VerifyConsoleIoHandle(hConOut);
5517 test_GetSetStdHandle();
5518 test_DuplicateConsoleHandle();
5519 test_GetNumberOfConsoleInputEvents(hConIn);
5520 test_WriteConsoleInputA(hConIn);
5521 test_WriteConsoleInputW(hConIn);
5522 test_FlushConsoleInputBuffer(hConIn, hConOut);
5523 test_WriteConsoleOutputCharacterA(hConOut);
5524 test_WriteConsoleOutputCharacterW(hConOut);
5525 test_WriteConsoleOutputAttribute(hConOut);
5526 test_WriteConsoleOutput(hConOut);
5527 test_FillConsoleOutputCharacterA(hConOut);
5528 test_FillConsoleOutputCharacterW(hConOut);
5529 test_FillConsoleOutputAttribute(hConOut);
5530 test_ReadConsoleOutputCharacterA(hConOut);
5531 test_ReadConsoleOutputCharacterW(hConOut);
5532 test_ReadConsoleOutputAttribute(hConOut);
5533 test_ReadConsoleOutput(hConOut);
5534 if (!test_current)
5536 test_GetCurrentConsoleFont(hConOut);
5537 test_GetCurrentConsoleFontEx(hConOut);
5538 test_SetCurrentConsoleFontEx(hConOut);
5539 test_GetConsoleFontSize(hConOut);
5540 test_GetLargestConsoleWindowSize(hConOut);
5541 test_GetConsoleFontInfo(hConOut);
5542 test_SetConsoleFont(hConOut);
5544 test_GetConsoleScreenBufferInfoEx(hConOut);
5545 test_SetConsoleScreenBufferInfoEx(hConOut);
5546 test_file_info(hConIn, hConOut);
5547 test_GetConsoleOriginalTitle();
5548 test_GetConsoleTitleA();
5549 test_GetConsoleTitleW();
5550 if (!test_current)
5552 test_pseudo_console();
5553 test_AttachConsole(hConOut);
5554 test_AllocConsole();
5555 test_FreeConsole();
5556 test_CreateProcessCUI();
5557 test_CtrlHandlerSubsystem();
5559 else if (revert_output) SetConsoleActiveScreenBuffer(revert_output);
5561 CloseHandle(unbound_output);