Reactos
1/*
2 * Unit tests for console API
3 *
4 * Copyright (c) 2003,2004 Eric Pouech
5 * Copyright (c) 2007 Kirill K. Smirnov
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22#include <ntstatus.h>
23#define WIN32_NO_STATUS
24#include <windows.h>
25#include <winternl.h>
26#include <winioctl.h>
27#include <stdio.h>
28
29#include "wine/test.h"
30#ifdef __REACTOS__
31#include "winehacks.h"
32#endif
33
34static void (WINAPI *pClosePseudoConsole)(HPCON);
35static HRESULT (WINAPI *pCreatePseudoConsole)(COORD,HANDLE,HANDLE,DWORD,HPCON*);
36static BOOL (WINAPI *pGetConsoleInputExeNameA)(DWORD, LPSTR);
37static DWORD (WINAPI *pGetConsoleProcessList)(LPDWORD, DWORD);
38static HANDLE (WINAPI *pOpenConsoleW)(LPCWSTR,DWORD,BOOL,DWORD);
39static BOOL (WINAPI *pSetConsoleInputExeNameA)(LPCSTR);
40static BOOL (WINAPI *pVerifyConsoleIoHandle)(HANDLE handle);
41
42static BOOL skip_nt;
43
44/* DEFAULT_ATTRIB is used for all initial filling of the console.
45 * all modifications are made with TEST_ATTRIB so that we could check
46 * what has to be modified or not
47 */
48#define TEST_ATTRIB (BACKGROUND_BLUE | FOREGROUND_GREEN)
49#define DEFAULT_ATTRIB (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED)
50/* when filling the screen with non-blank chars, this macro defines
51 * what character should be at position 'c'
52 */
53#define CONTENT(c) ('A' + (((c).Y * 17 + (c).X) % 23))
54
55#define okCURSOR(hCon, c) do { \
56 CONSOLE_SCREEN_BUFFER_INFO __sbi; \
57 BOOL expect = GetConsoleScreenBufferInfo((hCon), &__sbi) && \
58 __sbi.dwCursorPosition.X == (c).X && __sbi.dwCursorPosition.Y == (c).Y; \
59 ok(expect, "Expected cursor at (%d,%d), got (%d,%d)\n", \
60 (c).X, (c).Y, __sbi.dwCursorPosition.X, __sbi.dwCursorPosition.Y); \
61} while (0)
62
63#define okCHAR(hCon, c, ch, attr) do { \
64 char __ch; WORD __attr; DWORD __len; BOOL expect; \
65 expect = ReadConsoleOutputCharacterA((hCon), &__ch, 1, (c), &__len) == 1 && __len == 1 && __ch == (ch); \
66 ok(expect, "At (%d,%d): expecting char '%c'/%02x got '%c'/%02x\n", (c).X, (c).Y, (ch), (ch), __ch, __ch); \
67 expect = ReadConsoleOutputAttribute((hCon), &__attr, 1, (c), &__len) == 1 && __len == 1 && __attr == (attr); \
68 ok(expect, "At (%d,%d): expecting attr %04x got %04x\n", (c).X, (c).Y, (attr), __attr); \
69} while (0)
70
71static void init_function_pointers(void)
72{
73 HMODULE hKernel32;
74
75#define KERNEL32_GET_PROC(func) \
76 p##func = (void *)GetProcAddress(hKernel32, #func); \
77 if(!p##func) trace("GetProcAddress(hKernel32, '%s') failed\n", #func);
78
79 hKernel32 = GetModuleHandleA("kernel32.dll");
80 KERNEL32_GET_PROC(ClosePseudoConsole);
81 KERNEL32_GET_PROC(CreatePseudoConsole);
82 KERNEL32_GET_PROC(GetConsoleInputExeNameA);
83 KERNEL32_GET_PROC(GetConsoleProcessList);
84 KERNEL32_GET_PROC(OpenConsoleW);
85 KERNEL32_GET_PROC(SetConsoleInputExeNameA);
86 KERNEL32_GET_PROC(VerifyConsoleIoHandle);
87
88#undef KERNEL32_GET_PROC
89}
90
91static HANDLE create_unbound_handle(BOOL output, BOOL test_status)
92{
93 OBJECT_ATTRIBUTES attr = {sizeof(attr)};
94 IO_STATUS_BLOCK iosb;
95 UNICODE_STRING name;
96 HANDLE handle;
97 NTSTATUS status;
98
99 attr.ObjectName = &name;
100 attr.Attributes = OBJ_INHERIT;
101 RtlInitUnicodeString( &name, output ? L"\\Device\\ConDrv\\Output" : L"\\Device\\ConDrv\\Input" );
102 status = NtCreateFile( &handle, FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE | FILE_READ_ATTRIBUTES |
103 FILE_WRITE_ATTRIBUTES, &attr, &iosb, NULL, FILE_ATTRIBUTE_NORMAL,
104 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_CREATE,
105 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
106 if (test_status) ok(!status, "NtCreateFile failed: %#lx\n", status);
107 return status ? NULL : handle;
108}
109
110/* FIXME: this could be optimized on a speed point of view */
111static void resetContent(HANDLE hCon, COORD sbSize, BOOL content)
112{
113 COORD c;
114 WORD attr = DEFAULT_ATTRIB;
115 char ch;
116 DWORD len;
117
118 for (c.X = 0; c.X < sbSize.X; c.X++)
119 {
120 for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
121 {
122 ch = (content) ? CONTENT(c) : ' ';
123 WriteConsoleOutputAttribute(hCon, &attr, 1, c, &len);
124 WriteConsoleOutputCharacterA(hCon, &ch, 1, c, &len);
125 }
126 }
127}
128
129/* dummy console ctrl handler to test reset of ctrl handler's list */
130static BOOL WINAPI mydummych(DWORD event)
131{
132 return TRUE;
133}
134
135static void testCursor(HANDLE hCon, COORD sbSize)
136{
137 COORD c;
138
139 c.X = c.Y = 0;
140 ok(SetConsoleCursorPosition(0, c) == 0, "No handle\n");
141 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %lu\n",
142 ERROR_INVALID_HANDLE, GetLastError());
143
144 c.X = c.Y = 0;
145 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
146 okCURSOR(hCon, c);
147
148 c.X = sbSize.X - 1;
149 c.Y = sbSize.Y - 1;
150 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in lower-right\n");
151 okCURSOR(hCon, c);
152
153 c.X = sbSize.X;
154 c.Y = sbSize.Y - 1;
155 ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
156 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n",
157 ERROR_INVALID_PARAMETER, GetLastError());
158
159 c.X = sbSize.X - 1;
160 c.Y = sbSize.Y;
161 ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
162 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n",
163 ERROR_INVALID_PARAMETER, GetLastError());
164
165 c.X = -1;
166 c.Y = 0;
167 ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
168 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n",
169 ERROR_INVALID_PARAMETER, GetLastError());
170
171 c.X = 0;
172 c.Y = -1;
173 ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
174 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %lu\n",
175 ERROR_INVALID_PARAMETER, GetLastError());
176}
177
178static void testCursorInfo(HANDLE hCon)
179{
180 BOOL ret;
181 CONSOLE_CURSOR_INFO info;
182 HANDLE pipe1, pipe2;
183
184 SetLastError(0xdeadbeef);
185 ret = GetConsoleCursorInfo(NULL, NULL);
186 ok(!ret, "Expected failure\n");
187 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %lu\n",
188 ERROR_INVALID_HANDLE, GetLastError());
189
190 SetLastError(0xdeadbeef);
191 info.dwSize = -1;
192 ret = GetConsoleCursorInfo(NULL, &info);
193 ok(!ret, "Expected failure\n");
194 ok(info.dwSize == -1, "Expected no change for dwSize\n");
195 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %lu\n",
196 ERROR_INVALID_HANDLE, GetLastError());
197
198 /* Test the correct call first to distinguish between win9x and the rest */
199 SetLastError(0xdeadbeef);
200 ret = GetConsoleCursorInfo(hCon, &info);
201 ok(ret, "Expected success\n");
202 ok(info.dwSize == 25 ||
203 info.dwSize == 12 /* win9x */,
204 "Expected 12 or 25, got %ld\n", info.dwSize);
205 ok(info.bVisible, "Expected the cursor to be visible\n");
206 ok(GetLastError() == 0xdeadbeef, "GetLastError: expecting %u got %lu\n",
207 0xdeadbeef, GetLastError());
208
209 CreatePipe(&pipe1, &pipe2, NULL, 0);
210 info.dwSize = -1;
211 ret = GetConsoleCursorInfo(pipe1, &info);
212 ok(!ret, "Expected failure\n");
213 ok(info.dwSize == -1, "Expected no change for dwSize\n");
214 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: %lu\n", GetLastError());
215 CloseHandle(pipe1);
216 CloseHandle(pipe2);
217
218 /* Don't test NULL CONSOLE_CURSOR_INFO, it crashes on win9x and win7 */
219}
220
221static void testEmptyWrite(HANDLE hCon)
222{
223 static const char emptybuf[16];
224 COORD c;
225 DWORD len;
226
227 c.X = c.Y = 0;
228 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
229
230 len = -1;
231 ok(WriteConsoleA(hCon, NULL, 0, &len, NULL) != 0 && len == 0, "WriteConsole\n");
232 okCURSOR(hCon, c);
233
234 /* Passing a NULL lpBuffer with sufficiently large non-zero length succeeds
235 * on native Windows and result in memory-like contents being written to
236 * the console. Calling WriteConsoleW like this will crash on Wine. */
237 if (0)
238 {
239 len = -1;
240 ok(!WriteConsoleA(hCon, NULL, 16, &len, NULL) && len == -1, "WriteConsole\n");
241 okCURSOR(hCon, c);
242
243 /* Cursor advances for this call. */
244 len = -1;
245 ok(WriteConsoleA(hCon, NULL, 128, &len, NULL) != 0 && len == 128, "WriteConsole\n");
246 }
247
248 len = -1;
249 ok(WriteConsoleA(hCon, emptybuf, 0, &len, NULL) != 0 && len == 0, "WriteConsole\n");
250 okCURSOR(hCon, c);
251
252 /* WriteConsole does not halt on a null terminator and is happy to write
253 * memory contents beyond the actual size of the buffer. */
254 len = -1;
255 ok(WriteConsoleA(hCon, emptybuf, 16, &len, NULL) != 0 && len == 16, "WriteConsole\n");
256 c.X += 16;
257 okCURSOR(hCon, c);
258}
259
260static void simple_write_console(HANDLE console, const char *text)
261{
262 DWORD len;
263 COORD c = {0, 0};
264 BOOL ret;
265
266 /* single line write */
267 c.X = c.Y = 0;
268 ok(SetConsoleCursorPosition(console, c) != 0, "Cursor in upper-left\n");
269
270 ret = WriteConsoleA(console, text, strlen(text), &len, NULL);
271 ok(ret, "WriteConsoleA failed: %lu\n", GetLastError());
272 ok(len == strlen(text), "unexpected len %lu\n", len);
273}
274
275static void testWriteSimple(HANDLE hCon)
276{
277 const char* mytest = "abcdefg";
278 int mylen = strlen(mytest);
279 COORD c = {0, 0};
280 DWORD len;
281 BOOL ret;
282
283 simple_write_console(hCon, mytest);
284
285 for (c.X = 0; c.X < mylen; c.X++)
286 {
287 okCHAR(hCon, c, mytest[c.X], TEST_ATTRIB);
288 }
289
290 okCURSOR(hCon, c);
291 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
292
293 ret = WriteFile(hCon, mytest, mylen, &len, NULL);
294 ok(ret, "WriteFile failed: %lu\n", GetLastError());
295 ok(len == mylen, "unexpected len = %lu\n", len);
296
297 for (c.X = 0; c.X < 2 * mylen; c.X++)
298 {
299 okCHAR(hCon, c, mytest[c.X % mylen], TEST_ATTRIB);
300 }
301
302 okCURSOR(hCon, c);
303 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
304}
305
306static void testWriteNotWrappedNotProcessed(HANDLE hCon, COORD sbSize)
307{
308 COORD c;
309 DWORD len, mode;
310 const char* mytest = "123";
311 const int mylen = strlen(mytest);
312 char ctrl_buf[32];
313 int ret;
314 int p;
315
316 ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode & ~(ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT)),
317 "clearing wrap at EOL & processed output\n");
318
319 /* write line, wrapping disabled, buffer exceeds sb width */
320 c.X = sbSize.X - 3; c.Y = 0;
321 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
322
323 ret = WriteConsoleA(hCon, mytest, mylen, &len, NULL);
324 ok(ret != 0 && len == mylen, "Couldn't write, ret = %d, len = %ld\n", ret, len);
325 c.Y = 0;
326 for (p = mylen - 3; p < mylen; p++)
327 {
328 c.X = sbSize.X - 3 + p % 3;
329 okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
330 }
331
332 c.X = 0; c.Y = 1;
333 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
334
335 p = sbSize.X - 3 + mylen % 3;
336 c.X = p; c.Y = 0;
337
338 /* write line, wrapping disabled, strings end on end of line */
339 c.X = sbSize.X - mylen; c.Y = 0;
340 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
341
342 ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
343
344 /* test how control chars are handled. */
345 c.X = c.Y = 0;
346 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
347 for (p = 0; p < 32; p++) ctrl_buf[p] = (char)p;
348 ok(WriteConsoleA(hCon, ctrl_buf, 32, &len, NULL) != 0 && len == 32, "WriteConsole\n");
349 for (p = 0; p < 32; p++)
350 {
351 c.X = p; c.Y = 0;
352 okCHAR(hCon, c, (char)p, TEST_ATTRIB);
353 }
354}
355
356static void testWriteNotWrappedProcessed(HANDLE hCon, COORD sbSize)
357{
358 COORD c;
359 DWORD len, mode;
360 const char* mytest = "abcd\nf\tg";
361 const int mylen = strlen(mytest);
362 const int mylen2 = strchr(mytest, '\n') - mytest;
363 int p;
364 WORD attr;
365
366 ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, (mode | ENABLE_PROCESSED_OUTPUT) &
367 ~(ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING)),
368 "clearing wrap at EOL & setting processed output\n");
369
370 /* write line, wrapping disabled, buffer exceeds sb width */
371 c.X = sbSize.X - 5; c.Y = 0;
372 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-5\n");
373
374 ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
375 c.Y = 0;
376 for (c.X = sbSize.X - 5; c.X < sbSize.X - 1; c.X++)
377 {
378 okCHAR(hCon, c, mytest[c.X - sbSize.X + 5], TEST_ATTRIB);
379 }
380
381 ReadConsoleOutputAttribute(hCon, &attr, 1, c, &len);
382 /* Win9x and WinMe change the attribs for '\n' up to 'f' */
383 if (attr == TEST_ATTRIB)
384 {
385 win_skip("Win9x/WinMe don't respect ~ENABLE_WRAP_AT_EOL_OUTPUT\n");
386 return;
387 }
388
389 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
390
391 c.X = 0; c.Y++;
392 okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
393 for (c.X = 1; c.X < 8; c.X++)
394 okCHAR(hCon, c, ' ', TEST_ATTRIB);
395 okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
396 c.X++;
397 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
398
399 okCURSOR(hCon, c);
400
401 /* write line, wrapping disabled, strings end on end of line */
402 c.X = sbSize.X - 4; c.Y = 0;
403 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-4\n");
404
405 ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
406 c.Y = 0;
407 for (c.X = sbSize.X - 4; c.X < sbSize.X; c.X++)
408 {
409 okCHAR(hCon, c, mytest[c.X - sbSize.X + 4], TEST_ATTRIB);
410 }
411 c.X = 0; c.Y++;
412 okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
413 for (c.X = 1; c.X < 8; c.X++)
414 okCHAR(hCon, c, ' ', TEST_ATTRIB);
415 okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
416 c.X++;
417 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
418
419 okCURSOR(hCon, c);
420
421 /* write line, wrapping disabled, strings end after end of line */
422 c.X = sbSize.X - 3; c.Y = 0;
423 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-4\n");
424
425 ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
426 c.Y = 0;
427 for (p = mylen2 - 3; p < mylen2; p++)
428 {
429 c.X = sbSize.X - 3 + p % 3;
430 okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
431 }
432 c.X = 0; c.Y = 1;
433 okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
434 for (c.X = 1; c.X < 8; c.X++)
435 okCHAR(hCon, c, ' ', TEST_ATTRIB);
436 okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
437 c.X++;
438 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
439
440 okCURSOR(hCon, c);
441}
442
443static void testWriteWrappedNotProcessed(HANDLE hCon, COORD sbSize)
444{
445 COORD c;
446 DWORD len, mode;
447 const char* mytest = "abcd\nf\tg";
448 const int mylen = strlen(mytest);
449 int p;
450
451 ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon,(mode | ENABLE_WRAP_AT_EOL_OUTPUT) & ~(ENABLE_PROCESSED_OUTPUT)),
452 "setting wrap at EOL & clearing processed output\n");
453
454 /* write line, wrapping enabled, buffer doesn't exceed sb width */
455 c.X = sbSize.X - 9; c.Y = 0;
456 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-9\n");
457
458 ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
459 c.Y = 0;
460 for (p = 0; p < mylen; p++)
461 {
462 c.X = sbSize.X - 9 + p;
463 okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
464 }
465 c.X = sbSize.X - 9 + mylen;
466 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
467 c.X = 0; c.Y = 1;
468 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
469
470 /* write line, wrapping enabled, buffer does exceed sb width */
471 c.X = sbSize.X - 3; c.Y = 0;
472 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
473
474 c.Y = 1;
475 c.X = mylen - 3;
476 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
477}
478
479static void testWriteWrappedProcessed(HANDLE hCon, COORD sbSize)
480{
481 COORD c;
482 DWORD len, mode;
483 const char* mytest = "abcd\nf\tg";
484 const int mylen = strlen(mytest);
485 int p;
486 WORD attr;
487
488 ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode | (ENABLE_WRAP_AT_EOL_OUTPUT|ENABLE_PROCESSED_OUTPUT)),
489 "setting wrap at EOL & processed output\n");
490
491 /* write line, wrapping enabled, buffer doesn't exceed sb width */
492 c.X = sbSize.X - 9; c.Y = 0;
493 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-9\n");
494
495 ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
496 for (p = 0; p < 4; p++)
497 {
498 c.X = sbSize.X - 9 + p;
499 okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
500 }
501 c.X = sbSize.X - 9 + p;
502 ReadConsoleOutputAttribute(hCon, &attr, 1, c, &len);
503 if (attr == TEST_ATTRIB)
504 win_skip("Win9x/WinMe changes attribs for '\\n' up to 'f'\n");
505 else
506 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
507 c.X = 0; c.Y++;
508 okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
509 for (c.X = 1; c.X < 8; c.X++)
510 okCHAR(hCon, c, ' ', TEST_ATTRIB);
511 okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
512 c.X++;
513 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
514 okCURSOR(hCon, c);
515
516 /* write line, wrapping enabled, buffer does exceed sb width */
517 c.X = sbSize.X - 3; c.Y = 2;
518 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
519
520 ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
521 for (p = 0; p < 3; p++)
522 {
523 c.X = sbSize.X - 3 + p;
524 okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
525 }
526 c.X = 0; c.Y++;
527 okCHAR(hCon, c, mytest[3], TEST_ATTRIB);
528 c.X++;
529 ReadConsoleOutputAttribute(hCon, &attr, 1, c, &len);
530 if (attr == TEST_ATTRIB)
531 win_skip("Win9x/WinMe changes attribs for '\\n' up to 'f'\n");
532 else
533 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
534
535 c.X = 0; c.Y++;
536 okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
537 for (c.X = 1; c.X < 8; c.X++)
538 okCHAR(hCon, c, ' ', TEST_ATTRIB);
539 okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
540 c.X++;
541 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
542 okCURSOR(hCon, c);
543}
544
545static void testWrite(HANDLE hCon, COORD sbSize)
546{
547 /* FIXME: should in fact ensure that the sb is at least 10 characters wide */
548 ok(SetConsoleTextAttribute(hCon, TEST_ATTRIB), "Setting default text color\n");
549 resetContent(hCon, sbSize, FALSE);
550 testEmptyWrite(hCon);
551 resetContent(hCon, sbSize, FALSE);
552 testWriteSimple(hCon);
553 resetContent(hCon, sbSize, FALSE);
554 testWriteNotWrappedNotProcessed(hCon, sbSize);
555 resetContent(hCon, sbSize, FALSE);
556 testWriteNotWrappedProcessed(hCon, sbSize);
557 resetContent(hCon, sbSize, FALSE);
558 testWriteWrappedNotProcessed(hCon, sbSize);
559 resetContent(hCon, sbSize, FALSE);
560 testWriteWrappedProcessed(hCon, sbSize);
561}
562
563static void testScroll(HANDLE hCon, COORD sbSize)
564{
565 SMALL_RECT scroll, clip;
566 COORD dst, c, tc;
567 CHAR_INFO ci;
568 BOOL ret;
569
570#define W 11
571#define H 7
572
573#define IN_SRECT(r,c) ((r).Left <= (c).X && (c).X <= (r).Right && (r).Top <= (c).Y && (c).Y <= (r).Bottom)
574#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)
575
576 /* no clipping, src & dst rect don't overlap */
577 resetContent(hCon, sbSize, TRUE);
578
579 scroll.Left = 0;
580 scroll.Right = W - 1;
581 scroll.Top = 0;
582 scroll.Bottom = H - 1;
583 dst.X = W + 3;
584 dst.Y = H + 3;
585 ci.Char.UnicodeChar = '#';
586 ci.Attributes = TEST_ATTRIB;
587
588 clip.Left = 0;
589 clip.Right = sbSize.X - 1;
590 clip.Top = 0;
591 clip.Bottom = sbSize.Y - 1;
592
593 ok(ScrollConsoleScreenBufferA(hCon, &scroll, NULL, dst, &ci), "Scrolling SB\n");
594
595 for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
596 {
597 for (c.X = 0; c.X < sbSize.X; c.X++)
598 {
599 if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
600 {
601 tc.X = c.X - dst.X;
602 tc.Y = c.Y - dst.Y;
603 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
604 }
605 else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
606 okCHAR(hCon, c, '#', TEST_ATTRIB);
607 else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
608 }
609 }
610
611 /* no clipping, src & dst rect do overlap */
612 resetContent(hCon, sbSize, TRUE);
613
614 scroll.Left = 0;
615 scroll.Right = W - 1;
616 scroll.Top = 0;
617 scroll.Bottom = H - 1;
618 dst.X = W /2;
619 dst.Y = H / 2;
620 ci.Char.UnicodeChar = '#';
621 ci.Attributes = TEST_ATTRIB;
622
623 clip.Left = 0;
624 clip.Right = sbSize.X - 1;
625 clip.Top = 0;
626 clip.Bottom = sbSize.Y - 1;
627
628 ok(ScrollConsoleScreenBufferA(hCon, &scroll, NULL, dst, &ci), "Scrolling SB\n");
629
630 for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
631 {
632 for (c.X = 0; c.X < sbSize.X; c.X++)
633 {
634 if (dst.X <= c.X && c.X < dst.X + W && dst.Y <= c.Y && c.Y < dst.Y + H)
635 {
636 tc.X = c.X - dst.X;
637 tc.Y = c.Y - dst.Y;
638 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
639 }
640 else if (c.X < W && c.Y < H) okCHAR(hCon, c, '#', TEST_ATTRIB);
641 else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
642 }
643 }
644
645 /* clipping, src & dst rect don't overlap */
646 resetContent(hCon, sbSize, TRUE);
647
648 scroll.Left = 0;
649 scroll.Right = W - 1;
650 scroll.Top = 0;
651 scroll.Bottom = H - 1;
652 dst.X = W + 3;
653 dst.Y = H + 3;
654 ci.Char.UnicodeChar = '#';
655 ci.Attributes = TEST_ATTRIB;
656
657 clip.Left = W / 2;
658 clip.Right = min(W + W / 2, sbSize.X - 1);
659 clip.Top = H / 2;
660 clip.Bottom = min(H + H / 2, sbSize.Y - 1);
661
662 SetLastError(0xdeadbeef);
663 ret = ScrollConsoleScreenBufferA(hCon, &scroll, &clip, dst, &ci);
664 if (ret)
665 {
666 for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
667 {
668 for (c.X = 0; c.X < sbSize.X; c.X++)
669 {
670 if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
671 {
672 tc.X = c.X - dst.X;
673 tc.Y = c.Y - dst.Y;
674 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
675 }
676 else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
677 okCHAR(hCon, c, '#', TEST_ATTRIB);
678 else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
679 }
680 }
681 }
682 else
683 {
684 /* Win9x will fail, Only accept ERROR_NOT_ENOUGH_MEMORY */
685 ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY,
686 "Expected ERROR_NOT_ENOUGH_MEMORY, got %lu\n", GetLastError());
687 }
688
689 /* no clipping, src & dst rect do overlap */
690 scroll.Left = 0;
691 scroll.Right = W - 1;
692 scroll.Top = 0;
693 scroll.Bottom = H - 1;
694 dst.X = W / 2 - 3;
695 dst.Y = H / 2 - 3;
696 ci.Char.UnicodeChar = '#';
697 ci.Attributes = TEST_ATTRIB;
698
699 ret = ScrollConsoleScreenBufferA(hCon, &scroll, NULL, dst, &ci);
700 ok(ret, "ScrollConsoleScreenBufferA failed: %lu\n", GetLastError());
701 /* no win10 1909 error here, only check the result of the clipped case */
702
703 /* clipping, src & dst rect do overlap */
704 resetContent(hCon, sbSize, TRUE);
705
706 scroll.Left = 0;
707 scroll.Right = W - 1;
708 scroll.Top = 0;
709 scroll.Bottom = H - 1;
710 dst.X = W / 2 - 3;
711 dst.Y = H / 2 - 3;
712 ci.Char.UnicodeChar = '#';
713 ci.Attributes = TEST_ATTRIB;
714
715 clip.Left = W / 2;
716 clip.Right = min(W + W / 2, sbSize.X - 1);
717 clip.Top = H / 2;
718 clip.Bottom = min(H + H / 2, sbSize.Y - 1);
719
720 /* Windows 10 1909 fails if the destination is not in the clip rect
721 * but the result is still ok!
722 */
723 SetLastError(0xdeadbeef);
724 ret = ScrollConsoleScreenBufferA(hCon, &scroll, &clip, dst, &ci);
725 ok((ret && GetLastError() == 0xdeadbeef) ||
726 broken(!ret && GetLastError() == ERROR_INVALID_PARAMETER),
727 "ScrollConsoleScreenBufferA failed: %lu\n", GetLastError());
728
729 for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
730 {
731 for (c.X = 0; c.X < sbSize.X; c.X++)
732 {
733 if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
734 {
735 tc.X = c.X - dst.X;
736 tc.Y = c.Y - dst.Y;
737 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
738 }
739 else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
740 okCHAR(hCon, c, '#', TEST_ATTRIB);
741 else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
742 }
743 }
744}
745
746static int mch_count;
747/* we need the event as Wine console event generation isn't synchronous
748 * (ie GenerateConsoleCtrlEvent returns before all ctrl-handlers in all
749 * processes have been called).
750 */
751static HANDLE mch_event;
752static BOOL WINAPI mch(DWORD event)
753{
754 mch_count++;
755 SetEvent(mch_event);
756 return TRUE;
757}
758
759static void testCtrlHandler(void)
760{
761 ok(!SetConsoleCtrlHandler(mch, FALSE), "Shouldn't succeed\n");
762 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %lu\n", GetLastError());
763 ok(SetConsoleCtrlHandler(mch, TRUE), "Couldn't set handler\n");
764 /* wine requires the event for the test, as we cannot ensure, so far, that
765 * events are processed synchronously in GenerateConsoleCtrlEvent()
766 */
767 mch_event = CreateEventA(NULL, TRUE, FALSE, NULL);
768 mch_count = 0;
769 ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n");
770 /* FIXME: it isn't synchronous on wine but it can still happen before we test */
771 if (0) ok(mch_count == 1, "Event isn't synchronous\n");
772#ifdef __REACTOS__
773 DWORD res = WaitForSingleObject(mch_event, 3000);
774 ok(res == WAIT_OBJECT_0 || broken(res == WAIT_TIMEOUT) /* ROS testbots on Windows */, "event sending didn't work (%ld)\n", res);
775#else
776 ok(WaitForSingleObject(mch_event, 3000) == WAIT_OBJECT_0, "event sending didn't work\n");
777#endif
778 CloseHandle(mch_event);
779
780 ok(SetConsoleCtrlHandler(NULL, FALSE), "Couldn't turn on ctrl-c handling\n");
781 ok((RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags & 1) == 0,
782 "Unexpect ConsoleFlags value %lx\n", RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags);
783
784 /* Turning off ctrl-c handling doesn't work on win9x such way ... */
785 ok(SetConsoleCtrlHandler(NULL, TRUE), "Couldn't turn off ctrl-c handling\n");
786 ok((RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags & 1) != 0,
787 "Unexpect ConsoleFlags value %lx\n", RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags);
788 mch_event = CreateEventA(NULL, TRUE, FALSE, NULL);
789 mch_count = 0;
790 if(!(GetVersion() & 0x80000000))
791 /* ... and next line leads to an unhandled exception on 9x. Avoid it on 9x. */
792 ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n");
793 ok(WaitForSingleObject(mch_event, 3000) == WAIT_TIMEOUT && mch_count == 0, "Event shouldn't have been sent\n");
794 CloseHandle(mch_event);
795 ok(SetConsoleCtrlHandler(mch, FALSE), "Couldn't remove handler\n");
796 ok(!SetConsoleCtrlHandler(mch, FALSE), "Shouldn't succeed\n");
797 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %lu\n", GetLastError());
798}
799
800/*
801 * Test console screen buffer:
802 * 1) Try to set invalid handle.
803 * 2) Try to set non-console handles.
804 * 3) Use CONOUT$ file as active SB.
805 * 4) Test cursor.
806 * 5) Test output codepage to show it is not a property of SB.
807 * 6) Test switching to old SB if we close all handles to current SB - works
808 * in Windows, TODO in wine.
809 *
810 * What is not tested but should be:
811 * 1) ScreenBufferInfo
812 */
813static void testScreenBuffer(HANDLE hConOut)
814{
815 HANDLE hConOutRW, hConOutRO, hConOutWT;
816 HANDLE hFileOutRW, hFileOutRO, hFileOutWT;
817 HANDLE hConOutNew;
818 char test_str1[] = "Test for SB1";
819 char test_str2[] = "Test for SB2";
820 char test_cp866[] = {0xe2, 0xa5, 0xe1, 0xe2, 0};
821 char test_cp1251[] = {0xf2, 0xe5, 0xf1, 0xf2, 0};
822 WCHAR test_unicode[] = {0x0442, 0x0435, 0x0441, 0x0442, 0};
823 WCHAR str_wbuf[20];
824 char str_buf[20];
825 DWORD len, error;
826 COORD c;
827 BOOL ret;
828 DWORD oldcp;
829
830 if (!IsValidCodePage(866))
831 {
832 skip("Codepage 866 not available\n");
833 return;
834 }
835
836 /* In the beginning set output codepage to 866 */
837 oldcp = GetConsoleOutputCP();
838 SetLastError(0xdeadbeef);
839 ret = SetConsoleOutputCP(866);
840 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
841 {
842 win_skip("SetConsoleOutputCP is not implemented\n");
843 return;
844 }
845 ok(ret, "Cannot set output codepage to 866\n");
846
847 hConOutRW = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
848 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
849 CONSOLE_TEXTMODE_BUFFER, NULL);
850 ok(hConOutRW != INVALID_HANDLE_VALUE,
851 "Cannot create a new screen buffer for ReadWrite\n");
852 hConOutRO = CreateConsoleScreenBuffer(GENERIC_READ,
853 FILE_SHARE_READ, NULL,
854 CONSOLE_TEXTMODE_BUFFER, NULL);
855 ok(hConOutRO != INVALID_HANDLE_VALUE,
856 "Cannot create a new screen buffer for ReadOnly\n");
857 hConOutWT = CreateConsoleScreenBuffer(GENERIC_WRITE,
858 FILE_SHARE_WRITE, NULL,
859 CONSOLE_TEXTMODE_BUFFER, NULL);
860 ok(hConOutWT != INVALID_HANDLE_VALUE,
861 "Cannot create a new screen buffer for WriteOnly\n");
862
863 hFileOutRW = CreateFileA("NUL", GENERIC_READ | GENERIC_WRITE,
864 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
865 OPEN_EXISTING, 0, NULL);
866 ok(hFileOutRW != INVALID_HANDLE_VALUE, "Cannot open NUL for ReadWrite\n");
867 hFileOutRO = CreateFileA("NUL", GENERIC_READ, FILE_SHARE_READ,
868 NULL, OPEN_EXISTING, 0, NULL);
869 ok(hFileOutRO != INVALID_HANDLE_VALUE, "Cannot open NUL for ReadOnly\n");
870 hFileOutWT = CreateFileA("NUL", GENERIC_WRITE, FILE_SHARE_WRITE,
871 NULL, OPEN_EXISTING, 0, NULL);
872 ok(hFileOutWT != INVALID_HANDLE_VALUE, "Cannot open NUL for WriteOnly\n");
873
874 /* Trying to set invalid handle */
875 SetLastError(0);
876 ok(!SetConsoleActiveScreenBuffer(INVALID_HANDLE_VALUE),
877 "Shouldn't succeed\n");
878 ok(GetLastError() == ERROR_INVALID_HANDLE,
879 "GetLastError: expecting %u got %lu\n",
880 ERROR_INVALID_HANDLE, GetLastError());
881
882 /* Trying to set non-console handles */
883 SetLastError(0);
884 ok(!SetConsoleActiveScreenBuffer(hFileOutRW), "Shouldn't succeed\n");
885 ok(GetLastError() == ERROR_INVALID_HANDLE,
886 "GetLastError: expecting %u got %lu\n",
887 ERROR_INVALID_HANDLE, GetLastError());
888
889 SetLastError(0);
890 ok(!SetConsoleActiveScreenBuffer(hFileOutRO), "Shouldn't succeed\n");
891 ok(GetLastError() == ERROR_INVALID_HANDLE,
892 "GetLastError: expecting %u got %lu\n",
893 ERROR_INVALID_HANDLE, GetLastError());
894
895 SetLastError(0);
896 ok(!SetConsoleActiveScreenBuffer(hFileOutWT), "Shouldn't succeed\n");
897 ok(GetLastError() == ERROR_INVALID_HANDLE,
898 "GetLastError: expecting %u got %lu\n",
899 ERROR_INVALID_HANDLE, GetLastError());
900
901 /* trying to write non-console handle */
902 SetLastError(0xdeadbeef);
903 ret = WriteConsoleA(hFileOutRW, test_str1, lstrlenA(test_str1), &len, NULL);
904 error = GetLastError();
905 ok(!ret, "Shouldn't succeed\n");
906 ok(error == ERROR_INVALID_HANDLE || error == ERROR_INVALID_FUNCTION,
907 "GetLastError: got %lu\n", error);
908
909 SetLastError(0xdeadbeef);
910 ret = WriteConsoleA(hFileOutRO, test_str1, lstrlenA(test_str1), &len, NULL);
911 error = GetLastError();
912 ok(!ret, "Shouldn't succeed\n");
913 ok(error == ERROR_INVALID_HANDLE || error == ERROR_INVALID_FUNCTION,
914 "GetLastError: got %lu\n", error);
915
916 SetLastError(0xdeadbeef);
917 ret = WriteConsoleA(hFileOutWT, test_str1, lstrlenA(test_str1), &len, NULL);
918 error = GetLastError();
919 ok(!ret, "Shouldn't succeed\n");
920 ok(error == ERROR_INVALID_HANDLE || error == ERROR_INVALID_FUNCTION,
921 "GetLastError: got %lu\n", error);
922
923 CloseHandle(hFileOutRW);
924 CloseHandle(hFileOutRO);
925 CloseHandle(hFileOutWT);
926
927 /* Trying to set SB handles with various access modes */
928 SetLastError(0);
929 ok(!SetConsoleActiveScreenBuffer(hConOutRO), "Shouldn't succeed\n");
930 ok(GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == ERROR_ACCESS_DENIED) /* win10 1809 */,
931 "unexpected last error %lu\n", GetLastError());
932
933 ok(SetConsoleActiveScreenBuffer(hConOutWT), "Couldn't set new WriteOnly SB\n");
934
935 ok(SetConsoleActiveScreenBuffer(hConOutRW), "Couldn't set new ReadWrite SB\n");
936
937 CloseHandle(hConOutWT);
938 CloseHandle(hConOutRO);
939
940 /* Now we have two ReadWrite SB, active must be hConOutRW */
941 /* Open current SB via CONOUT$ */
942 hConOutNew = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0,
943 NULL, OPEN_EXISTING, 0, 0);
944 ok(hConOutNew != INVALID_HANDLE_VALUE, "CONOUT$ is not opened\n");
945
946
947 /* test cursor */
948 c.X = c.Y = 10;
949 SetConsoleCursorPosition(hConOut, c);
950 c.X = c.Y = 5;
951 SetConsoleCursorPosition(hConOutRW, c);
952 okCURSOR(hConOutNew, c);
953 c.X = c.Y = 10;
954 okCURSOR(hConOut, c);
955
956
957 c.X = c.Y = 0;
958
959 /* Write using hConOutNew... */
960 SetConsoleCursorPosition(hConOutNew, c);
961 ret = WriteConsoleA(hConOutNew, test_str2, lstrlenA(test_str2), &len, NULL);
962 ok (ret && len == lstrlenA(test_str2), "WriteConsoleA failed\n");
963 /* ... and read it back via hConOutRW */
964 ret = ReadConsoleOutputCharacterA(hConOutRW, str_buf, lstrlenA(test_str2), c, &len);
965 ok(ret && len == lstrlenA(test_str2), "ReadConsoleOutputCharacterA failed\n");
966 str_buf[lstrlenA(test_str2)] = 0;
967 ok(!lstrcmpA(str_buf, test_str2), "got '%s' expected '%s'\n", str_buf, test_str2);
968
969
970 /* Now test output codepage handling. Current is 866 as we set earlier. */
971 SetConsoleCursorPosition(hConOutRW, c);
972 ret = WriteConsoleA(hConOutRW, test_cp866, lstrlenA(test_cp866), &len, NULL);
973 ok(ret && len == lstrlenA(test_cp866), "WriteConsoleA failed\n");
974 ret = ReadConsoleOutputCharacterW(hConOutRW, str_wbuf, lstrlenW(test_unicode), c, &len);
975 /* Work around some broken results under Windows with some locale (ja, cn, ko...)
976 * Looks like a real bug in Win10 (at least).
977 */
978 if (ret && broken(len == lstrlenW(test_unicode) / sizeof(WCHAR)))
979 ret = ReadConsoleOutputCharacterW(hConOutRW, str_wbuf, lstrlenW(test_unicode) * sizeof(WCHAR), c, &len);
980 ok(ret, "ReadConsoleOutputCharacterW failed\n");
981 ok(len == lstrlenW(test_unicode), "unexpected len %lu %u\n", len, lstrlenW(test_unicode));
982 ok(!memcmp(str_wbuf, test_unicode, lstrlenW(test_unicode) * sizeof(WCHAR)),
983 "string does not match the pattern\n");
984
985 /*
986 * cp866 is OK, let's switch to cp1251.
987 * We expect that this codepage will be used in every SB - active and not.
988 */
989 ok(SetConsoleOutputCP(1251), "Cannot set output cp to 1251\n");
990 SetConsoleCursorPosition(hConOutRW, c);
991 ret = WriteConsoleA(hConOutRW, test_cp1251, lstrlenA(test_cp1251), &len, NULL);
992 ok(ret && len == lstrlenA(test_cp1251), "WriteConsoleA failed\n");
993 ret = ReadConsoleOutputCharacterW(hConOutRW, str_wbuf, lstrlenA(test_cp1251), c, &len);
994 ok(ret && len == lstrlenA(test_cp1251), "ReadConsoleOutputCharacterW failed\n");
995 str_wbuf[lstrlenA(test_cp1251)] = 0;
996 ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n");
997
998 /* Check what has happened to hConOut. */
999 SetConsoleCursorPosition(hConOut, c);
1000 ret = WriteConsoleA(hConOut, test_cp1251, lstrlenA(test_cp1251), &len, NULL);
1001 ok(ret && len == lstrlenA(test_cp1251), "WriteConsoleA failed\n");
1002 ret = ReadConsoleOutputCharacterW(hConOut, str_wbuf, lstrlenA(test_cp1251), c, &len);
1003 ok(ret && len == lstrlenA(test_cp1251), "ReadConsoleOutputCharacterW failed\n");
1004 str_wbuf[lstrlenA(test_cp1251)] = 0;
1005 ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n");
1006
1007 /* Close all handles of current console SB */
1008 CloseHandle(hConOutNew);
1009 CloseHandle(hConOutRW);
1010
1011 /* Now active SB should be hConOut */
1012 hConOutNew = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0,
1013 NULL, OPEN_EXISTING, 0, 0);
1014 ok(hConOutNew != INVALID_HANDLE_VALUE, "CONOUT$ is not opened\n");
1015
1016 /* Write using hConOutNew... */
1017 SetConsoleCursorPosition(hConOutNew, c);
1018 ret = WriteConsoleA(hConOutNew, test_str1, lstrlenA(test_str1), &len, NULL);
1019 ok (ret && len == lstrlenA(test_str1), "WriteConsoleA failed\n");
1020 /* ... and read it back via hConOut */
1021 ret = ReadConsoleOutputCharacterA(hConOut, str_buf, lstrlenA(test_str1), c, &len);
1022 ok(ret && len == lstrlenA(test_str1), "ReadConsoleOutputCharacterA failed\n");
1023 str_buf[lstrlenA(test_str1)] = 0;
1024 todo_wine ok(!lstrcmpA(str_buf, test_str1), "got '%s' expected '%s'\n", str_buf, test_str1);
1025 CloseHandle(hConOutNew);
1026
1027 /* This is not really needed under Windows */
1028 SetConsoleActiveScreenBuffer(hConOut);
1029
1030 /* restore codepage */
1031 SetConsoleOutputCP(oldcp);
1032}
1033
1034static void test_new_screen_buffer_properties(HANDLE hConOut)
1035{
1036#if defined(__REACTOS__) && DLL_EXPORT_VERSION < 0x600
1037 UNREFERENCED_PARAMETER(hConOut);
1038 skip("Cannot build test_new_screen_buffer_properties() unless DLL_EXPORT_VERSION >= 0x600.\n");
1039#else
1040 BOOL ret;
1041 HANDLE hConOut2;
1042 CONSOLE_FONT_INFOEX cfi, cfi2;
1043 CONSOLE_SCREEN_BUFFER_INFO csbi, csbi2;
1044
1045 /* Font information */
1046 cfi.cbSize = cfi2.cbSize = sizeof(CONSOLE_FONT_INFOEX);
1047
1048 ret = GetCurrentConsoleFontEx(hConOut, FALSE, &cfi);
1049 ok(ret, "GetCurrentConsoleFontEx failed: error %lu\n", GetLastError());
1050
1051 hConOut2 = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, 0, NULL,
1052 CONSOLE_TEXTMODE_BUFFER, NULL);
1053 ok(hConOut2 != INVALID_HANDLE_VALUE, "CreateConsoleScreenBuffer failed: error %lu\n", GetLastError());
1054
1055 ret = GetCurrentConsoleFontEx(hConOut2, FALSE, &cfi2);
1056 ok(ret, "GetCurrentConsoleFontEx failed: error %lu\n", GetLastError());
1057 CloseHandle(hConOut2);
1058
1059 ok(cfi2.nFont == cfi.nFont, "Font index should match: "
1060 "got %lu, expected %lu\n", cfi2.nFont, cfi.nFont);
1061 ok(cfi2.dwFontSize.X == cfi.dwFontSize.X, "Font width should match: "
1062 "got %d, expected %d\n", cfi2.dwFontSize.X, cfi.dwFontSize.X);
1063 ok(cfi2.dwFontSize.Y == cfi.dwFontSize.Y, "Font height should match: "
1064 "got %d, expected %d\n", cfi2.dwFontSize.Y, cfi.dwFontSize.Y);
1065 ok(cfi2.FontFamily == cfi.FontFamily, "Font family should match: "
1066 "got %u, expected %u\n", cfi2.FontFamily, cfi.FontFamily);
1067 ok(cfi2.FontWeight == cfi.FontWeight, "Font weight should match: "
1068 "got %u, expected %u\n", cfi2.FontWeight, cfi.FontWeight);
1069 ok(!lstrcmpW(cfi2.FaceName, cfi.FaceName), "Font name should match: "
1070 "got %s, expected %s\n", wine_dbgstr_w(cfi2.FaceName), wine_dbgstr_w(cfi.FaceName));
1071
1072 /* Display window size */
1073 ret = GetConsoleScreenBufferInfo(hConOut, &csbi);
1074 ok(ret, "GetConsoleScreenBufferInfo failed: error %lu\n", GetLastError());
1075
1076 hConOut2 = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, 0, NULL,
1077 CONSOLE_TEXTMODE_BUFFER, NULL);
1078 ok(hConOut2 != INVALID_HANDLE_VALUE, "CreateConsoleScreenBuffer failed: error %lu\n", GetLastError());
1079
1080 ret = GetConsoleScreenBufferInfo(hConOut2, &csbi2);
1081 ok(ret, "GetConsoleScreenBufferInfo failed: error %lu\n", GetLastError());
1082 CloseHandle(hConOut2);
1083
1084 ok(csbi2.srWindow.Left == csbi.srWindow.Left, "Left coordinate should match\n");
1085 ok(csbi2.srWindow.Top == csbi.srWindow.Top, "Top coordinate should match\n");
1086 ok(csbi2.srWindow.Right == csbi.srWindow.Right, "Right coordinate should match\n");
1087 ok(csbi2.srWindow.Bottom == csbi.srWindow.Bottom, "Bottom coordinate should match\n");
1088#endif
1089}
1090
1091static void test_new_screen_buffer_color_attributes(HANDLE hConOut)
1092{
1093#if defined(__REACTOS__) && DLL_EXPORT_VERSION < 0x600
1094 UNREFERENCED_PARAMETER(hConOut);
1095 skip("Cannot build test_new_screen_buffer_color_attributes() unless DLL_EXPORT_VERSION >= 0x600.\n");
1096#else
1097 CONSOLE_SCREEN_BUFFER_INFOEX csbi, csbi2;
1098 BOOL ret;
1099 HANDLE hConOut2;
1100 WORD orig_attr, orig_popup, attr;
1101
1102 csbi.cbSize = csbi2.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
1103
1104 ret = GetConsoleScreenBufferInfoEx(hConOut, &csbi);
1105 ok(ret, "GetConsoleScreenBufferInfoEx failed: error %lu\n", GetLastError());
1106 orig_attr = csbi.wAttributes;
1107 orig_popup = csbi.wPopupAttributes;
1108
1109 hConOut2 = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, 0, NULL,
1110 CONSOLE_TEXTMODE_BUFFER, NULL);
1111 ok(hConOut2 != INVALID_HANDLE_VALUE, "CreateConsoleScreenBuffer failed: error %lu\n", GetLastError());
1112
1113 ret = GetConsoleScreenBufferInfoEx(hConOut2, &csbi2);
1114 ok(ret, "GetConsoleScreenBufferInfoEx failed: error %lu\n", GetLastError());
1115 CloseHandle(hConOut2);
1116
1117 ok(csbi2.wAttributes == orig_attr, "Character Attributes should have been copied: "
1118 "got %#x, expected %#x\n", csbi2.wAttributes, orig_attr);
1119 ok(csbi2.wPopupAttributes != orig_popup, "Popup Attributes should not match original value\n");
1120 ok(csbi2.wPopupAttributes == orig_attr, "Popup Attributes should match Character Attributes\n");
1121
1122 /* Test different Character Attributes */
1123 attr = FOREGROUND_BLUE|BACKGROUND_GREEN;
1124 ret = SetConsoleTextAttribute(hConOut, attr);
1125 ok(ret, "SetConsoleTextAttribute failed: error %lu\n", GetLastError());
1126
1127 hConOut2 = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, 0, NULL,
1128 CONSOLE_TEXTMODE_BUFFER, NULL);
1129 ok(hConOut2 != INVALID_HANDLE_VALUE, "CreateConsoleScreenBuffer failed: error %lu\n", GetLastError());
1130
1131 memset(&csbi2, 0, sizeof(CONSOLE_SCREEN_BUFFER_INFOEX));
1132 csbi2.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
1133
1134 ret = GetConsoleScreenBufferInfoEx(hConOut2, &csbi2);
1135 ok(ret, "GetConsoleScreenBufferInfoEx failed: error %lu\n", GetLastError());
1136 CloseHandle(hConOut2);
1137
1138 ok(csbi2.wAttributes == attr, "Character Attributes should have been copied: "
1139 "got %#x, expected %#x\n", csbi2.wAttributes, attr);
1140 ok(csbi2.wPopupAttributes != orig_popup, "Popup Attributes should not match original value\n");
1141 ok(csbi2.wPopupAttributes == attr, "Popup Attributes should match Character Attributes\n");
1142
1143 ret = SetConsoleTextAttribute(hConOut, orig_attr);
1144 ok(ret, "SetConsoleTextAttribute failed: error %lu\n", GetLastError());
1145
1146 /* Test inheritance of different Popup Attributes */
1147 csbi.wPopupAttributes = attr;
1148 ret = SetConsoleScreenBufferInfoEx(hConOut, &csbi);
1149 ok(ret, "SetConsoleScreenBufferInfoEx failed: error %lu\n", GetLastError());
1150
1151 hConOut2 = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, 0, NULL,
1152 CONSOLE_TEXTMODE_BUFFER, NULL);
1153 ok(hConOut2 != INVALID_HANDLE_VALUE, "CreateConsoleScreenBuffer failed: error %lu\n", GetLastError());
1154
1155 memset(&csbi2, 0, sizeof(CONSOLE_SCREEN_BUFFER_INFOEX));
1156 csbi2.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
1157
1158 ret = GetConsoleScreenBufferInfoEx(hConOut2, &csbi2);
1159 ok(ret, "GetConsoleScreenBufferInfoEx failed: error %lu\n", GetLastError());
1160 CloseHandle(hConOut2);
1161
1162 ok(csbi2.wAttributes == orig_attr, "Character Attributes should have been copied: "
1163 "got %#x, expected %#x\n", csbi2.wAttributes, orig_attr);
1164 ok(csbi2.wPopupAttributes != orig_popup, "Popup Attributes should not match original value\n");
1165 ok(csbi2.wPopupAttributes == orig_attr, "Popup Attributes should match Character Attributes\n");
1166
1167 csbi.wPopupAttributes = orig_popup;
1168 ret = SetConsoleScreenBufferInfoEx(hConOut, &csbi);
1169 ok(ret, "SetConsoleScreenBufferInfoEx failed: error %lu\n", GetLastError());
1170#endif
1171}
1172
1173static void CALLBACK signaled_function(void *p, BOOLEAN timeout)
1174{
1175 HANDLE event = p;
1176 SetEvent(event);
1177 ok(!timeout, "wait shouldn't have timed out\n");
1178}
1179
1180static void testWaitForConsoleInput(HANDLE input_handle)
1181{
1182 HANDLE wait_handle;
1183 HANDLE complete_event;
1184 INPUT_RECORD record;
1185 DWORD events_written;
1186 DWORD wait_ret;
1187 BOOL ret;
1188
1189 complete_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1190
1191 /* Test success case */
1192 ret = RegisterWaitForSingleObject(&wait_handle, input_handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
1193 ok(ret == TRUE, "Expected RegisterWaitForSingleObject to return TRUE, got %d\n", ret);
1194 /* give worker thread a chance to start up */
1195 Sleep(100);
1196 record.EventType = KEY_EVENT;
1197 record.Event.KeyEvent.bKeyDown = 1;
1198 record.Event.KeyEvent.wRepeatCount = 1;
1199 record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
1200 record.Event.KeyEvent.wVirtualScanCode = VK_RETURN;
1201 record.Event.KeyEvent.uChar.UnicodeChar = '\r';
1202 record.Event.KeyEvent.dwControlKeyState = 0;
1203 ret = WriteConsoleInputW(input_handle, &record, 1, &events_written);
1204 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
1205 wait_ret = WaitForSingleObject(complete_event, INFINITE);
1206 ok(wait_ret == WAIT_OBJECT_0, "Expected the handle to be signaled\n");
1207 ret = UnregisterWait(wait_handle);
1208 /* If the callback is still running, this fails with ERROR_IO_PENDING, but
1209 that's ok and expected. */
1210 ok(ret != 0 || GetLastError() == ERROR_IO_PENDING,
1211 "UnregisterWait failed with error %ld\n", GetLastError());
1212
1213 /* Test timeout case */
1214 FlushConsoleInputBuffer(input_handle);
1215 ret = RegisterWaitForSingleObject(&wait_handle, input_handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
1216 wait_ret = WaitForSingleObject(complete_event, 100);
1217 ok(wait_ret == WAIT_TIMEOUT, "Expected the wait to time out\n");
1218 ret = UnregisterWait(wait_handle);
1219 ok(ret, "UnregisterWait failed with error %ld\n", GetLastError());
1220
1221 /* Clean up */
1222 CloseHandle(complete_event);
1223}
1224
1225static BOOL filter_spurious_event(HANDLE input)
1226{
1227 INPUT_RECORD ir;
1228 DWORD r;
1229
1230 if (!ReadConsoleInputW(input, &ir, 1, &r) || r != 1) return FALSE;
1231
1232 switch (ir.EventType)
1233 {
1234 case MOUSE_EVENT:
1235 if (ir.Event.MouseEvent.dwEventFlags == MOUSE_MOVED) return TRUE;
1236 ok(0, "Unexcepted mouse message: state=%lx ctrl=%lx flags=%lx (%u, %u)\n",
1237 ir.Event.MouseEvent.dwButtonState,
1238 ir.Event.MouseEvent.dwControlKeyState,
1239 ir.Event.MouseEvent.dwEventFlags,
1240 ir.Event.MouseEvent.dwMousePosition.X,
1241 ir.Event.MouseEvent.dwMousePosition.Y);
1242 break;
1243 case WINDOW_BUFFER_SIZE_EVENT:
1244 return TRUE;
1245 default:
1246 ok(0, "Unexpected message %u\n", ir.EventType);
1247 }
1248 return FALSE;
1249}
1250
1251static void test_wait(HANDLE input, HANDLE orig_output)
1252{
1253 HANDLE output, unbound_output, unbound_input;
1254 LARGE_INTEGER zero;
1255 INPUT_RECORD ir;
1256 DWORD res, count;
1257 NTSTATUS status;
1258 BOOL ret;
1259
1260 if (skip_nt) return;
1261
1262 memset(&ir, 0, sizeof(ir));
1263 ir.EventType = MOUSE_EVENT;
1264 ir.Event.MouseEvent.dwEventFlags = MOUSE_MOVED;
1265 zero.QuadPart = 0;
1266
1267 output = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
1268 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1269 CONSOLE_TEXTMODE_BUFFER, NULL);
1270 ok(output != INVALID_HANDLE_VALUE, "CreateConsoleScreenBuffer failed: %lu\n", GetLastError());
1271
1272 ret = SetConsoleActiveScreenBuffer(output);
1273 ok(ret, "SetConsoleActiveScreenBuffer failed: %lu\n", GetLastError());
1274 ret = FlushConsoleInputBuffer(input);
1275 ok(ret, "FlushConsoleInputBuffer failed: %lu\n", GetLastError());
1276
1277 unbound_output = create_unbound_handle(TRUE, TRUE);
1278 unbound_input = create_unbound_handle(FALSE, TRUE);
1279
1280 while ((res = WaitForSingleObject(input, 0)) == WAIT_OBJECT_0)
1281 {
1282 if (!filter_spurious_event(input)) break;
1283 }
1284 ok(res == WAIT_TIMEOUT, "WaitForSingleObject returned %lx\n", res);
1285 while ((res = WaitForSingleObject(output, 0)) == WAIT_OBJECT_0)
1286 {
1287 if (!filter_spurious_event(input)) break;
1288 }
1289 ok(res == WAIT_TIMEOUT, "WaitForSingleObject returned %lx\n", res);
1290 while ((res = WaitForSingleObject(orig_output, 0)) == WAIT_OBJECT_0)
1291 {
1292 if (!filter_spurious_event(input)) break;
1293 }
1294 ok(res == WAIT_TIMEOUT, "WaitForSingleObject returned %lx\n", res);
1295 while ((res = WaitForSingleObject(unbound_output, 0)) == WAIT_OBJECT_0)
1296 {
1297 if (!filter_spurious_event(unbound_input)) break;
1298 }
1299 ok(res == WAIT_TIMEOUT, "WaitForSingleObject returned %lx\n", res);
1300 while ((res = WaitForSingleObject(unbound_input, 0)) == WAIT_OBJECT_0)
1301 {
1302 if (!filter_spurious_event(unbound_input)) break;
1303 }
1304 ok(res == WAIT_TIMEOUT, "WaitForSingleObject returned %lx\n", res);
1305 while ((status = NtWaitForSingleObject(input, FALSE, &zero)) == STATUS_SUCCESS)
1306 {
1307 if (!filter_spurious_event(input)) break;
1308 }
1309 ok(status == STATUS_TIMEOUT || broken(status == STATUS_ACCESS_DENIED /* win2k8 */),
1310 "NtWaitForSingleObject returned %lx\n", status);
1311 while ((status = NtWaitForSingleObject(output, FALSE, &zero)) == STATUS_SUCCESS)
1312 {
1313 if (!filter_spurious_event(input)) break;
1314 }
1315 ok(status == STATUS_TIMEOUT || broken(status == STATUS_ACCESS_DENIED /* win2k8 */),
1316 "NtWaitForSingleObject returned %lx\n", status);
1317
1318 ret = WriteConsoleInputW(input, &ir, 1, &count);
1319 ok(ret, "WriteConsoleInputW failed: %lu\n", GetLastError());
1320
1321 res = WaitForSingleObject(input, 0);
1322 ok(!res, "WaitForSingleObject returned %lx\n", res);
1323 res = WaitForSingleObject(output, 0);
1324 ok(!res, "WaitForSingleObject returned %lx\n", res);
1325 res = WaitForSingleObject(orig_output, 0);
1326 ok(!res, "WaitForSingleObject returned %lx\n", res);
1327 res = WaitForSingleObject(unbound_output, 0);
1328 ok(!res, "WaitForSingleObject returned %lx\n", res);
1329 res = WaitForSingleObject(unbound_input, 0);
1330 ok(!res, "WaitForSingleObject returned %lx\n", res);
1331 status = NtWaitForSingleObject(input, FALSE, &zero);
1332 ok(!status || broken(status == STATUS_ACCESS_DENIED /* win2k8 */),
1333 "NtWaitForSingleObject returned %lx\n", status);
1334 status = NtWaitForSingleObject(output, FALSE, &zero);
1335 ok(!status || broken(status == STATUS_ACCESS_DENIED /* win2k8 */),
1336 "NtWaitForSingleObject returned %lx\n", status);
1337
1338 ret = SetConsoleActiveScreenBuffer(orig_output);
1339 ok(ret, "SetConsoleActiveScreenBuffer failed: %lu\n", GetLastError());
1340
1341 CloseHandle(unbound_input);
1342 CloseHandle(unbound_output);
1343 CloseHandle(output);
1344}
1345
1346static void test_GetSetConsoleInputExeName(void)
1347{
1348 BOOL ret;
1349 DWORD error;
1350 char buffer[MAX_PATH], module[MAX_PATH], *p;
1351 static char input_exe[MAX_PATH] = "winetest.exe";
1352
1353 SetLastError(0xdeadbeef);
1354 ret = pGetConsoleInputExeNameA(0, NULL);
1355 error = GetLastError();
1356 ok(ret, "GetConsoleInputExeNameA failed\n");
1357 ok(error == ERROR_BUFFER_OVERFLOW, "got %lu expected ERROR_BUFFER_OVERFLOW\n", error);
1358
1359 SetLastError(0xdeadbeef);
1360 ret = pGetConsoleInputExeNameA(0, buffer);
1361 error = GetLastError();
1362 ok(ret, "GetConsoleInputExeNameA failed\n");
1363 ok(error == ERROR_BUFFER_OVERFLOW, "got %lu expected ERROR_BUFFER_OVERFLOW\n", error);
1364
1365 GetModuleFileNameA(GetModuleHandleA(NULL), module, sizeof(module));
1366 p = strrchr(module, '\\') + 1;
1367
1368 ret = pGetConsoleInputExeNameA(ARRAY_SIZE(buffer), buffer);
1369 ok(ret, "GetConsoleInputExeNameA failed\n");
1370 todo_wine ok(!lstrcmpA(buffer, p), "got %s expected %s\n", buffer, p);
1371
1372 SetLastError(0xdeadbeef);
1373 ret = pSetConsoleInputExeNameA(NULL);
1374 error = GetLastError();
1375 ok(!ret, "SetConsoleInputExeNameA failed\n");
1376 ok(error == ERROR_INVALID_PARAMETER, "got %lu expected ERROR_INVALID_PARAMETER\n", error);
1377
1378 SetLastError(0xdeadbeef);
1379 ret = pSetConsoleInputExeNameA("");
1380 error = GetLastError();
1381 ok(!ret, "SetConsoleInputExeNameA failed\n");
1382 ok(error == ERROR_INVALID_PARAMETER, "got %lu expected ERROR_INVALID_PARAMETER\n", error);
1383
1384 ret = pSetConsoleInputExeNameA(input_exe);
1385 ok(ret, "SetConsoleInputExeNameA failed\n");
1386
1387 ret = pGetConsoleInputExeNameA(ARRAY_SIZE(buffer), buffer);
1388 ok(ret, "GetConsoleInputExeNameA failed\n");
1389 ok(!lstrcmpA(buffer, input_exe), "got %s expected %s\n", buffer, input_exe);
1390}
1391
1392static void test_GetConsoleProcessList(void)
1393{
1394 DWORD ret, *list = NULL;
1395
1396 if (!pGetConsoleProcessList)
1397 {
1398 win_skip("GetConsoleProcessList is not available\n");
1399 return;
1400 }
1401
1402 SetLastError(0xdeadbeef);
1403 ret = pGetConsoleProcessList(NULL, 0);
1404 ok(ret == 0, "Expected failure\n");
1405 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1406 "Expected ERROR_INVALID_PARAMETER, got %ld\n",
1407 GetLastError());
1408
1409 SetLastError(0xdeadbeef);
1410 ret = pGetConsoleProcessList(NULL, 1);
1411 ok(ret == 0, "Expected failure\n");
1412 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1413 "Expected ERROR_INVALID_PARAMETER, got %ld\n",
1414 GetLastError());
1415
1416 /* We should only have 1 process but only for these specific unit tests as
1417 * we created our own console. An AttachConsole(ATTACH_PARENT_PROCESS)
1418 * gives us two processes - see test_AttachConsole.
1419 */
1420 list = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD));
1421
1422 SetLastError(0xdeadbeef);
1423 ret = pGetConsoleProcessList(list, 0);
1424 ok(ret == 0, "Expected failure\n");
1425 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1426 "Expected ERROR_INVALID_PARAMETER, got %ld\n",
1427 GetLastError());
1428
1429 SetLastError(0xdeadbeef);
1430 ret = pGetConsoleProcessList(list, 1);
1431 ok(ret == 1, "Expected 1, got %ld\n", ret);
1432
1433 HeapFree(GetProcessHeap(), 0, list);
1434
1435 list = HeapAlloc(GetProcessHeap(), 0, ret * sizeof(DWORD));
1436
1437 SetLastError(0xdeadbeef);
1438 ret = pGetConsoleProcessList(list, ret);
1439 ok(ret == 1, "Expected 1, got %ld\n", ret);
1440
1441 if (ret == 1)
1442 {
1443 DWORD pid = GetCurrentProcessId();
1444 ok(list[0] == pid, "Expected %ld, got %ld\n", pid, list[0]);
1445 }
1446
1447 HeapFree(GetProcessHeap(), 0, list);
1448}
1449
1450static void test_OpenCON(void)
1451{
1452 static const WCHAR conW[] = {'C','O','N',0};
1453 static const DWORD accesses[] = {CREATE_NEW, CREATE_ALWAYS, OPEN_EXISTING,
1454 OPEN_ALWAYS, TRUNCATE_EXISTING};
1455 unsigned i;
1456 HANDLE h;
1457
1458 for (i = 0; i < ARRAY_SIZE(accesses); i++)
1459 {
1460 h = CreateFileW(conW, GENERIC_WRITE, 0, NULL, accesses[i], 0, NULL);
1461 ok(h != INVALID_HANDLE_VALUE || broken(accesses[i] == TRUNCATE_EXISTING /* Win8 */),
1462 "Expected to open the CON device on write (%lx)\n", accesses[i]);
1463 CloseHandle(h);
1464
1465 h = CreateFileW(conW, GENERIC_READ, 0, NULL, accesses[i], 0, NULL);
1466 /* Windows versions differ here:
1467 * MSDN states in CreateFile that TRUNCATE_EXISTING requires GENERIC_WRITE
1468 * NT, XP, Vista comply, but Win7 doesn't and allows opening CON with TRUNCATE_EXISTING
1469 * So don't test when disposition is TRUNCATE_EXISTING
1470 */
1471 ok(h != INVALID_HANDLE_VALUE || broken(accesses[i] == TRUNCATE_EXISTING /* Win7+ */),
1472 "Expected to open the CON device on read (%lx)\n", accesses[i]);
1473 CloseHandle(h);
1474 h = CreateFileW(conW, GENERIC_READ|GENERIC_WRITE, 0, NULL, accesses[i], 0, NULL);
1475 ok(h == INVALID_HANDLE_VALUE, "Expected not to open the CON device on read-write (%lx)\n", accesses[i]);
1476 ok(GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_INVALID_PARAMETER,
1477 "Unexpected error %lx\n", GetLastError());
1478 }
1479}
1480
1481static void test_OpenConsoleW(void)
1482{
1483 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
1484 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
1485 static const WCHAR emptyW[] = {0};
1486 static const WCHAR invalidW[] = {'I','N','V','A','L','I','D',0};
1487 DWORD gle;
1488
1489 static const struct
1490 {
1491 LPCWSTR name;
1492 DWORD access;
1493 BOOL inherit;
1494 DWORD creation;
1495 DWORD gle, gle2;
1496 } invalid_table[] = {
1497 {NULL, 0, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1498 {NULL, 0, FALSE, 0xdeadbeef, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1499 {NULL, 0xdeadbeef, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1500 {NULL, 0xdeadbeef, TRUE, 0xdeadbeef, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1501 {NULL, 0, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1502 {NULL, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1503 {NULL, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1504 {NULL, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1505 {emptyW, 0, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1506 {emptyW, 0, FALSE, 0xdeadbeef, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1507 {emptyW, 0xdeadbeef, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1508 {emptyW, 0xdeadbeef, TRUE, 0xdeadbeef, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1509 {emptyW, 0, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1510 {emptyW, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1511 {emptyW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1512 {emptyW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING, ERROR_INVALID_PARAMETER, ERROR_PATH_NOT_FOUND},
1513 {invalidW, 0, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1514 {invalidW, 0, FALSE, 0xdeadbeef, ERROR_INVALID_PARAMETER, 0},
1515 {invalidW, 0xdeadbeef, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1516 {invalidW, 0xdeadbeef, TRUE, 0xdeadbeef, ERROR_INVALID_PARAMETER, 0},
1517 {invalidW, 0, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1518 {invalidW, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1519 {invalidW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1520 {invalidW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING, ERROR_INVALID_PARAMETER, ERROR_FILE_NOT_FOUND},
1521 {coninW, 0, FALSE, 0xdeadbeef, ERROR_INVALID_PARAMETER, 0},
1522 {coninW, 0xdeadbeef, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_ACCESS_DENIED},
1523 {coninW, 0xdeadbeef, TRUE, 0xdeadbeef, ERROR_INVALID_PARAMETER, 0},
1524 {conoutW, 0, FALSE, 0xdeadbeef, ERROR_INVALID_PARAMETER, 0},
1525 {conoutW, 0xceadbeef, FALSE, 0, ERROR_INVALID_PARAMETER, ERROR_ACCESS_DENIED},
1526 {conoutW, 0xdeadbeef, TRUE, 0xdeadbeef, ERROR_INVALID_PARAMETER, 0},
1527 };
1528 static const struct
1529 {
1530 LPCWSTR name;
1531 DWORD access;
1532 BOOL inherit;
1533 DWORD creation;
1534 } valid_table[] = {
1535 {coninW, 0, FALSE, 0 },
1536 {coninW, 0, TRUE, 0 },
1537 {coninW, GENERIC_EXECUTE, TRUE, 0 },
1538 {coninW, GENERIC_ALL, TRUE, 0 },
1539 {coninW, 0, FALSE, OPEN_ALWAYS },
1540 {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, 0 },
1541 {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_NEW },
1542 {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_ALWAYS },
1543 {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS },
1544 {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, TRUNCATE_EXISTING},
1545 {conoutW, 0, FALSE, 0 },
1546 {conoutW, 0, FALSE, OPEN_ALWAYS },
1547 {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, 0 },
1548 {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_NEW, },
1549 {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_ALWAYS },
1550 {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS },
1551 {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, TRUNCATE_EXISTING},
1552 };
1553
1554 int index;
1555 HANDLE ret;
1556
1557 if (!pOpenConsoleW)
1558 {
1559 win_skip("OpenConsoleW is not available\n");
1560 return;
1561 }
1562
1563 for (index = 0; index < ARRAY_SIZE(invalid_table); index++)
1564 {
1565 SetLastError(0xdeadbeef);
1566 ret = pOpenConsoleW(invalid_table[index].name, invalid_table[index].access,
1567 invalid_table[index].inherit, invalid_table[index].creation);
1568 gle = GetLastError();
1569 ok(ret == INVALID_HANDLE_VALUE,
1570 "Expected OpenConsoleW to return INVALID_HANDLE_VALUE for index %d, got %p\n",
1571 index, ret);
1572 ok(gle == invalid_table[index].gle || (gle != 0 && gle == invalid_table[index].gle2),
1573 "Expected GetLastError() to return %lu/%lu for index %d, got %lu\n",
1574 invalid_table[index].gle, invalid_table[index].gle2, index, gle);
1575 }
1576
1577 for (index = 0; index < ARRAY_SIZE(valid_table); index++)
1578 {
1579 ret = pOpenConsoleW(valid_table[index].name, valid_table[index].access,
1580 valid_table[index].inherit, valid_table[index].creation);
1581 todo_wine
1582 ok(ret != INVALID_HANDLE_VALUE || broken(ret == INVALID_HANDLE_VALUE /* until Win7 */),
1583 "Expected OpenConsoleW to succeed for index %d, got %p\n", index, ret);
1584 if (ret != INVALID_HANDLE_VALUE)
1585 CloseHandle(ret);
1586 }
1587
1588 ret = pOpenConsoleW(coninW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING);
1589 ok(ret != INVALID_HANDLE_VALUE, "Expected OpenConsoleW to return a valid handle\n");
1590 if (ret != INVALID_HANDLE_VALUE)
1591 CloseHandle(ret);
1592
1593 ret = pOpenConsoleW(conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING);
1594 ok(ret != INVALID_HANDLE_VALUE, "Expected OpenConsoleW to return a valid handle\n");
1595 if (ret != INVALID_HANDLE_VALUE)
1596 CloseHandle(ret);
1597}
1598
1599static void test_CreateFileW(void)
1600{
1601 static const struct
1602 {
1603 BOOL input;
1604 DWORD access;
1605 BOOL inherit;
1606 DWORD creation;
1607 DWORD gle;
1608 BOOL is_broken;
1609 } cf_table[] = {
1610 {TRUE, 0, FALSE, OPEN_ALWAYS, 0, FALSE},
1611 {TRUE, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_INVALID_PARAMETER, TRUE},
1612 {TRUE, 0, FALSE, 0, ERROR_INVALID_PARAMETER, TRUE},
1613 {TRUE, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_NEW, 0, FALSE},
1614 {TRUE, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_ALWAYS, 0, FALSE},
1615 {TRUE, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, 0, FALSE},
1616 {FALSE, 0, FALSE, 0, ERROR_INVALID_PARAMETER, TRUE},
1617 {FALSE, 0, FALSE, OPEN_ALWAYS, 0, FALSE},
1618 {FALSE, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_INVALID_PARAMETER, TRUE},
1619 {FALSE, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_NEW, 0, FALSE},
1620 {FALSE, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_ALWAYS, 0, FALSE},
1621 {FALSE, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, 0, FALSE},
1622 /* TRUNCATE_EXISTING is forbidden starting with Windows 8 */
1623 };
1624
1625 static const UINT nt_disposition[5] =
1626 {
1627 FILE_CREATE, /* CREATE_NEW */
1628 FILE_OVERWRITE_IF, /* CREATE_ALWAYS */
1629 FILE_OPEN, /* OPEN_EXISTING */
1630 FILE_OPEN_IF, /* OPEN_ALWAYS */
1631 FILE_OVERWRITE /* TRUNCATE_EXISTING */
1632 };
1633
1634 int index;
1635 HANDLE ret;
1636 SECURITY_ATTRIBUTES sa;
1637 OBJECT_ATTRIBUTES attr = {sizeof(attr)};
1638 UNICODE_STRING string;
1639 IO_STATUS_BLOCK iosb;
1640 NTSTATUS status;
1641
1642 for (index = 0; index < ARRAY_SIZE(cf_table); index++)
1643 {
1644 SetLastError(0xdeadbeef);
1645
1646 sa.nLength = sizeof(sa);
1647 sa.lpSecurityDescriptor = NULL;
1648 sa.bInheritHandle = cf_table[index].inherit;
1649
1650 ret = CreateFileW(cf_table[index].input ? L"CONIN$" : L"CONOUT$", cf_table[index].access,
1651 FILE_SHARE_READ|FILE_SHARE_WRITE, &sa,
1652 cf_table[index].creation, FILE_ATTRIBUTE_NORMAL, NULL);
1653 if (ret == INVALID_HANDLE_VALUE)
1654 {
1655 ok(cf_table[index].gle,
1656 "Expected CreateFileW not to return INVALID_HANDLE_VALUE for index %d\n", index);
1657 ok(GetLastError() == cf_table[index].gle,
1658 "Expected GetLastError() to return %lu for index %d, got %lu\n",
1659 cf_table[index].gle, index, GetLastError());
1660 }
1661 else
1662 {
1663 ok(!cf_table[index].gle || broken(cf_table[index].is_broken) /* Win7 */,
1664 "Expected CreateFileW to succeed for index %d\n", index);
1665 CloseHandle(ret);
1666 }
1667
1668 if (skip_nt) continue;
1669
1670 SetLastError(0xdeadbeef);
1671
1672 sa.nLength = sizeof(sa);
1673 sa.lpSecurityDescriptor = NULL;
1674 sa.bInheritHandle = cf_table[index].inherit;
1675
1676 ret = CreateFileW(cf_table[index].input ? L"\\??\\CONIN$" : L"\\??\\CONOUT$", cf_table[index].access,
1677 FILE_SHARE_READ|FILE_SHARE_WRITE, &sa,
1678 cf_table[index].creation, FILE_ATTRIBUTE_NORMAL, NULL);
1679 if (cf_table[index].gle)
1680 ok(ret == INVALID_HANDLE_VALUE && GetLastError() == cf_table[index].gle,
1681 "CreateFileW to returned %p %lu for index %d\n", ret, GetLastError(), index);
1682 else
1683 ok(ret != INVALID_HANDLE_VALUE && (!cf_table[index].gle || broken(cf_table[index].is_broken) /* Win7 */),
1684 "CreateFileW to returned %p %lu for index %d\n", ret, GetLastError(), index);
1685 if (ret != INVALID_HANDLE_VALUE) CloseHandle(ret);
1686
1687 if (cf_table[index].gle) continue;
1688
1689 RtlInitUnicodeString(&string, cf_table[index].input
1690 ? L"\\Device\\ConDrv\\CurrentIn" : L"\\Device\\ConDrv\\CurrentOut");
1691 attr.ObjectName = &string;
1692 status = NtCreateFile(&ret, cf_table[index].access | SYNCHRONIZE | FILE_READ_ATTRIBUTES, &attr, &iosb, NULL,
1693 FILE_ATTRIBUTE_NORMAL, 0, nt_disposition[cf_table[index].creation - CREATE_NEW],
1694 FILE_NON_DIRECTORY_FILE, NULL, 0);
1695 ok(!status, "NtCreateFile failed %lx for %u\n", status, index);
1696 CloseHandle(ret);
1697
1698 RtlInitUnicodeString(&string, cf_table[index].input ? L"\\??\\CONIN$" : L"\\??\\CONOUT$");
1699 attr.ObjectName = &string;
1700 status = NtCreateFile(&ret, cf_table[index].access | SYNCHRONIZE | FILE_READ_ATTRIBUTES, &attr, &iosb, NULL,
1701 FILE_ATTRIBUTE_NORMAL, 0, nt_disposition[cf_table[index].creation - CREATE_NEW],
1702 FILE_NON_DIRECTORY_FILE, NULL, 0);
1703 ok(!status, "NtCreateFile failed %lx for %u\n", status, index);
1704 CloseHandle(ret);
1705 }
1706}
1707
1708static void test_VerifyConsoleIoHandle( HANDLE handle )
1709{
1710 BOOL ret;
1711 DWORD error;
1712
1713 if (!pVerifyConsoleIoHandle)
1714 {
1715 win_skip("VerifyConsoleIoHandle is not available\n");
1716 return;
1717 }
1718
1719 /* invalid handle */
1720 SetLastError(0xdeadbeef);
1721 ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee0);
1722 error = GetLastError();
1723 ok(!ret, "expected VerifyConsoleIoHandle to fail\n");
1724 ok(error == 0xdeadbeef, "wrong GetLastError() %ld\n", error);
1725
1726 /* invalid handle + 1 */
1727 SetLastError(0xdeadbeef);
1728 ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee1);
1729 error = GetLastError();
1730 ok(!ret, "expected VerifyConsoleIoHandle to fail\n");
1731 ok(error == 0xdeadbeef, "wrong GetLastError() %ld\n", error);
1732
1733 /* invalid handle + 2 */
1734 SetLastError(0xdeadbeef);
1735 ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee2);
1736 error = GetLastError();
1737 ok(!ret, "expected VerifyConsoleIoHandle to fail\n");
1738 ok(error == 0xdeadbeef, "wrong GetLastError() %ld\n", error);
1739
1740 /* invalid handle + 3 */
1741 SetLastError(0xdeadbeef);
1742 ret = pVerifyConsoleIoHandle((HANDLE)0xdeadbee3);
1743 error = GetLastError();
1744 ok(!ret, "expected VerifyConsoleIoHandle to fail\n");
1745 ok(error == 0xdeadbeef, "wrong GetLastError() %ld\n", error);
1746
1747 /* valid handle */
1748 SetLastError(0xdeadbeef);
1749 ret = pVerifyConsoleIoHandle(handle);
1750 error = GetLastError();
1751 ok(ret ||
1752 broken(!ret), /* Windows 8 and 10 */
1753 "expected VerifyConsoleIoHandle to succeed\n");
1754 ok(error == 0xdeadbeef, "wrong GetLastError() %ld\n", error);
1755}
1756
1757static void test_GetSetStdHandle(void)
1758{
1759 HANDLE handle;
1760 DWORD error;
1761 BOOL ret;
1762
1763 /* get invalid std handle */
1764 SetLastError(0xdeadbeef);
1765 handle = GetStdHandle(42);
1766 error = GetLastError();
1767 ok(error == ERROR_INVALID_HANDLE || broken(error == ERROR_INVALID_FUNCTION)/* Win9x */,
1768 "wrong GetLastError() %ld\n", error);
1769 ok(handle == INVALID_HANDLE_VALUE, "expected INVALID_HANDLE_VALUE\n");
1770
1771 /* get valid */
1772 SetLastError(0xdeadbeef);
1773 handle = GetStdHandle(STD_INPUT_HANDLE);
1774 error = GetLastError();
1775 ok(error == 0xdeadbeef, "wrong GetLastError() %ld\n", error);
1776
1777 /* set invalid std handle */
1778 SetLastError(0xdeadbeef);
1779 ret = SetStdHandle(42, handle);
1780 error = GetLastError();
1781 ok(!ret, "expected SetStdHandle to fail\n");
1782 ok(error == ERROR_INVALID_HANDLE || broken(error == ERROR_INVALID_FUNCTION)/* Win9x */,
1783 "wrong GetLastError() %ld\n", error);
1784
1785 /* set valid (restore old value) */
1786 SetLastError(0xdeadbeef);
1787 ret = SetStdHandle(STD_INPUT_HANDLE, handle);
1788 error = GetLastError();
1789 ok(ret, "expected SetStdHandle to succeed\n");
1790 ok(error == 0xdeadbeef, "wrong GetLastError() %ld\n", error);
1791}
1792
1793static void test_DuplicateConsoleHandle(void)
1794{
1795 HANDLE handle, event;
1796 BOOL ret;
1797
1798 if (skip_nt) return;
1799
1800 event = CreateEventW(NULL, TRUE, FALSE, NULL);
1801
1802 /* duplicate an event handle with DuplicateConsoleHandle */
1803 handle = DuplicateConsoleHandle(event, 0, FALSE, DUPLICATE_SAME_ACCESS);
1804 ok(handle != NULL, "DuplicateConsoleHandle failed: %lu\n", GetLastError());
1805
1806 ret = SetEvent(handle);
1807 ok(ret, "SetEvent failed: %lu\n", GetLastError());
1808
1809 ret = CloseConsoleHandle(handle);
1810 ok(ret, "CloseConsoleHandle failed: %lu\n", GetLastError());
1811 ret = CloseConsoleHandle(event);
1812 ok(ret, "CloseConsoleHandle failed: %lu\n", GetLastError());
1813
1814 handle = DuplicateConsoleHandle((HANDLE)0xdeadbeef, 0, FALSE, DUPLICATE_SAME_ACCESS);
1815 ok(handle == INVALID_HANDLE_VALUE, "DuplicateConsoleHandle failed: %lu\n", GetLastError());
1816 ok(GetLastError() == ERROR_INVALID_HANDLE, "last error = %lu\n", GetLastError());
1817}
1818
1819static void test_GetNumberOfConsoleInputEvents(HANDLE input_handle)
1820{
1821 DWORD count;
1822 BOOL ret;
1823 int i;
1824
1825 const struct
1826 {
1827 HANDLE handle;
1828 LPDWORD nrofevents;
1829 DWORD last_error;
1830 } invalid_table[] =
1831 {
1832 {NULL, NULL, ERROR_INVALID_HANDLE},
1833 {NULL, &count, ERROR_INVALID_HANDLE},
1834 {INVALID_HANDLE_VALUE, NULL, ERROR_INVALID_HANDLE},
1835 {INVALID_HANDLE_VALUE, &count, ERROR_INVALID_HANDLE},
1836 };
1837
1838 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
1839 {
1840 SetLastError(0xdeadbeef);
1841 if (invalid_table[i].nrofevents) count = 0xdeadbeef;
1842 ret = GetNumberOfConsoleInputEvents(invalid_table[i].handle,
1843 invalid_table[i].nrofevents);
1844 ok(!ret, "[%d] Expected GetNumberOfConsoleInputEvents to return FALSE, got %d\n", i, ret);
1845 if (invalid_table[i].nrofevents)
1846 {
1847 ok(count == 0xdeadbeef,
1848 "[%d] Expected output count to be unmodified, got %lu\n", i, count);
1849 }
1850 ok(GetLastError() == invalid_table[i].last_error,
1851 "[%d] Expected last error to be %lu, got %lu\n",
1852 i, invalid_table[i].last_error, GetLastError());
1853 }
1854
1855 /* Test crashes on Windows 7. */
1856 if (0)
1857 {
1858 SetLastError(0xdeadbeef);
1859 ret = GetNumberOfConsoleInputEvents(input_handle, NULL);
1860 ok(!ret, "Expected GetNumberOfConsoleInputEvents to return FALSE, got %d\n", ret);
1861 ok(GetLastError() == ERROR_INVALID_ACCESS,
1862 "Expected last error to be ERROR_INVALID_ACCESS, got %lu\n",
1863 GetLastError());
1864 }
1865
1866 count = 0xdeadbeef;
1867 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1868 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1869 ok(count != 0xdeadbeef, "Expected output count to initialized\n");
1870}
1871
1872static void test_WriteConsoleInputA(HANDLE input_handle)
1873{
1874 INPUT_RECORD event;
1875 INPUT_RECORD event_list[5];
1876 MOUSE_EVENT_RECORD mouse_event = { {0, 0}, 0, 0, MOUSE_MOVED };
1877 KEY_EVENT_RECORD key_event;
1878 DWORD count, console_mode, gle;
1879 BOOL ret;
1880 int i;
1881
1882 const struct
1883 {
1884 HANDLE handle;
1885 const INPUT_RECORD *buffer;
1886 DWORD count;
1887 LPDWORD written;
1888 DWORD gle, gle2;
1889 int win_crash;
1890 } invalid_table[] =
1891 {
1892 {NULL, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1893 {NULL, NULL, 0, &count,ERROR_INVALID_HANDLE},
1894 {NULL, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1895 {NULL, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
1896 {NULL, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1897 {NULL, &event, 0, &count, ERROR_INVALID_HANDLE},
1898 {NULL, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1899 {NULL, &event, 1, &count, ERROR_INVALID_HANDLE},
1900 {INVALID_HANDLE_VALUE, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1901 {INVALID_HANDLE_VALUE, NULL, 0, &count, ERROR_INVALID_HANDLE},
1902 {INVALID_HANDLE_VALUE, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1903 {INVALID_HANDLE_VALUE, NULL, 1, &count, ERROR_INVALID_HANDLE, ERROR_INVALID_ACCESS},
1904 {INVALID_HANDLE_VALUE, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1905 {INVALID_HANDLE_VALUE, &event, 0, &count, ERROR_INVALID_HANDLE},
1906 {INVALID_HANDLE_VALUE, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1907 {INVALID_HANDLE_VALUE, &event, 1, &count, ERROR_INVALID_HANDLE},
1908 {input_handle, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1909 {input_handle, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1910 {input_handle, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
1911 {input_handle, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
1912 {input_handle, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
1913 };
1914
1915 /* Suppress external sources of input events for the duration of the test. */
1916 ret = GetConsoleMode(input_handle, &console_mode);
1917 ok(ret == TRUE, "Expected GetConsoleMode to return TRUE, got %d\n", ret);
1918 if (!ret)
1919 {
1920 skip("GetConsoleMode failed with last error %lu\n", GetLastError());
1921 return;
1922 }
1923
1924 ret = SetConsoleMode(input_handle, console_mode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
1925 ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret);
1926 if (!ret)
1927 {
1928 skip("SetConsoleMode failed with last error %lu\n", GetLastError());
1929 return;
1930 }
1931
1932 /* Discard any events queued before the tests. */
1933 ret = FlushConsoleInputBuffer(input_handle);
1934 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1935
1936 event.EventType = MOUSE_EVENT;
1937 event.Event.MouseEvent = mouse_event;
1938
1939 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
1940 {
1941 if (invalid_table[i].win_crash)
1942 continue;
1943
1944 SetLastError(0xdeadbeef);
1945 if (invalid_table[i].written) count = 0xdeadbeef;
1946 ret = WriteConsoleInputA(invalid_table[i].handle,
1947 invalid_table[i].buffer,
1948 invalid_table[i].count,
1949 invalid_table[i].written);
1950 ok(!ret, "[%d] Expected WriteConsoleInputA to return FALSE, got %d\n", i, ret);
1951 gle = GetLastError();
1952 ok(gle == invalid_table[i].gle || (gle != 0 && gle == invalid_table[i].gle2),
1953 "[%d] Expected last error to be %lu or %lu, got %lu\n",
1954 i, invalid_table[i].gle, invalid_table[i].gle2, gle);
1955 }
1956
1957 count = 0xdeadbeef;
1958 ret = WriteConsoleInputA(input_handle, NULL, 0, &count);
1959 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1960 ok(count == 0, "Expected count to be 0, got %lu\n", count);
1961
1962 count = 0xdeadbeef;
1963 ret = WriteConsoleInputA(input_handle, &event, 0, &count);
1964 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1965 ok(count == 0, "Expected count to be 0, got %lu\n", count);
1966
1967 count = 0xdeadbeef;
1968 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1969 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1970 ok(count == 1, "Expected count to be 1, got %lu\n", count);
1971
1972 ret = FlushConsoleInputBuffer(input_handle);
1973 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1974
1975 /* Writing a single mouse event doesn't seem to affect the count if an adjacent mouse event is already queued. */
1976 event.EventType = MOUSE_EVENT;
1977 event.Event.MouseEvent = mouse_event;
1978
1979 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1980 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1981 ok(count == 1, "Expected count to be 1, got %lu\n", count);
1982
1983 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1984 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1985 ok(count == 1, "Expected count to be 1, got %lu\n", count);
1986
1987 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
1988 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
1989 ok(count == 1, "Expected count to be 1, got %lu\n", count);
1990
1991 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
1992 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
1993 todo_wine
1994 ok(count == 1, "Expected count to be 1, got %lu\n", count);
1995
1996 ret = FlushConsoleInputBuffer(input_handle);
1997 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
1998
1999 for (i = 0; i < ARRAY_SIZE(event_list); i++)
2000 {
2001 event_list[i].EventType = MOUSE_EVENT;
2002 event_list[i].Event.MouseEvent = mouse_event;
2003 }
2004
2005 /* Writing consecutive chunks of mouse events appears to work. */
2006 ret = WriteConsoleInputA(input_handle, event_list, ARRAY_SIZE(event_list), &count);
2007 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
2008 ok(count == ARRAY_SIZE(event_list),
2009 "Expected count to be event list length, got %lu\n", count);
2010
2011 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2012 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2013 ok(count == ARRAY_SIZE(event_list),
2014 "Expected count to be event list length, got %lu\n", count);
2015
2016 ret = WriteConsoleInputA(input_handle, event_list, ARRAY_SIZE(event_list), &count);
2017 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
2018 ok(count == ARRAY_SIZE(event_list),
2019 "Expected count to be event list length, got %lu\n", count);
2020
2021 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2022 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2023 ok(count == 2*ARRAY_SIZE(event_list),
2024 "Expected count to be twice event list length, got %lu\n", count);
2025
2026 /* Again, writing a single mouse event with adjacent mouse events queued doesn't appear to affect the count. */
2027 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
2028 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
2029 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2030
2031 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2032 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2033 todo_wine
2034 ok(count == 2*ARRAY_SIZE(event_list),
2035 "Expected count to be twice event list length, got %lu\n", count);
2036
2037 ret = FlushConsoleInputBuffer(input_handle);
2038 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
2039
2040 key_event.bKeyDown = FALSE;
2041 key_event.wRepeatCount = 0;
2042 key_event.wVirtualKeyCode = VK_SPACE;
2043 key_event.wVirtualScanCode = VK_SPACE;
2044 key_event.uChar.AsciiChar = ' ';
2045 key_event.dwControlKeyState = 0;
2046
2047 event.EventType = KEY_EVENT;
2048 event.Event.KeyEvent = key_event;
2049
2050 /* Key events don't exhibit the same behavior as mouse events. */
2051 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
2052 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
2053 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2054
2055 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2056 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2057 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2058
2059 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
2060 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
2061 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2062
2063 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2064 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2065 ok(count == 2, "Expected count to be 2, got %lu\n", count);
2066
2067 ret = FlushConsoleInputBuffer(input_handle);
2068 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
2069
2070 /* Try interleaving mouse and key events. */
2071 event.EventType = MOUSE_EVENT;
2072 event.Event.MouseEvent = mouse_event;
2073
2074 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
2075 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
2076 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2077
2078 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2079 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2080 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2081
2082 event.EventType = KEY_EVENT;
2083 event.Event.KeyEvent = key_event;
2084
2085 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
2086 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
2087 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2088
2089 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2090 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2091 ok(count == 2, "Expected count to be 2, got %lu\n", count);
2092
2093 event.EventType = MOUSE_EVENT;
2094 event.Event.MouseEvent = mouse_event;
2095
2096 ret = WriteConsoleInputA(input_handle, &event, 1, &count);
2097 ok(ret == TRUE, "Expected WriteConsoleInputA to return TRUE, got %d\n", ret);
2098 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2099
2100 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2101 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2102 ok(count == 3, "Expected count to be 3, got %lu\n", count);
2103
2104 /* Restore the old console mode. */
2105 ret = SetConsoleMode(input_handle, console_mode);
2106 ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret);
2107}
2108
2109static void test_WriteConsoleInputW(HANDLE input_handle)
2110{
2111 INPUT_RECORD event;
2112 INPUT_RECORD event_list[5];
2113 MOUSE_EVENT_RECORD mouse_event = { {0, 0}, 0, 0, MOUSE_MOVED };
2114 KEY_EVENT_RECORD key_event;
2115 DWORD count, console_mode, gle;
2116 BOOL ret;
2117 int i;
2118
2119 const struct
2120 {
2121 HANDLE handle;
2122 const INPUT_RECORD *buffer;
2123 DWORD count;
2124 LPDWORD written;
2125 DWORD gle, gle2;
2126 int win_crash;
2127 } invalid_table[] =
2128 {
2129 {NULL, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
2130 {NULL, NULL, 0, &count, ERROR_INVALID_HANDLE},
2131 {NULL, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
2132 {NULL, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
2133 {NULL, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
2134 {NULL, &event, 0, &count, ERROR_INVALID_HANDLE},
2135 {NULL, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
2136 {NULL, &event, 1, &count, ERROR_INVALID_HANDLE},
2137 {INVALID_HANDLE_VALUE, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
2138 {INVALID_HANDLE_VALUE, NULL, 0, &count, ERROR_INVALID_HANDLE},
2139 {INVALID_HANDLE_VALUE, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
2140 {INVALID_HANDLE_VALUE, NULL, 1, &count, ERROR_INVALID_HANDLE, ERROR_INVALID_ACCESS},
2141 {INVALID_HANDLE_VALUE, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
2142 {INVALID_HANDLE_VALUE, &event, 0, &count, ERROR_INVALID_HANDLE},
2143 {INVALID_HANDLE_VALUE, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
2144 {INVALID_HANDLE_VALUE, &event, 1, &count, ERROR_INVALID_HANDLE},
2145 {input_handle, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
2146 {input_handle, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
2147 {input_handle, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
2148 {input_handle, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
2149 {input_handle, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
2150 };
2151
2152 /* Suppress external sources of input events for the duration of the test. */
2153 ret = GetConsoleMode(input_handle, &console_mode);
2154 ok(ret == TRUE, "Expected GetConsoleMode to return TRUE, got %d\n", ret);
2155 if (!ret)
2156 {
2157 skip("GetConsoleMode failed with last error %lu\n", GetLastError());
2158 return;
2159 }
2160
2161 ret = SetConsoleMode(input_handle, console_mode & ~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT));
2162 ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret);
2163 if (!ret)
2164 {
2165 skip("SetConsoleMode failed with last error %lu\n", GetLastError());
2166 return;
2167 }
2168
2169 /* Discard any events queued before the tests. */
2170 ret = FlushConsoleInputBuffer(input_handle);
2171 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
2172
2173 event.EventType = MOUSE_EVENT;
2174 event.Event.MouseEvent = mouse_event;
2175
2176 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2177 {
2178 if (invalid_table[i].win_crash)
2179 continue;
2180
2181 SetLastError(0xdeadbeef);
2182 if (invalid_table[i].written) count = 0xdeadbeef;
2183 ret = WriteConsoleInputW(invalid_table[i].handle,
2184 invalid_table[i].buffer,
2185 invalid_table[i].count,
2186 invalid_table[i].written);
2187 ok(!ret, "[%d] Expected WriteConsoleInputW to return FALSE, got %d\n", i, ret);
2188 gle = GetLastError();
2189 ok(gle == invalid_table[i].gle || (gle != 0 && gle == invalid_table[i].gle2),
2190 "[%d] Expected last error to be %lu or %lu, got %lu\n",
2191 i, invalid_table[i].gle, invalid_table[i].gle2, gle);
2192 }
2193
2194 count = 0xdeadbeef;
2195 ret = WriteConsoleInputW(input_handle, NULL, 0, &count);
2196 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2197 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2198
2199 count = 0xdeadbeef;
2200 ret = WriteConsoleInputW(input_handle, &event, 0, &count);
2201 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2202 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2203
2204 count = 0xdeadbeef;
2205 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2206 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2207 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2208
2209 ret = FlushConsoleInputBuffer(input_handle);
2210 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
2211
2212 /* Writing a single mouse event doesn't seem to affect the count if an adjacent mouse event is already queued. */
2213 event.EventType = MOUSE_EVENT;
2214 event.Event.MouseEvent = mouse_event;
2215
2216 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2217 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2218 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2219
2220 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2221 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2222 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2223
2224 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2225 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2226 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2227
2228 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2229 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2230 todo_wine
2231 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2232
2233 ret = FlushConsoleInputBuffer(input_handle);
2234 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
2235
2236 for (i = 0; i < ARRAY_SIZE(event_list); i++)
2237 {
2238 event_list[i].EventType = MOUSE_EVENT;
2239 event_list[i].Event.MouseEvent = mouse_event;
2240 }
2241
2242 /* Writing consecutive chunks of mouse events appears to work. */
2243 ret = WriteConsoleInputW(input_handle, event_list, ARRAY_SIZE(event_list), &count);
2244 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2245 ok(count == ARRAY_SIZE(event_list),
2246 "Expected count to be event list length, got %lu\n", count);
2247
2248 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2249 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2250 ok(count == ARRAY_SIZE(event_list),
2251 "Expected count to be event list length, got %lu\n", count);
2252
2253 ret = WriteConsoleInputW(input_handle, event_list, ARRAY_SIZE(event_list), &count);
2254 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2255 ok(count == ARRAY_SIZE(event_list),
2256 "Expected count to be event list length, got %lu\n", count);
2257
2258 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2259 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2260 ok(count == 2*ARRAY_SIZE(event_list),
2261 "Expected count to be twice event list length, got %lu\n", count);
2262
2263 /* Again, writing a single mouse event with adjacent mouse events queued doesn't appear to affect the count. */
2264 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2265 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2266 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2267
2268 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2269 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2270 todo_wine
2271 ok(count == 2*ARRAY_SIZE(event_list),
2272 "Expected count to be twice event list length, got %lu\n", count);
2273
2274 ret = FlushConsoleInputBuffer(input_handle);
2275 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
2276
2277 key_event.bKeyDown = FALSE;
2278 key_event.wRepeatCount = 0;
2279 key_event.wVirtualKeyCode = VK_SPACE;
2280 key_event.wVirtualScanCode = VK_SPACE;
2281 key_event.uChar.UnicodeChar = ' ';
2282 key_event.dwControlKeyState = 0;
2283
2284 event.EventType = KEY_EVENT;
2285 event.Event.KeyEvent = key_event;
2286
2287 /* Key events don't exhibit the same behavior as mouse events. */
2288 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2289 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2290 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2291
2292 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2293 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2294 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2295
2296 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2297 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2298 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2299
2300 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2301 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2302 ok(count == 2, "Expected count to be 2, got %lu\n", count);
2303
2304 ret = FlushConsoleInputBuffer(input_handle);
2305 ok(ret == TRUE, "Expected FlushConsoleInputBuffer to return TRUE, got %d\n", ret);
2306
2307 /* Try interleaving mouse and key events. */
2308 event.EventType = MOUSE_EVENT;
2309 event.Event.MouseEvent = mouse_event;
2310
2311 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2312 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2313 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2314
2315 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2316 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2317 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2318
2319 event.EventType = KEY_EVENT;
2320 event.Event.KeyEvent = key_event;
2321
2322 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2323 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2324 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2325
2326 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2327 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2328 ok(count == 2, "Expected count to be 2, got %lu\n", count);
2329
2330 event.EventType = MOUSE_EVENT;
2331 event.Event.MouseEvent = mouse_event;
2332
2333 ret = WriteConsoleInputW(input_handle, &event, 1, &count);
2334 ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
2335 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2336
2337 ret = GetNumberOfConsoleInputEvents(input_handle, &count);
2338 ok(ret == TRUE, "Expected GetNumberOfConsoleInputEvents to return TRUE, got %d\n", ret);
2339 ok(count == 3, "Expected count to be 3, got %lu\n", count);
2340
2341 /* Restore the old console mode. */
2342 ret = SetConsoleMode(input_handle, console_mode);
2343 ok(ret == TRUE, "Expected SetConsoleMode to return TRUE, got %d\n", ret);
2344}
2345
2346static void test_FlushConsoleInputBuffer(HANDLE input, HANDLE output)
2347{
2348 INPUT_RECORD record;
2349 DWORD count;
2350 BOOL ret;
2351
2352 ret = FlushConsoleInputBuffer(input);
2353 ok(ret, "FlushConsoleInputBuffer failed: %lu\n", GetLastError());
2354
2355 ret = GetNumberOfConsoleInputEvents(input, &count);
2356 ok(ret, "GetNumberOfConsoleInputEvents failed: %lu\n", GetLastError());
2357 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2358
2359 record.EventType = KEY_EVENT;
2360 record.Event.KeyEvent.bKeyDown = 1;
2361 record.Event.KeyEvent.wRepeatCount = 1;
2362 record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
2363 record.Event.KeyEvent.wVirtualScanCode = VK_RETURN;
2364 record.Event.KeyEvent.uChar.UnicodeChar = '\r';
2365 record.Event.KeyEvent.dwControlKeyState = 0;
2366 ret = WriteConsoleInputW(input, &record, 1, &count);
2367 ok(ret, "WriteConsoleInputW failed: %lu\n", GetLastError());
2368
2369 ret = GetNumberOfConsoleInputEvents(input, &count);
2370 ok(ret, "GetNumberOfConsoleInputEvents failed: %lu\n", GetLastError());
2371 ok(count == 1, "Expected count to be 0, got %lu\n", count);
2372
2373 ret = FlushConsoleInputBuffer(input);
2374 ok(ret, "FlushConsoleInputBuffer failed: %lu\n", GetLastError());
2375
2376 ret = GetNumberOfConsoleInputEvents(input, &count);
2377 ok(ret, "GetNumberOfConsoleInputEvents failed: %lu\n", GetLastError());
2378 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2379
2380 ret = WriteConsoleInputW(input, &record, 1, &count);
2381 ok(ret, "WriteConsoleInputW failed: %lu\n", GetLastError());
2382
2383 ret = GetNumberOfConsoleInputEvents(input, &count);
2384 ok(ret, "GetNumberOfConsoleInputEvents failed: %lu\n", GetLastError());
2385 ok(count == 1, "Expected count to be 0, got %lu\n", count);
2386
2387 ret = FlushFileBuffers(input);
2388 ok(ret, "FlushFileBuffers failed: %lu\n", GetLastError());
2389
2390 ret = GetNumberOfConsoleInputEvents(input, &count);
2391 ok(ret, "GetNumberOfConsoleInputEvents failed: %lu\n", GetLastError());
2392 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2393
2394 ret = FlushConsoleInputBuffer(output);
2395 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "FlushConsoleInputBuffer returned: %x(%lu)\n",
2396 ret, GetLastError());
2397
2398 ret = FlushFileBuffers(output);
2399 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "FlushFileBuffers returned: %x(%lu)\n",
2400 ret, GetLastError());
2401}
2402
2403static void test_WriteConsoleOutputCharacterA(HANDLE output_handle)
2404{
2405 static const char output[] = {'a', 0};
2406
2407 COORD origin = {0, 0};
2408 DWORD count;
2409 BOOL ret;
2410 int i;
2411
2412 const struct
2413 {
2414 HANDLE hConsoleOutput;
2415 LPCSTR str;
2416 DWORD length;
2417 COORD coord;
2418 LPDWORD lpNumCharsWritten;
2419 DWORD expected_count;
2420 DWORD last_error;
2421 int win7_crash;
2422 } invalid_table[] =
2423 {
2424 {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2425 {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2426 {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2427 {NULL, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2428 {NULL, output, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2429 {NULL, output, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2430 {NULL, output, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2431 {NULL, output, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2432 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2433 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2434 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2435 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2436 {INVALID_HANDLE_VALUE, output, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2437 {INVALID_HANDLE_VALUE, output, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2438 {INVALID_HANDLE_VALUE, output, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2439 {INVALID_HANDLE_VALUE, output, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2440 {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2441 {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2442 {output_handle, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2443 {output_handle, output, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2444 {output_handle, output, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2445 };
2446
2447 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2448 {
2449 if (invalid_table[i].win7_crash)
2450 continue;
2451
2452 SetLastError(0xdeadbeef);
2453 if (invalid_table[i].lpNumCharsWritten) count = 0xdeadbeef;
2454 ret = WriteConsoleOutputCharacterA(invalid_table[i].hConsoleOutput,
2455 invalid_table[i].str,
2456 invalid_table[i].length,
2457 invalid_table[i].coord,
2458 invalid_table[i].lpNumCharsWritten);
2459 ok(!ret, "[%d] Expected WriteConsoleOutputCharacterA to return FALSE, got %d\n", i, ret);
2460 ok(GetLastError() == invalid_table[i].last_error,
2461 "[%d] Expected last error to be %lu, got %lu\n",
2462 i, invalid_table[i].last_error, GetLastError());
2463 }
2464
2465 count = 0xdeadbeef;
2466 ret = WriteConsoleOutputCharacterA(output_handle, NULL, 0, origin, &count);
2467 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2468 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2469
2470 count = 0xdeadbeef;
2471 ret = WriteConsoleOutputCharacterA(output_handle, output, 0, origin, &count);
2472 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2473 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2474
2475 count = 0xdeadbeef;
2476 ret = WriteConsoleOutputCharacterA(output_handle, output, 1, origin, &count);
2477 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2478 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2479
2480 count = 0xdeadbeef;
2481 origin.X = 200;
2482 ret = WriteConsoleOutputCharacterA(output_handle, output, 0, origin, &count);
2483 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2484 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2485
2486 for (i = 1; i < 32; i++)
2487 {
2488 CONSOLE_SCREEN_BUFFER_INFO csbi;
2489 char ch = (char)i;
2490 COORD c = {1, 2};
2491
2492 ret = WriteConsoleOutputCharacterA(output_handle, &ch, 1, c, &count);
2493 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2494 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2495 okCHAR(output_handle, c, (char)i, 7);
2496 ret = GetConsoleScreenBufferInfo(output_handle, &csbi);
2497 }
2498}
2499
2500static void test_WriteConsoleOutputCharacterW(HANDLE output_handle)
2501{
2502 static const WCHAR outputW[] = {'a',0};
2503
2504 COORD origin = {0, 0};
2505 DWORD count;
2506 BOOL ret;
2507 int i;
2508
2509 const struct
2510 {
2511 HANDLE hConsoleOutput;
2512 LPCWSTR str;
2513 DWORD length;
2514 COORD coord;
2515 LPDWORD lpNumCharsWritten;
2516 DWORD expected_count;
2517 DWORD last_error;
2518 int win7_crash;
2519 } invalid_table[] =
2520 {
2521 {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2522 {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2523 {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2524 {NULL, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2525 {NULL, outputW, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2526 {NULL, outputW, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2527 {NULL, outputW, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2528 {NULL, outputW, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2529 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2530 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2531 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2532 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2533 {INVALID_HANDLE_VALUE, outputW, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2534 {INVALID_HANDLE_VALUE, outputW, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2535 {INVALID_HANDLE_VALUE, outputW, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2536 {INVALID_HANDLE_VALUE, outputW, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2537 {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2538 {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2539 {output_handle, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2540 {output_handle, outputW, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2541 {output_handle, outputW, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2542 };
2543
2544 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2545 {
2546 if (invalid_table[i].win7_crash)
2547 continue;
2548
2549 SetLastError(0xdeadbeef);
2550 if (invalid_table[i].lpNumCharsWritten) count = 0xdeadbeef;
2551 ret = WriteConsoleOutputCharacterW(invalid_table[i].hConsoleOutput,
2552 invalid_table[i].str,
2553 invalid_table[i].length,
2554 invalid_table[i].coord,
2555 invalid_table[i].lpNumCharsWritten);
2556 ok(!ret, "[%d] Expected WriteConsoleOutputCharacterW to return FALSE, got %d\n", i, ret);
2557 ok(GetLastError() == invalid_table[i].last_error,
2558 "[%d] Expected last error to be %lu, got %lu\n",
2559 i, invalid_table[i].last_error, GetLastError());
2560 }
2561
2562 count = 0xdeadbeef;
2563 ret = WriteConsoleOutputCharacterW(output_handle, NULL, 0, origin, &count);
2564 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2565 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2566
2567 count = 0xdeadbeef;
2568 ret = WriteConsoleOutputCharacterW(output_handle, outputW, 0, origin, &count);
2569 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2570 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2571
2572 count = 0xdeadbeef;
2573 ret = WriteConsoleOutputCharacterW(output_handle, outputW, 1, origin, &count);
2574 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2575 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2576
2577 count = 0xdeadbeef;
2578 origin.X = 200;
2579 ret = WriteConsoleOutputCharacterW(output_handle, outputW, 0, origin, &count);
2580 ok(ret == TRUE, "Expected WriteConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2581 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2582
2583}
2584
2585static void test_WriteConsoleOutputAttribute(HANDLE output_handle)
2586{
2587 WORD attr = FOREGROUND_BLUE;
2588 COORD origin = {0, 0};
2589 DWORD count;
2590 BOOL ret;
2591 int i;
2592
2593 const struct
2594 {
2595 HANDLE hConsoleOutput;
2596 const WORD *attr;
2597 DWORD length;
2598 COORD coord;
2599 LPDWORD lpNumAttrsWritten;
2600 DWORD expected_count;
2601 DWORD last_error;
2602 int win7_crash;
2603 } invalid_table[] =
2604 {
2605 {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2606 {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2607 {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2608 {NULL, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2609 {NULL, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2610 {NULL, &attr, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2611 {NULL, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2612 {NULL, &attr, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2613 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2614 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2615 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2616 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2617 {INVALID_HANDLE_VALUE, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2618 {INVALID_HANDLE_VALUE, &attr, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2619 {INVALID_HANDLE_VALUE, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2620 {INVALID_HANDLE_VALUE, &attr, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
2621 {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2622 {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2623 {output_handle, NULL, 1, {0, 0}, &count, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2624 {output_handle, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2625 {output_handle, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
2626 };
2627
2628 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2629 {
2630 if (invalid_table[i].win7_crash)
2631 continue;
2632
2633 SetLastError(0xdeadbeef);
2634 if (invalid_table[i].lpNumAttrsWritten) count = 0xdeadbeef;
2635 ret = WriteConsoleOutputAttribute(invalid_table[i].hConsoleOutput,
2636 invalid_table[i].attr,
2637 invalid_table[i].length,
2638 invalid_table[i].coord,
2639 invalid_table[i].lpNumAttrsWritten);
2640 ok(!ret, "[%d] Expected WriteConsoleOutputAttribute to return FALSE, got %d\n", i, ret);
2641 ok(GetLastError() == invalid_table[i].last_error,
2642 "[%d] Expected last error to be %lu, got %lu\n",
2643 i, invalid_table[i].last_error, GetLastError());
2644 }
2645
2646 count = 0xdeadbeef;
2647 ret = WriteConsoleOutputAttribute(output_handle, NULL, 0, origin, &count);
2648 ok(ret == TRUE, "Expected WriteConsoleOutputAttribute to return TRUE, got %d\n", ret);
2649 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2650
2651 count = 0xdeadbeef;
2652 ret = WriteConsoleOutputAttribute(output_handle, &attr, 0, origin, &count);
2653 ok(ret == TRUE, "Expected WriteConsoleOutputAttribute to return TRUE, got %d\n", ret);
2654 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2655
2656 count = 0xdeadbeef;
2657 ret = WriteConsoleOutputAttribute(output_handle, &attr, 1, origin, &count);
2658 ok(ret == TRUE, "Expected WriteConsoleOutputAttribute to return TRUE, got %d\n", ret);
2659 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2660
2661 count = 0xdeadbeef;
2662 origin.X = 200;
2663 ret = WriteConsoleOutputAttribute(output_handle, &attr, 0, origin, &count);
2664 ok(ret == TRUE, "Expected WriteConsoleOutputAttribute to return TRUE, got %d\n", ret);
2665 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2666}
2667
2668static void set_region(SMALL_RECT *region, unsigned int left, unsigned int top, unsigned int right, unsigned int bottom)
2669{
2670 region->Left = left;
2671 region->Top = top;
2672 region->Right = right;
2673 region->Bottom = bottom;
2674}
2675
2676#define check_region(a,b,c,d,e) check_region_(__LINE__,a,b,c,d,e)
2677static void check_region_(unsigned int line, const SMALL_RECT *region, unsigned int left, unsigned int top, int right, int bottom)
2678{
2679 ok_(__FILE__,line)(region->Left == left, "Left = %u, expected %u\n", region->Left, left);
2680 ok_(__FILE__,line)(region->Top == top, "Top = %u, expected %u\n", region->Top, top);
2681 /* In multiple places returned region depends on Windows versions: some return right < left, others leave it untouched */
2682 if (right >= 0)
2683 ok_(__FILE__,line)(region->Right == right, "Right = %u, expected %u\n", region->Right, right);
2684 else
2685 ok_(__FILE__,line)(region->Right == -right || region->Right == region->Left - 1,
2686 "Right = %u, expected %d\n", region->Right, right);
2687 if (bottom > 0)
2688 ok_(__FILE__,line)(region->Bottom == bottom, "Bottom = %u, expected %u\n", region->Bottom, bottom);
2689 else if (bottom < 0)
2690 ok_(__FILE__,line)(region->Bottom == -bottom || region->Bottom == region->Top - 1,
2691 "Bottom = %u, expected %d\n", region->Bottom, bottom);
2692}
2693
2694static void test_WriteConsoleOutput(HANDLE console)
2695{
2696 CONSOLE_SCREEN_BUFFER_INFO info;
2697 CHAR_INFO char_info_buf[2048];
2698 SMALL_RECT region;
2699 COORD size, coord;
2700 unsigned int i;
2701 BOOL ret;
2702
2703 for (i = 0; i < ARRAY_SIZE(char_info_buf); i++)
2704 {
2705 char_info_buf[i].Char.UnicodeChar = '0' + i % 10;
2706 char_info_buf[i].Attributes = 0;
2707 }
2708
2709 ret = GetConsoleScreenBufferInfo(console, &info);
2710 ok(ret, "GetConsoleScreenBufferInfo failed: %lu\n", GetLastError());
2711
2712 size.X = 23;
2713 size.Y = 17;
2714 coord.X = 2;
2715 coord.Y = 3;
2716 set_region(®ion, 10, 7, 15, 11);
2717 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, ®ion);
2718 ok(ret, "WriteConsoleOutputW failed: %lu\n", GetLastError());
2719 check_region(®ion, 10, 7, 15, 11);
2720
2721 size.X = 23;
2722 size.Y = 17;
2723 coord.X = 2;
2724 coord.Y = 3;
2725 set_region(®ion, 200, 7, 15, 211);
2726 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, ®ion);
2727 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
2728 check_region(®ion, 200, 7, 15, 211);
2729
2730 size.X = 23;
2731 size.Y = 17;
2732 coord.X = 2;
2733 coord.Y = 3;
2734 set_region(®ion, 200, 7, 211, 8);
2735 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, ®ion);
2736 ok(ret, "WriteConsoleOutputW failed: %lu\n", GetLastError());
2737 check_region(®ion, 200, 7, 211, 8);
2738
2739 size.X = 23;
2740 size.Y = 17;
2741 coord.X = 2;
2742 coord.Y = 3;
2743 set_region(®ion, 10, 7, 9, 11);
2744 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, ®ion);
2745 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
2746 check_region(®ion, 10, 7, 9, 11);
2747
2748 size.X = 23;
2749 size.Y = 17;
2750 coord.X = 2;
2751 coord.Y = 3;
2752 set_region(®ion, 10, 7, 11, 6);
2753 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, ®ion);
2754 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
2755 check_region(®ion, 10, 7, 11, 6);
2756
2757 size.X = 2;
2758 size.Y = 17;
2759 coord.X = 2;
2760 coord.Y = 3;
2761 set_region(®ion, 10, 7, 15, 11);
2762 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, ®ion);
2763 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
2764 check_region(®ion, 10, 7, 15, 11);
2765
2766 size.X = 23;
2767 size.Y = 3;
2768 coord.X = 2;
2769 coord.Y = 3;
2770 set_region(®ion, 10, 7, 15, 11);
2771 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, ®ion);
2772 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
2773 check_region(®ion, 10, 7, 15, 11);
2774
2775 size.X = 6;
2776 size.Y = 17;
2777 coord.X = 2;
2778 coord.Y = 3;
2779 set_region(®ion, 10, 7, 15, 11);
2780 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, ®ion);
2781 ok(ret, "WriteConsoleOutputW failed: %lu\n", GetLastError());
2782 check_region(®ion, 10, 7, 13, 11);
2783
2784 size.X = 6;
2785 size.Y = 17;
2786 coord.X = 2;
2787 coord.Y = 3;
2788 set_region(®ion, 10, 7, 15, 11);
2789 ret = WriteConsoleOutputW((HANDLE)0xdeadbeef, char_info_buf, size, coord, ®ion);
2790 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
2791 if (!skip_nt) check_region(®ion, 10, 7, 13, 11);
2792
2793 size.X = 16;
2794 size.Y = 7;
2795 coord.X = 2;
2796 coord.Y = 3;
2797 set_region(®ion, 10, 7, 15, 11);
2798 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, ®ion);
2799 ok(ret, "WriteConsoleOutputW failed: %lu\n", GetLastError());
2800 check_region(®ion, 10, 7, 15, 10);
2801
2802 size.X = 16;
2803 size.Y = 7;
2804 coord.X = 2;
2805 coord.Y = 3;
2806 set_region(®ion, info.dwSize.X - 2, 7, info.dwSize.X + 2, 7);
2807 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, ®ion);
2808 ok(ret, "WriteConsoleOutputW failed: %lu\n", GetLastError());
2809 check_region(®ion, info.dwSize.X - 2, 7, info.dwSize.X - 1, 7);
2810}
2811
2812static void test_FillConsoleOutputCharacterA(HANDLE output_handle)
2813{
2814 COORD origin = {0, 0};
2815 DWORD count;
2816 BOOL ret;
2817 int i;
2818
2819 const struct
2820 {
2821 HANDLE hConsoleOutput;
2822 CHAR ch;
2823 DWORD length;
2824 COORD coord;
2825 LPDWORD lpNumCharsWritten;
2826 DWORD last_error;
2827 int win7_crash;
2828 } invalid_table[] =
2829 {
2830 {NULL, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2831 {NULL, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2832 {NULL, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2833 {NULL, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2834 {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2835 {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2836 {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2837 {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2838 {output_handle, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2839 {output_handle, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2840 };
2841
2842 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2843 {
2844 if (invalid_table[i].win7_crash)
2845 continue;
2846
2847 SetLastError(0xdeadbeef);
2848 if (invalid_table[i].lpNumCharsWritten) count = 0xdeadbeef;
2849 ret = FillConsoleOutputCharacterA(invalid_table[i].hConsoleOutput,
2850 invalid_table[i].ch,
2851 invalid_table[i].length,
2852 invalid_table[i].coord,
2853 invalid_table[i].lpNumCharsWritten);
2854 ok(!ret, "[%d] Expected FillConsoleOutputCharacterA to return FALSE, got %d\n", i, ret);
2855 ok(GetLastError() == invalid_table[i].last_error,
2856 "[%d] Expected last error to be %lu, got %lu\n",
2857 i, invalid_table[i].last_error, GetLastError());
2858 }
2859
2860 count = 0xdeadbeef;
2861 ret = FillConsoleOutputCharacterA(output_handle, 'a', 0, origin, &count);
2862 ok(ret == TRUE, "Expected FillConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2863 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2864
2865 count = 0xdeadbeef;
2866 ret = FillConsoleOutputCharacterA(output_handle, 'a', 1, origin, &count);
2867 ok(ret == TRUE, "Expected FillConsoleOutputCharacterA to return TRUE, got %d\n", ret);
2868 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2869}
2870
2871static void test_FillConsoleOutputCharacterW(HANDLE output_handle)
2872{
2873 COORD origin = {0, 0};
2874 DWORD count;
2875 BOOL ret;
2876 int i;
2877
2878 const struct
2879 {
2880 HANDLE hConsoleOutput;
2881 WCHAR ch;
2882 DWORD length;
2883 COORD coord;
2884 LPDWORD lpNumCharsWritten;
2885 DWORD last_error;
2886 int win7_crash;
2887 } invalid_table[] =
2888 {
2889 {NULL, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2890 {NULL, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2891 {NULL, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2892 {NULL, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2893 {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2894 {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2895 {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2896 {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2897 {output_handle, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2898 {output_handle, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2899 };
2900
2901 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2902 {
2903 if (invalid_table[i].win7_crash)
2904 continue;
2905
2906 SetLastError(0xdeadbeef);
2907 if (invalid_table[i].lpNumCharsWritten) count = 0xdeadbeef;
2908 ret = FillConsoleOutputCharacterW(invalid_table[i].hConsoleOutput,
2909 invalid_table[i].ch,
2910 invalid_table[i].length,
2911 invalid_table[i].coord,
2912 invalid_table[i].lpNumCharsWritten);
2913 ok(!ret, "[%d] Expected FillConsoleOutputCharacterW to return FALSE, got %d\n", i, ret);
2914 ok(GetLastError() == invalid_table[i].last_error,
2915 "[%d] Expected last error to be %lu, got %lu\n",
2916 i, invalid_table[i].last_error, GetLastError());
2917 }
2918
2919 count = 0xdeadbeef;
2920 ret = FillConsoleOutputCharacterW(output_handle, 'a', 0, origin, &count);
2921 ok(ret == TRUE, "Expected FillConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2922 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2923
2924 count = 0xdeadbeef;
2925 ret = FillConsoleOutputCharacterW(output_handle, 'a', 1, origin, &count);
2926 ok(ret == TRUE, "Expected FillConsoleOutputCharacterW to return TRUE, got %d\n", ret);
2927 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2928}
2929
2930static void test_FillConsoleOutputAttribute(HANDLE output_handle)
2931{
2932 COORD origin = {0, 0};
2933 DWORD count;
2934 BOOL ret;
2935 int i;
2936
2937 const struct
2938 {
2939 HANDLE hConsoleOutput;
2940 WORD attr;
2941 DWORD length;
2942 COORD coord;
2943 LPDWORD lpNumAttrsWritten;
2944 DWORD last_error;
2945 int win7_crash;
2946 } invalid_table[] =
2947 {
2948 {NULL, FOREGROUND_BLUE, 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2949 {NULL, FOREGROUND_BLUE, 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2950 {NULL, FOREGROUND_BLUE, 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2951 {NULL, FOREGROUND_BLUE, 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2952 {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2953 {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
2954 {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2955 {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
2956 {output_handle, FOREGROUND_BLUE, 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2957 {output_handle, FOREGROUND_BLUE, 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
2958 };
2959
2960 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
2961 {
2962 if (invalid_table[i].win7_crash)
2963 continue;
2964
2965 SetLastError(0xdeadbeef);
2966 if (invalid_table[i].lpNumAttrsWritten) count = 0xdeadbeef;
2967 ret = FillConsoleOutputAttribute(invalid_table[i].hConsoleOutput,
2968 invalid_table[i].attr,
2969 invalid_table[i].length,
2970 invalid_table[i].coord,
2971 invalid_table[i].lpNumAttrsWritten);
2972 ok(!ret, "[%d] Expected FillConsoleOutputAttribute to return FALSE, got %d\n", i, ret);
2973 ok(GetLastError() == invalid_table[i].last_error,
2974 "[%d] Expected last error to be %lu, got %lu\n",
2975 i, invalid_table[i].last_error, GetLastError());
2976 }
2977
2978 count = 0xdeadbeef;
2979 ret = FillConsoleOutputAttribute(output_handle, FOREGROUND_BLUE, 0, origin, &count);
2980 ok(ret == TRUE, "Expected FillConsoleOutputAttribute to return TRUE, got %d\n", ret);
2981 ok(count == 0, "Expected count to be 0, got %lu\n", count);
2982
2983 count = 0xdeadbeef;
2984 ret = FillConsoleOutputAttribute(output_handle, FOREGROUND_BLUE, 1, origin, &count);
2985 ok(ret == TRUE, "Expected FillConsoleOutputAttribute to return TRUE, got %d\n", ret);
2986 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2987
2988 count = 0xdeadbeef;
2989 ret = FillConsoleOutputAttribute(output_handle, ~0, 1, origin, &count);
2990 ok(ret == TRUE, "Expected FillConsoleOutputAttribute to return TRUE, got %d\n", ret);
2991 ok(count == 1, "Expected count to be 1, got %lu\n", count);
2992}
2993
2994static void test_ReadConsoleOutputCharacterA(HANDLE output_handle)
2995{
2996 CHAR read;
2997 COORD origin = {0, 0};
2998 DWORD count;
2999 BOOL ret;
3000 int i;
3001
3002 const struct
3003 {
3004 HANDLE hConsoleOutput;
3005 LPSTR lpstr;
3006 DWORD length;
3007 COORD coord;
3008 LPDWORD read_count;
3009 DWORD expected_count;
3010 DWORD last_error;
3011 int win7_crash;
3012 } invalid_table[] =
3013 {
3014 {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3015 {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3016 {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3017 {NULL, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
3018 {NULL, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3019 {NULL, &read, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3020 {NULL, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3021 {NULL, &read, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3022 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3023 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3024 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3025 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
3026 {INVALID_HANDLE_VALUE, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3027 {INVALID_HANDLE_VALUE, &read, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3028 {INVALID_HANDLE_VALUE, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3029 {INVALID_HANDLE_VALUE, &read, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3030 {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3031 {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3032 {output_handle, NULL, 1, {0, 0}, &count, 1, ERROR_INVALID_ACCESS, 1},
3033 {output_handle, NULL, 10, {0, 0}, &count, 10, ERROR_INVALID_ACCESS, 1},
3034 {output_handle, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3035 {output_handle, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3036 };
3037
3038 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
3039 {
3040 if (invalid_table[i].win7_crash)
3041 continue;
3042
3043 SetLastError(0xdeadbeef);
3044 if (invalid_table[i].read_count) count = 0xdeadbeef;
3045 ret = ReadConsoleOutputCharacterA(invalid_table[i].hConsoleOutput,
3046 invalid_table[i].lpstr,
3047 invalid_table[i].length,
3048 invalid_table[i].coord,
3049 invalid_table[i].read_count);
3050 ok(!ret, "[%d] Expected ReadConsoleOutputCharacterA to return FALSE, got %d\n", i, ret);
3051 ok(GetLastError() == invalid_table[i].last_error,
3052 "[%d] Expected last error to be %lu, got %lu\n",
3053 i, invalid_table[i].last_error, GetLastError());
3054 }
3055
3056 count = 0xdeadbeef;
3057 ret = ReadConsoleOutputCharacterA(output_handle, NULL, 0, origin, &count);
3058 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterA to return TRUE, got %d\n", ret);
3059 ok(count == 0, "Expected count to be 0, got %lu\n", count);
3060
3061 count = 0xdeadbeef;
3062 ret = ReadConsoleOutputCharacterA(output_handle, &read, 0, origin, &count);
3063 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterA to return TRUE, got %d\n", ret);
3064 ok(count == 0, "Expected count to be 0, got %lu\n", count);
3065
3066 count = 0xdeadbeef;
3067 ret = ReadConsoleOutputCharacterA(output_handle, &read, 1, origin, &count);
3068 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterA to return TRUE, got %d\n", ret);
3069 ok(count == 1, "Expected count to be 1, got %lu\n", count);
3070
3071 count = 0xdeadbeef;
3072 origin.X = 200;
3073 ret = ReadConsoleOutputCharacterA(output_handle, &read, 1, origin, &count);
3074 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterA to return TRUE, got %d\n", ret);
3075 ok(count == 0, "Expected count to be 0, got %lu\n", count);
3076}
3077
3078static void test_ReadConsoleOutputCharacterW(HANDLE output_handle)
3079{
3080 WCHAR read;
3081 COORD origin = {0, 0};
3082 DWORD count;
3083 BOOL ret;
3084 int i;
3085
3086 const struct
3087 {
3088 HANDLE hConsoleOutput;
3089 LPWSTR buffer;
3090 DWORD length;
3091 COORD coord;
3092 LPDWORD read_count;
3093 DWORD expected_count;
3094 DWORD last_error;
3095 int win7_crash;
3096 } invalid_table[] =
3097 {
3098 {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3099 {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3100 {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3101 {NULL, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
3102 {NULL, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3103 {NULL, &read, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3104 {NULL, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3105 {NULL, &read, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3106 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3107 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3108 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3109 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
3110 {INVALID_HANDLE_VALUE, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3111 {INVALID_HANDLE_VALUE, &read, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3112 {INVALID_HANDLE_VALUE, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3113 {INVALID_HANDLE_VALUE, &read, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3114 {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3115 {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3116 {output_handle, NULL, 1, {0, 0}, &count, 1, ERROR_INVALID_ACCESS, 1},
3117 {output_handle, NULL, 10, {0, 0}, &count, 10, ERROR_INVALID_ACCESS, 1},
3118 {output_handle, &read, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3119 {output_handle, &read, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3120 };
3121
3122 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
3123 {
3124 if (invalid_table[i].win7_crash)
3125 continue;
3126
3127 SetLastError(0xdeadbeef);
3128 if (invalid_table[i].read_count) count = 0xdeadbeef;
3129 ret = ReadConsoleOutputCharacterW(invalid_table[i].hConsoleOutput,
3130 invalid_table[i].buffer,
3131 invalid_table[i].length,
3132 invalid_table[i].coord,
3133 invalid_table[i].read_count);
3134 ok(!ret, "[%d] Expected ReadConsoleOutputCharacterW to return FALSE, got %d\n", i, ret);
3135 ok(GetLastError() == invalid_table[i].last_error,
3136 "[%d] Expected last error to be %lu, got %lu\n",
3137 i, invalid_table[i].last_error, GetLastError());
3138 }
3139
3140 count = 0xdeadbeef;
3141 ret = ReadConsoleOutputCharacterW(output_handle, NULL, 0, origin, &count);
3142 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterW to return TRUE, got %d\n", ret);
3143 ok(count == 0, "Expected count to be 0, got %lu\n", count);
3144
3145 count = 0xdeadbeef;
3146 ret = ReadConsoleOutputCharacterW(output_handle, &read, 0, origin, &count);
3147 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterW to return TRUE, got %d\n", ret);
3148 ok(count == 0, "Expected count to be 0, got %lu\n", count);
3149
3150 count = 0xdeadbeef;
3151 ret = ReadConsoleOutputCharacterW(output_handle, &read, 1, origin, &count);
3152 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterW to return TRUE, got %d\n", ret);
3153 ok(count == 1, "Expected count to be 1, got %lu\n", count);
3154
3155 count = 0xdeadbeef;
3156 origin.X = 200;
3157 ret = ReadConsoleOutputCharacterW(output_handle, &read, 1, origin, &count);
3158 ok(ret == TRUE, "Expected ReadConsoleOutputCharacterW to return TRUE, got %d\n", ret);
3159 ok(count == 0, "Expected count to be 0, got %lu\n", count);
3160}
3161
3162static void test_ReadConsoleOutputAttribute(HANDLE output_handle)
3163{
3164 WORD attr;
3165 COORD origin = {0, 0};
3166 DWORD count;
3167 BOOL ret;
3168 int i;
3169
3170 const struct
3171 {
3172 HANDLE hConsoleOutput;
3173 LPWORD lpAttribute;
3174 DWORD length;
3175 COORD coord;
3176 LPDWORD read_count;
3177 DWORD expected_count;
3178 DWORD last_error;
3179 int win7_crash;
3180 } invalid_table[] =
3181 {
3182 {NULL, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3183 {NULL, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3184 {NULL, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3185 {NULL, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
3186 {NULL, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3187 {NULL, &attr, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3188 {NULL, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3189 {NULL, &attr, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3190 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3191 {INVALID_HANDLE_VALUE, NULL, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3192 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3193 {INVALID_HANDLE_VALUE, NULL, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE, 1},
3194 {INVALID_HANDLE_VALUE, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3195 {INVALID_HANDLE_VALUE, &attr, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3196 {INVALID_HANDLE_VALUE, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3197 {INVALID_HANDLE_VALUE, &attr, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
3198 {output_handle, NULL, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3199 {output_handle, NULL, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3200 {output_handle, NULL, 1, {0, 0}, &count, 1, ERROR_INVALID_ACCESS, 1},
3201 {output_handle, &attr, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3202 {output_handle, &attr, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
3203 };
3204
3205 for (i = 0; i < ARRAY_SIZE(invalid_table); i++)
3206 {
3207 if (invalid_table[i].win7_crash)
3208 continue;
3209
3210 SetLastError(0xdeadbeef);
3211 if (invalid_table[i].read_count) count = 0xdeadbeef;
3212 ret = ReadConsoleOutputAttribute(invalid_table[i].hConsoleOutput,
3213 invalid_table[i].lpAttribute,
3214 invalid_table[i].length,
3215 invalid_table[i].coord,
3216 invalid_table[i].read_count);
3217 ok(!ret, "[%d] Expected ReadConsoleOutputAttribute to return FALSE, got %d\n", i, ret);
3218 ok(GetLastError() == invalid_table[i].last_error,
3219 "[%d] Expected last error to be %lu, got %lu\n",
3220 i, invalid_table[i].last_error, GetLastError());
3221 }
3222
3223 count = 0xdeadbeef;
3224 ret = ReadConsoleOutputAttribute(output_handle, NULL, 0, origin, &count);
3225 ok(ret == TRUE, "Expected ReadConsoleOutputAttribute to return TRUE, got %d\n", ret);
3226 ok(count == 0, "Expected count to be 0, got %lu\n", count);
3227
3228 count = 0xdeadbeef;
3229 ret = ReadConsoleOutputAttribute(output_handle, &attr, 0, origin, &count);
3230 ok(ret == TRUE, "Expected ReadConsoleOutputAttribute to return TRUE, got %d\n", ret);
3231 ok(count == 0, "Expected count to be 0, got %lu\n", count);
3232
3233 count = 0xdeadbeef;
3234 ret = ReadConsoleOutputAttribute(output_handle, &attr, 1, origin, &count);
3235 ok(ret == TRUE, "Expected ReadConsoleOutputAttribute to return TRUE, got %d\n", ret);
3236 ok(count == 1, "Expected count to be 1, got %lu\n", count);
3237
3238 count = 0xdeadbeef;
3239 origin.X = 200;
3240 ret = ReadConsoleOutputAttribute(output_handle, &attr, 1, origin, &count);
3241 ok(ret == TRUE, "Expected ReadConsoleOutputAttribute to return TRUE, got %d\n", ret);
3242 ok(count == 0, "Expected count to be 1, got %lu\n", count);
3243}
3244
3245static void test_ReadConsoleOutput(HANDLE console)
3246{
3247 CONSOLE_SCREEN_BUFFER_INFO info;
3248 CHAR_INFO char_info_buf[2048];
3249 SMALL_RECT region;
3250 COORD size, coord;
3251 DWORD count;
3252 WCHAR ch;
3253 BOOL ret;
3254
3255 if (skip_nt) return;
3256
3257 ret = GetConsoleScreenBufferInfo(console, &info);
3258 ok(ret, "GetConsoleScreenBufferInfo failed: %lu\n", GetLastError());
3259
3260 size.X = 23;
3261 size.Y = 17;
3262 coord.X = 2;
3263 coord.Y = 3;
3264 set_region(®ion, 10, 7, 15, 11);
3265 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, ®ion);
3266 ok(ret, "ReadConsoleOutputW failed: %lu\n", GetLastError());
3267 check_region(®ion, 10, 7, 15, 11);
3268
3269 size.X = 23;
3270 size.Y = 17;
3271 coord.X = 2;
3272 coord.Y = 3;
3273 set_region(®ion, 200, 7, 15, 211);
3274 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, ®ion);
3275 ok(!ret, "ReadConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
3276 check_region(®ion, 200, 7, -15, 0);
3277
3278 size.X = 23;
3279 size.Y = 17;
3280 coord.X = 2;
3281 coord.Y = 3;
3282 set_region(®ion, 200, 7, 211, 8);
3283 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, ®ion);
3284 ok((!ret && (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_INVALID_FUNCTION)) || broken(ret /* win8 */),
3285 "ReadConsoleOutputW returned: %x %lu\n", ret, GetLastError());
3286 if (!ret && GetLastError() == ERROR_INVALID_PARAMETER) check_region(®ion, 200, 7, -211, -8);
3287
3288 size.X = 23;
3289 size.Y = 17;
3290 coord.X = 2;
3291 coord.Y = 3;
3292 set_region(®ion, 10, 7, 9, 11);
3293 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, ®ion);
3294 ok((!ret && (GetLastError() == ERROR_INVALID_FUNCTION || GetLastError() == ERROR_NOT_ENOUGH_MEMORY)) || broken(ret /* win8 */),
3295 "ReadConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
3296 check_region(®ion, 10, 7, 9, -11);
3297
3298 size.X = 23;
3299 size.Y = 17;
3300 coord.X = 2;
3301 coord.Y = 3;
3302 set_region(®ion, 10, 7, 11, 6);
3303 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, ®ion);
3304 ok((!ret && (GetLastError() == ERROR_INVALID_FUNCTION || GetLastError() == ERROR_NOT_ENOUGH_MEMORY)) || broken(ret /* win8 */),
3305 "ReadConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
3306 check_region(®ion, 10, 7, -11, 6);
3307
3308 size.X = 2;
3309 size.Y = 17;
3310 coord.X = 2;
3311 coord.Y = 3;
3312 set_region(®ion, 10, 7, 15, 11);
3313 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, ®ion);
3314 ok((!ret && (GetLastError() == ERROR_INVALID_FUNCTION || GetLastError() == ERROR_NOT_ENOUGH_MEMORY)) || broken(ret /* win8 */),
3315 "ReadConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
3316 check_region(®ion, 10, 7, -15, -11);
3317
3318 size.X = 23;
3319 size.Y = 3;
3320 coord.X = 2;
3321 coord.Y = 3;
3322 set_region(®ion, 10, 7, 15, 11);
3323 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, ®ion);
3324 ok((!ret && (GetLastError() == ERROR_INVALID_FUNCTION || GetLastError() == ERROR_NOT_ENOUGH_MEMORY)) || broken(ret /* win8 */),
3325 "ReadConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
3326 check_region(®ion, 10, 7, -15, 6);
3327
3328 size.X = 6;
3329 size.Y = 17;
3330 coord.X = 2;
3331 coord.Y = 3;
3332 set_region(®ion, 10, 7, 15, 11);
3333 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, ®ion);
3334 ok(ret, "ReadConsoleOutputW failed: %lu\n", GetLastError());
3335 check_region(®ion, 10, 7, 13, 11);
3336
3337 size.X = 6;
3338 size.Y = 17;
3339 coord.X = 2;
3340 coord.Y = 3;
3341 set_region(®ion, 10, 7, 15, 11);
3342 ret = ReadConsoleOutputW((HANDLE)0xdeadbeef, char_info_buf, size, coord, ®ion);
3343 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "ReadConsoleOutputW returned: %x(%lu)\n", ret, GetLastError());
3344 if (!skip_nt) check_region(®ion, 10, 7, 13, 11);
3345
3346 size.X = 16;
3347 size.Y = 7;
3348 coord.X = 2;
3349 coord.Y = 3;
3350 set_region(®ion, 10, 7, 15, 11);
3351 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, ®ion);
3352 ok(ret, "ReadConsoleOutputW failed: %lu\n", GetLastError());
3353 check_region(®ion, 10, 7, 15, 10);
3354
3355 size.X = 16;
3356 size.Y = 7;
3357 coord.X = 2;
3358 coord.Y = 3;
3359 set_region(®ion, info.dwSize.X - 2, 7, info.dwSize.X + 2, 7);
3360 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, ®ion);
3361 ok(ret || GetLastError() == ERROR_INVALID_PARAMETER, "ReadConsoleOutputW failed: %lu\n", GetLastError());
3362 if (ret) check_region(®ion, info.dwSize.X - 2, 7, info.dwSize.X - 1, 7);
3363
3364 coord.X = 2;
3365 coord.Y = 3;
3366 ret = WriteConsoleOutputCharacterW(console, L"xyz", 3, coord, &count);
3367 ok(ret, "WriteConsoleOutputCharacterW failed: %lu\n", GetLastError());
3368 ok(count == 3, "count = %lu\n", count);
3369
3370 memset(char_info_buf, 0xc0, sizeof(char_info_buf));
3371 size.X = 16;
3372 size.Y = 7;
3373 coord.X = 5;
3374 coord.Y = 6;
3375 set_region(®ion, 2, 3, 5, 3);
3376 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, ®ion);
3377 ok(ret, "ReadConsoleOutputW failed: %lu\n", GetLastError());
3378 check_region(®ion, 2, 3, 5, 3);
3379 ch = char_info_buf[coord.Y * size.X + coord.X].Char.UnicodeChar;
3380 ok(ch == 'x', "unexpected char %c/%x\n", ch, ch);
3381 ch = char_info_buf[coord.Y * size.X + coord.X + 1].Char.UnicodeChar;
3382 ok(ch == 'y', "unexpected char %c/%x\n", ch, ch);
3383 ch = char_info_buf[coord.Y * size.X + coord.X + 2].Char.UnicodeChar;
3384 ok(ch == 'z', "unexpected char %c/%x\n", ch, ch);
3385}
3386
3387static void test_ReadConsole(HANDLE input)
3388{
3389 DWORD ret, bytes;
3390 char buf[1024];
3391 HANDLE output;
3392
3393 SetLastError(0xdeadbeef);
3394 ret = GetFileSize(input, NULL);
3395 ok(ret == INVALID_FILE_SIZE || broken(TRUE), /* only Win7 pro64 on 64bit returns a valid file size here */
3396 "expected INVALID_FILE_SIZE, got %#lx\n", ret);
3397 if (ret == INVALID_FILE_SIZE)
3398 ok(GetLastError() == ERROR_INVALID_HANDLE ||
3399 GetLastError() == ERROR_INVALID_FUNCTION, /* Win 8, 10 */
3400 "expected ERROR_INVALID_HANDLE, got %ld\n", GetLastError());
3401
3402 bytes = 0xdeadbeef;
3403 SetLastError(0xdeadbeef);
3404 ret = ReadFile(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, "expected 0, got %lu\n", bytes);
3410
3411 bytes = 0xdeadbeef;
3412 SetLastError(0xdeadbeef);
3413 ret = ReadConsoleA(input, buf, -128, &bytes, NULL);
3414 ok(!ret, "expected 0, got %lu\n", ret);
3415 ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
3416 GetLastError() == ERROR_NOACCESS, /* Win 8, 10 */
3417 "expected ERROR_NOT_ENOUGH_MEMORY, got %ld\n", GetLastError());
3418 ok(bytes == 0xdeadbeef, "expected 0xdeadbeef, got %#lx\n", bytes);
3419
3420 bytes = 0xdeadbeef;
3421 SetLastError(0xdeadbeef);
3422 ret = ReadConsoleW(input, buf, -128, &bytes, NULL);
3423 ok(!ret, "expected 0, got %lu\n", ret);
3424 ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
3425 GetLastError() == ERROR_NOACCESS, /* Win 8, 10 */
3426 "expected ERROR_NOT_ENOUGH_MEMORY, got %ld\n", GetLastError());
3427 ok(bytes == 0xdeadbeef, "expected 0xdeadbeef, got %#lx\n", bytes);
3428
3429 output = CreateFileA("CONOUT$", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
3430 ok(output != INVALID_HANDLE_VALUE, "Could not open console\n");
3431
3432 ret = ReadConsoleW(output, buf, sizeof(buf) / sizeof(WCHAR), &bytes, NULL);
3433 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
3434 "ReadConsoleW returned %lx(%lu)\n", ret, GetLastError());
3435
3436 ret = ReadConsoleA(output, buf, sizeof(buf), &bytes, NULL);
3437 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
3438 "ReadConsoleA returned %lx(%lu)\n", ret, GetLastError());
3439
3440 ret = ReadFile(output, buf, sizeof(buf), &bytes, NULL);
3441 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
3442 "ReadFile returned %lx(%lu)\n", ret, GetLastError());
3443
3444 CloseHandle(output);
3445}
3446
3447static void test_GetCurrentConsoleFont(HANDLE std_output)
3448{
3449 BOOL ret;
3450 CONSOLE_FONT_INFO cfi;
3451 CONSOLE_SCREEN_BUFFER_INFO csbi;
3452 short int width, height;
3453 HANDLE pipe1, pipe2;
3454 COORD c;
3455
3456 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3457 SetLastError(0xdeadbeef);
3458 ret = GetCurrentConsoleFont(NULL, FALSE, &cfi);
3459 ok(!ret, "got %d, expected 0\n", ret);
3460 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3461 ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
3462 ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
3463
3464 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3465 SetLastError(0xdeadbeef);
3466 ret = GetCurrentConsoleFont(NULL, TRUE, &cfi);
3467 ok(!ret, "got %d, expected 0\n", ret);
3468 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3469 ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
3470 ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
3471
3472 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3473 SetLastError(0xdeadbeef);
3474 ret = GetCurrentConsoleFont(GetStdHandle(STD_INPUT_HANDLE), FALSE, &cfi);
3475 ok(!ret, "got %d, expected 0\n", ret);
3476 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3477 ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
3478 ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
3479
3480 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3481 SetLastError(0xdeadbeef);
3482 ret = GetCurrentConsoleFont(GetStdHandle(STD_INPUT_HANDLE), TRUE, &cfi);
3483 ok(!ret, "got %d, expected 0\n", ret);
3484 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3485 ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
3486 ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
3487
3488 CreatePipe(&pipe1, &pipe2, NULL, 0);
3489 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3490 SetLastError(0xdeadbeef);
3491 ret = GetCurrentConsoleFont(pipe1, TRUE, &cfi);
3492 ok(!ret, "got %d, expected 0\n", ret);
3493 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3494 ok(!cfi.dwFontSize.X, "got %d, expected 0\n", cfi.dwFontSize.X);
3495 ok(!cfi.dwFontSize.Y, "got %d, expected 0\n", cfi.dwFontSize.Y);
3496 CloseHandle(pipe1);
3497 CloseHandle(pipe2);
3498
3499 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3500 SetLastError(0xdeadbeef);
3501 ret = GetCurrentConsoleFont(std_output, FALSE, &cfi);
3502 ok(ret, "got %d, expected non-zero\n", ret);
3503 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3504 GetConsoleScreenBufferInfo(std_output, &csbi);
3505 width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
3506 height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
3507 c = GetConsoleFontSize(std_output, cfi.nFont);
3508 ok(cfi.dwFontSize.X == width || cfi.dwFontSize.X == c.X /* Vista and higher */,
3509 "got %d, expected %d\n", cfi.dwFontSize.X, width);
3510 ok(cfi.dwFontSize.Y == height || cfi.dwFontSize.Y == c.Y /* Vista and higher */,
3511 "got %d, expected %d\n", cfi.dwFontSize.Y, height);
3512
3513 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3514 SetLastError(0xdeadbeef);
3515 ret = GetCurrentConsoleFont(std_output, TRUE, &cfi);
3516 ok(ret, "got %d, expected non-zero\n", ret);
3517 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3518 ok(cfi.dwFontSize.X == csbi.dwMaximumWindowSize.X,
3519 "got %d, expected %d\n", cfi.dwFontSize.X, csbi.dwMaximumWindowSize.X);
3520 ok(cfi.dwFontSize.Y == csbi.dwMaximumWindowSize.Y,
3521 "got %d, expected %d\n", cfi.dwFontSize.Y, csbi.dwMaximumWindowSize.Y);
3522}
3523
3524static void test_GetCurrentConsoleFontEx(HANDLE std_output)
3525{
3526#if defined(__REACTOS__) && DLL_EXPORT_VERSION < 0x600
3527 UNREFERENCED_PARAMETER(std_output);
3528 skip("Cannot build test_GetCurrentConsoleFontEx() unless DLL_EXPORT_VERSION >= 0x600.\n");
3529#else
3530 HANDLE hmod;
3531 BOOL (WINAPI *pGetCurrentConsoleFontEx)(HANDLE, BOOL, CONSOLE_FONT_INFOEX *);
3532 CONSOLE_FONT_INFO cfi;
3533 CONSOLE_FONT_INFOEX cfix;
3534 BOOL ret;
3535 HANDLE std_input = GetStdHandle(STD_INPUT_HANDLE);
3536 HANDLE pipe1, pipe2;
3537 COORD c;
3538
3539 hmod = GetModuleHandleA("kernel32.dll");
3540 pGetCurrentConsoleFontEx = (void *)GetProcAddress(hmod, "GetCurrentConsoleFontEx");
3541 if (!pGetCurrentConsoleFontEx)
3542 {
3543 win_skip("GetCurrentConsoleFontEx is not available\n");
3544 return;
3545 }
3546
3547 SetLastError(0xdeadbeef);
3548 ret = pGetCurrentConsoleFontEx(NULL, FALSE, &cfix);
3549 ok(!ret, "got %d, expected 0\n", ret);
3550 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3551
3552 SetLastError(0xdeadbeef);
3553 ret = pGetCurrentConsoleFontEx(NULL, TRUE, &cfix);
3554 ok(!ret, "got %d, expected 0\n", ret);
3555 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3556
3557 SetLastError(0xdeadbeef);
3558 ret = pGetCurrentConsoleFontEx(std_input, FALSE, &cfix);
3559 ok(!ret, "got %d, expected 0\n", ret);
3560 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3561
3562 SetLastError(0xdeadbeef);
3563 ret = pGetCurrentConsoleFontEx(std_input, TRUE, &cfix);
3564 ok(!ret, "got %d, expected 0\n", ret);
3565 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3566
3567 SetLastError(0xdeadbeef);
3568 ret = pGetCurrentConsoleFontEx(std_output, FALSE, &cfix);
3569 ok(!ret, "got %d, expected 0\n", ret);
3570 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3571
3572 SetLastError(0xdeadbeef);
3573 ret = pGetCurrentConsoleFontEx(std_output, TRUE, &cfix);
3574 ok(!ret, "got %d, expected 0\n", ret);
3575 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3576
3577 cfix.cbSize = sizeof(CONSOLE_FONT_INFOEX);
3578
3579 SetLastError(0xdeadbeef);
3580 ret = pGetCurrentConsoleFontEx(NULL, FALSE, &cfix);
3581 ok(!ret, "got %d, expected 0\n", ret);
3582 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3583
3584 SetLastError(0xdeadbeef);
3585 ret = pGetCurrentConsoleFontEx(NULL, TRUE, &cfix);
3586 ok(!ret, "got %d, expected 0\n", ret);
3587 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3588
3589 SetLastError(0xdeadbeef);
3590 ret = pGetCurrentConsoleFontEx(std_input, FALSE, &cfix);
3591 ok(!ret, "got %d, expected 0\n", ret);
3592 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3593
3594 SetLastError(0xdeadbeef);
3595 ret = pGetCurrentConsoleFontEx(std_input, TRUE, &cfix);
3596 ok(!ret, "got %d, expected 0\n", ret);
3597 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3598
3599 CreatePipe(&pipe1, &pipe2, NULL, 0);
3600 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3601 SetLastError(0xdeadbeef);
3602 ret = pGetCurrentConsoleFontEx(pipe1, TRUE, &cfix);
3603 ok(!ret, "got %d, expected 0\n", ret);
3604 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3605 CloseHandle(pipe1);
3606 CloseHandle(pipe2);
3607
3608 SetLastError(0xdeadbeef);
3609 ret = pGetCurrentConsoleFontEx(std_output, FALSE, &cfix);
3610 ok(ret, "got %d, expected non-zero\n", ret);
3611 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3612
3613 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3614 SetLastError(0xdeadbeef);
3615 ret = GetCurrentConsoleFont(std_output, FALSE, &cfi);
3616 ok(ret, "got %d, expected non-zero\n", ret);
3617 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3618
3619 ok(cfix.dwFontSize.X == cfi.dwFontSize.X, "expected values to match\n");
3620 ok(cfix.dwFontSize.Y == cfi.dwFontSize.Y, "expected values to match\n");
3621
3622 SetLastError(0xdeadbeef);
3623 c = GetConsoleFontSize(std_output, cfix.nFont);
3624 ok(c.X && c.Y, "GetConsoleFontSize failed; err = %lu\n", GetLastError());
3625 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3626
3627 ok(cfix.dwFontSize.X == c.X, "Font width doesn't match; got %u, expected %u\n",
3628 cfix.dwFontSize.X, c.X);
3629 ok(cfix.dwFontSize.Y == c.Y, "Font height doesn't match; got %u, expected %u\n",
3630 cfix.dwFontSize.Y, c.Y);
3631
3632 ok(cfi.dwFontSize.X == c.X, "Font width doesn't match; got %u, expected %u\n",
3633 cfi.dwFontSize.X, c.X);
3634 ok(cfi.dwFontSize.Y == c.Y, "Font height doesn't match; got %u, expected %u\n",
3635 cfi.dwFontSize.Y, c.Y);
3636
3637 SetLastError(0xdeadbeef);
3638 ret = pGetCurrentConsoleFontEx(std_output, TRUE, &cfix);
3639 ok(ret, "got %d, expected non-zero\n", ret);
3640 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3641
3642 memset(&cfi, 0, sizeof(CONSOLE_FONT_INFO));
3643 SetLastError(0xdeadbeef);
3644 ret = GetCurrentConsoleFont(std_output, TRUE, &cfi);
3645 ok(ret, "got %d, expected non-zero\n", ret);
3646 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3647
3648 ok(cfix.dwFontSize.X == cfi.dwFontSize.X, "expected values to match\n");
3649 ok(cfix.dwFontSize.Y == cfi.dwFontSize.Y, "expected values to match\n");
3650#endif
3651}
3652
3653static void test_SetCurrentConsoleFontEx(HANDLE std_output)
3654{
3655#ifdef __REACTOS__
3656 UNREFERENCED_PARAMETER(std_output);
3657 skip("Cannot build test_SetCurrentConsoleFontEx() until kernelbase is synced.\n");
3658#else
3659 CONSOLE_FONT_INFOEX orig_cfix, cfix;
3660 BOOL ret;
3661 HANDLE pipe1, pipe2;
3662 HANDLE std_input = GetStdHandle(STD_INPUT_HANDLE);
3663
3664 orig_cfix.cbSize = sizeof(CONSOLE_FONT_INFOEX);
3665
3666 ret = GetCurrentConsoleFontEx(std_output, FALSE, &orig_cfix);
3667 ok(ret, "got %d, expected non-zero\n", ret);
3668
3669 cfix = orig_cfix;
3670 cfix.cbSize = 0;
3671
3672 SetLastError(0xdeadbeef);
3673 ret = SetCurrentConsoleFontEx(NULL, FALSE, &cfix);
3674 ok(!ret, "got %d, expected 0\n", ret);
3675 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3676
3677 SetLastError(0xdeadbeef);
3678 ret = SetCurrentConsoleFontEx(NULL, TRUE, &cfix);
3679 ok(!ret, "got %d, expected 0\n", ret);
3680 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3681
3682 CreatePipe(&pipe1, &pipe2, NULL, 0);
3683 SetLastError(0xdeadbeef);
3684 ret = SetCurrentConsoleFontEx(pipe1, FALSE, &cfix);
3685 ok(!ret, "got %d, expected 0\n", ret);
3686 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3687 CloseHandle(pipe1);
3688 CloseHandle(pipe2);
3689
3690 CreatePipe(&pipe1, &pipe2, NULL, 0);
3691 SetLastError(0xdeadbeef);
3692 ret = SetCurrentConsoleFontEx(pipe1, TRUE, &cfix);
3693 ok(!ret, "got %d, expected 0\n", ret);
3694 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3695 CloseHandle(pipe1);
3696 CloseHandle(pipe2);
3697
3698 SetLastError(0xdeadbeef);
3699 ret = SetCurrentConsoleFontEx(std_input, FALSE, &cfix);
3700 ok(!ret, "got %d, expected 0\n", ret);
3701 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3702
3703 SetLastError(0xdeadbeef);
3704 ret = SetCurrentConsoleFontEx(std_input, TRUE, &cfix);
3705 ok(!ret, "got %d, expected 0\n", ret);
3706 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3707
3708 SetLastError(0xdeadbeef);
3709 ret = SetCurrentConsoleFontEx(std_output, FALSE, &cfix);
3710 ok(!ret, "got %d, expected 0\n", ret);
3711 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3712
3713 SetLastError(0xdeadbeef);
3714 ret = SetCurrentConsoleFontEx(std_output, TRUE, &cfix);
3715 ok(!ret, "got %d, expected 0\n", ret);
3716 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
3717
3718 cfix = orig_cfix;
3719
3720 SetLastError(0xdeadbeef);
3721 ret = SetCurrentConsoleFontEx(NULL, FALSE, &cfix);
3722 ok(!ret, "got %d, expected 0\n", ret);
3723 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3724
3725 SetLastError(0xdeadbeef);
3726 ret = SetCurrentConsoleFontEx(NULL, TRUE, &cfix);
3727 ok(!ret, "got %d, expected 0\n", ret);
3728 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3729
3730 CreatePipe(&pipe1, &pipe2, NULL, 0);
3731 SetLastError(0xdeadbeef);
3732 ret = SetCurrentConsoleFontEx(pipe1, FALSE, &cfix);
3733 ok(!ret, "got %d, expected 0\n", ret);
3734 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3735 CloseHandle(pipe1);
3736 CloseHandle(pipe2);
3737
3738 CreatePipe(&pipe1, &pipe2, NULL, 0);
3739 SetLastError(0xdeadbeef);
3740 ret = SetCurrentConsoleFontEx(pipe1, TRUE, &cfix);
3741 ok(!ret, "got %d, expected 0\n", ret);
3742 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3743 CloseHandle(pipe1);
3744 CloseHandle(pipe2);
3745
3746 SetLastError(0xdeadbeef);
3747 ret = SetCurrentConsoleFontEx(std_input, FALSE, &cfix);
3748 ok(!ret, "got %d, expected 0\n", ret);
3749 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3750
3751 SetLastError(0xdeadbeef);
3752 ret = SetCurrentConsoleFontEx(std_input, TRUE, &cfix);
3753 ok(!ret, "got %d, expected 0\n", ret);
3754 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3755
3756 SetLastError(0xdeadbeef);
3757 ret = SetCurrentConsoleFontEx(std_output, FALSE, &cfix);
3758 ok(ret, "got %d, expected non-zero\n", ret);
3759 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3760
3761 SetLastError(0xdeadbeef);
3762 ret = SetCurrentConsoleFontEx(std_output, TRUE, &cfix);
3763 ok(ret, "got %d, expected non-zero\n", ret);
3764 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3765
3766 /* Restore original console font parameters */
3767 SetLastError(0xdeadbeef);
3768 ret = SetCurrentConsoleFontEx(std_output, FALSE, &orig_cfix);
3769 ok(ret, "got %d, expected non-zero\n", ret);
3770 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3771#endif
3772}
3773
3774static void test_GetConsoleFontSize(HANDLE std_output)
3775{
3776 COORD c;
3777 DWORD index = 0;
3778 CONSOLE_FONT_INFO cfi;
3779 RECT r;
3780 CONSOLE_SCREEN_BUFFER_INFO csbi;
3781 LONG font_width, font_height;
3782 HMODULE hmod;
3783 DWORD (WINAPI *pGetNumberOfConsoleFonts)(void);
3784 HANDLE pipe1, pipe2;
3785
3786 memset(&c, 10, sizeof(COORD));
3787 SetLastError(0xdeadbeef);
3788 c = GetConsoleFontSize(NULL, index);
3789 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3790 ok(!c.X, "got %d, expected 0\n", c.X);
3791 ok(!c.Y, "got %d, expected 0\n", c.Y);
3792
3793 memset(&c, 10, sizeof(COORD));
3794 SetLastError(0xdeadbeef);
3795 c = GetConsoleFontSize(GetStdHandle(STD_INPUT_HANDLE), index);
3796 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3797 ok(!c.X, "got %d, expected 0\n", c.X);
3798 ok(!c.Y, "got %d, expected 0\n", c.Y);
3799
3800 CreatePipe(&pipe1, &pipe2, NULL, 0);
3801 memset(&c, 10, sizeof(COORD));
3802 SetLastError(0xdeadbeef);
3803 c = GetConsoleFontSize(pipe1, index);
3804 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3805 ok(!c.X, "got %d, expected 0\n", c.X);
3806 ok(!c.Y, "got %d, expected 0\n", c.Y);
3807 CloseHandle(pipe1);
3808 CloseHandle(pipe2);
3809
3810 GetCurrentConsoleFont(std_output, FALSE, &cfi);
3811 memset(&c, 10, sizeof(COORD));
3812 SetLastError(0xdeadbeef);
3813 c = GetConsoleFontSize(std_output, cfi.nFont);
3814 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3815 GetClientRect(GetConsoleWindow(), &r);
3816 GetConsoleScreenBufferInfo(std_output, &csbi);
3817 font_width = (r.right - r.left) / (csbi.srWindow.Right - csbi.srWindow.Left + 1);
3818 font_height = (r.bottom - r.top) / (csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
3819 ok(c.X == font_width, "got %d, expected %ld\n", c.X, font_width);
3820 ok(c.Y == font_height, "got %d, expected %ld\n", c.Y, font_height);
3821
3822 hmod = GetModuleHandleA("kernel32.dll");
3823 pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts");
3824 if (!pGetNumberOfConsoleFonts)
3825 {
3826 win_skip("GetNumberOfConsoleFonts is not available\n");
3827 return;
3828 }
3829 index = pGetNumberOfConsoleFonts();
3830
3831 memset(&c, 10, sizeof(COORD));
3832 SetLastError(0xdeadbeef);
3833 c = GetConsoleFontSize(std_output, index);
3834 ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef) /* win10 1809 */,
3835 "unexpected last error %lu\n", GetLastError());
3836 if (GetLastError() == ERROR_INVALID_PARAMETER)
3837 {
3838 ok(!c.X, "got %d, expected 0\n", c.X);
3839 ok(!c.Y, "got %d, expected 0\n", c.Y);
3840 }
3841}
3842
3843static void test_GetLargestConsoleWindowSize(HANDLE std_output)
3844{
3845 COORD c, font;
3846 RECT r;
3847 LONG workarea_w, workarea_h, maxcon_w, maxcon_h;
3848 CONSOLE_SCREEN_BUFFER_INFO sbi;
3849 CONSOLE_FONT_INFO cfi;
3850 HANDLE pipe1, pipe2;
3851 DWORD index, i;
3852 HMODULE hmod;
3853 BOOL ret;
3854 DWORD (WINAPI *pGetNumberOfConsoleFonts)(void);
3855 BOOL (WINAPI *pSetConsoleFont)(HANDLE, DWORD);
3856
3857 memset(&c, 10, sizeof(COORD));
3858 SetLastError(0xdeadbeef);
3859 c = GetLargestConsoleWindowSize(NULL);
3860 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3861 ok(!c.X, "got %d, expected 0\n", c.X);
3862 ok(!c.Y, "got %d, expected 0\n", c.Y);
3863
3864 memset(&c, 10, sizeof(COORD));
3865 SetLastError(0xdeadbeef);
3866 c = GetLargestConsoleWindowSize(GetStdHandle(STD_INPUT_HANDLE));
3867 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3868 ok(!c.X, "got %d, expected 0\n", c.X);
3869 ok(!c.Y, "got %d, expected 0\n", c.Y);
3870
3871 CreatePipe(&pipe1, &pipe2, NULL, 0);
3872 memset(&c, 10, sizeof(COORD));
3873 SetLastError(0xdeadbeef);
3874 c = GetLargestConsoleWindowSize(pipe1);
3875 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3876 ok(!c.X, "got %d, expected 0\n", c.X);
3877 ok(!c.Y, "got %d, expected 0\n", c.Y);
3878 CloseHandle(pipe1);
3879 CloseHandle(pipe2);
3880
3881 SystemParametersInfoW(SPI_GETWORKAREA, 0, &r, 0);
3882 workarea_w = r.right - r.left;
3883 workarea_h = r.bottom - r.top - GetSystemMetrics(SM_CYCAPTION);
3884
3885 GetCurrentConsoleFont(std_output, FALSE, &cfi);
3886 index = cfi.nFont; /* save current font index */
3887
3888 hmod = GetModuleHandleA("kernel32.dll");
3889 pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts");
3890 if (!pGetNumberOfConsoleFonts)
3891 {
3892 win_skip("GetNumberOfConsoleFonts is not available\n");
3893 return;
3894 }
3895 pSetConsoleFont = (void *)GetProcAddress(hmod, "SetConsoleFont");
3896 if (!pSetConsoleFont)
3897 {
3898 win_skip("SetConsoleFont is not available\n");
3899 return;
3900 }
3901
3902 for (i = 0; i < pGetNumberOfConsoleFonts(); i++)
3903 {
3904 pSetConsoleFont(std_output, i);
3905 memset(&c, 10, sizeof(COORD));
3906 SetLastError(0xdeadbeef);
3907 c = GetLargestConsoleWindowSize(std_output);
3908 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3909 GetCurrentConsoleFont(std_output, FALSE, &cfi);
3910 font = GetConsoleFontSize(std_output, cfi.nFont);
3911 maxcon_w = workarea_w / font.X;
3912 maxcon_h = workarea_h / font.Y;
3913 ok(c.X == maxcon_w || c.X == maxcon_w - 1 /* Win10 */, "got %d, expected %ld\n", c.X, maxcon_w);
3914 ok(c.Y == maxcon_h || c.Y == maxcon_h - 1 /* Win10 */, "got %d, expected %ld\n", c.Y, maxcon_h);
3915
3916 ret = GetConsoleScreenBufferInfo(std_output, &sbi);
3917 ok(ret, "GetConsoleScreenBufferInfo failed %lu\n", GetLastError());
3918 ok(sbi.dwMaximumWindowSize.X == min(c.X, sbi.dwSize.X), "got %d, expected %d\n",
3919 sbi.dwMaximumWindowSize.X, min(c.X, sbi.dwSize.X));
3920 ok(sbi.dwMaximumWindowSize.Y == min(c.Y, sbi.dwSize.Y), "got %d, expected %d\n",
3921 sbi.dwMaximumWindowSize.Y, min(c.Y, sbi.dwSize.Y));
3922 }
3923 pSetConsoleFont(std_output, index); /* restore original font size */
3924}
3925
3926static void test_GetConsoleFontInfo(HANDLE std_output)
3927{
3928 HANDLE hmod;
3929 BOOL (WINAPI *pGetConsoleFontInfo)(HANDLE, BOOL, DWORD, CONSOLE_FONT_INFO *);
3930 DWORD (WINAPI *pGetNumberOfConsoleFonts)(void);
3931 DWORD num_fonts, index, i;
3932 int memsize, win_width, win_height, tmp_w, tmp_h;
3933 CONSOLE_FONT_INFO *cfi;
3934 BOOL ret;
3935 CONSOLE_SCREEN_BUFFER_INFO csbi;
3936 COORD orig_sb_size, tmp_sb_size, orig_font, tmp_font;
3937
3938 hmod = GetModuleHandleA("kernel32.dll");
3939 pGetConsoleFontInfo = (void *)GetProcAddress(hmod, "GetConsoleFontInfo");
3940 if (!pGetConsoleFontInfo)
3941 {
3942 win_skip("GetConsoleFontInfo is not available\n");
3943 return;
3944 }
3945
3946 pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts");
3947 if (!pGetNumberOfConsoleFonts)
3948 {
3949 win_skip("GetNumberOfConsoleFonts is not available\n");
3950 return;
3951 }
3952
3953 num_fonts = pGetNumberOfConsoleFonts();
3954 memsize = num_fonts * sizeof(CONSOLE_FONT_INFO);
3955 cfi = HeapAlloc(GetProcessHeap(), 0, memsize);
3956 memset(cfi, 0, memsize);
3957
3958 GetConsoleScreenBufferInfo(std_output, &csbi);
3959 orig_sb_size = csbi.dwSize;
3960 tmp_sb_size.X = csbi.dwSize.X + 3;
3961 tmp_sb_size.Y = csbi.dwSize.Y + 5;
3962 SetConsoleScreenBufferSize(std_output, tmp_sb_size);
3963
3964 SetLastError(0xdeadbeef);
3965 ret = pGetConsoleFontInfo(NULL, FALSE, 0, cfi);
3966 ok(!ret, "got %d, expected zero\n", ret);
3967 if (GetLastError() == LOWORD(E_NOTIMPL) /* win10 1709+ */ ||
3968 broken(GetLastError() == ERROR_GEN_FAILURE) /* win10 1607 */)
3969 {
3970 skip("GetConsoleFontInfo is not implemented\n");
3971 SetConsoleScreenBufferSize(std_output, orig_sb_size);
3972 HeapFree(GetProcessHeap(), 0, cfi);
3973 return;
3974 }
3975 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3976
3977 SetLastError(0xdeadbeef);
3978 ret = pGetConsoleFontInfo(GetStdHandle(STD_INPUT_HANDLE), FALSE, 0, cfi);
3979 ok(!ret, "got %d, expected zero\n", ret);
3980 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
3981
3982 SetLastError(0xdeadbeef);
3983 ret = pGetConsoleFontInfo(std_output, FALSE, 0, cfi);
3984 ok(!ret, "got %d, expected zero\n", ret);
3985 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
3986
3987 GetConsoleScreenBufferInfo(std_output, &csbi);
3988 win_width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
3989 win_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
3990
3991 GetCurrentConsoleFont(std_output, FALSE, &cfi[0]);
3992 index = cfi[0].nFont;
3993 orig_font = GetConsoleFontSize(std_output, index);
3994
3995 memset(cfi, 0, memsize);
3996 ret = pGetConsoleFontInfo(std_output, FALSE, num_fonts, cfi);
3997 ok(ret, "got %d, expected non-zero\n", ret);
3998 ok(cfi[index].dwFontSize.X == win_width, "got %d, expected %d\n",
3999 cfi[index].dwFontSize.X, win_width);
4000 ok(cfi[index].dwFontSize.Y == win_height, "got %d, expected %d\n",
4001 cfi[index].dwFontSize.Y, win_height);
4002
4003 for (i = 0; i < num_fonts; i++)
4004 {
4005 ok(cfi[i].nFont == i, "element out of order, got nFont %ld, expected %ld\n", cfi[i].nFont, i);
4006 tmp_font = GetConsoleFontSize(std_output, cfi[i].nFont);
4007 tmp_w = (double)orig_font.X / tmp_font.X * win_width;
4008 tmp_h = (double)orig_font.Y / tmp_font.Y * win_height;
4009 ok(cfi[i].dwFontSize.X == tmp_w, "got %d, expected %d\n", cfi[i].dwFontSize.X, tmp_w);
4010 ok(cfi[i].dwFontSize.Y == tmp_h, "got %d, expected %d\n", cfi[i].dwFontSize.Y, tmp_h);
4011 }
4012
4013 SetLastError(0xdeadbeef);
4014 ret = pGetConsoleFontInfo(NULL, TRUE, 0, cfi);
4015 ok(!ret, "got %d, expected zero\n", ret);
4016 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
4017
4018 SetLastError(0xdeadbeef);
4019 ret = pGetConsoleFontInfo(GetStdHandle(STD_INPUT_HANDLE), TRUE, 0, cfi);
4020 ok(!ret, "got %d, expected zero\n", ret);
4021 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
4022
4023 SetLastError(0xdeadbeef);
4024 ret = pGetConsoleFontInfo(std_output, TRUE, 0, cfi);
4025 ok(!ret, "got %d, expected zero\n", ret);
4026 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
4027
4028 memset(cfi, 0, memsize);
4029 ret = pGetConsoleFontInfo(std_output, TRUE, num_fonts, cfi);
4030 ok(ret, "got %d, expected non-zero\n", ret);
4031 ok(cfi[index].dwFontSize.X == csbi.dwMaximumWindowSize.X, "got %d, expected %d\n",
4032 cfi[index].dwFontSize.X, csbi.dwMaximumWindowSize.X);
4033 ok(cfi[index].dwFontSize.Y == csbi.dwMaximumWindowSize.Y, "got %d, expected %d\n",
4034 cfi[index].dwFontSize.Y, csbi.dwMaximumWindowSize.Y);
4035
4036 for (i = 0; i < num_fonts; i++)
4037 {
4038 ok(cfi[i].nFont == i, "element out of order, got nFont %ld, expected %ld\n", cfi[i].nFont, i);
4039 tmp_font = GetConsoleFontSize(std_output, cfi[i].nFont);
4040 tmp_w = (double)orig_font.X / tmp_font.X * csbi.dwMaximumWindowSize.X;
4041 tmp_h = (double)orig_font.Y / tmp_font.Y * csbi.dwMaximumWindowSize.Y;
4042 ok(cfi[i].dwFontSize.X == tmp_w, "got %d, expected %d\n", cfi[i].dwFontSize.X, tmp_w);
4043 ok(cfi[i].dwFontSize.Y == tmp_h, "got %d, expected %d\n", cfi[i].dwFontSize.Y, tmp_h);
4044 }
4045
4046 HeapFree(GetProcessHeap(), 0, cfi);
4047 SetConsoleScreenBufferSize(std_output, orig_sb_size);
4048}
4049
4050static void test_SetConsoleFont(HANDLE std_output)
4051{
4052 HANDLE hmod;
4053 BOOL (WINAPI *pSetConsoleFont)(HANDLE, DWORD);
4054 BOOL ret;
4055 DWORD (WINAPI *pGetNumberOfConsoleFonts)(void);
4056 DWORD num_fonts;
4057
4058 hmod = GetModuleHandleA("kernel32.dll");
4059 pSetConsoleFont = (void *)GetProcAddress(hmod, "SetConsoleFont");
4060 if (!pSetConsoleFont)
4061 {
4062 win_skip("SetConsoleFont is not available\n");
4063 return;
4064 }
4065
4066 SetLastError(0xdeadbeef);
4067 ret = pSetConsoleFont(NULL, 0);
4068 ok(!ret, "got %d, expected zero\n", ret);
4069 if (GetLastError() == LOWORD(E_NOTIMPL) /* win10 1709+ */ ||
4070 broken(GetLastError() == ERROR_GEN_FAILURE) /* win10 1607 */)
4071 {
4072 skip("SetConsoleFont is not implemented\n");
4073 return;
4074 }
4075 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
4076
4077 SetLastError(0xdeadbeef);
4078 ret = pSetConsoleFont(GetStdHandle(STD_INPUT_HANDLE), 0);
4079 ok(!ret, "got %d, expected zero\n", ret);
4080 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
4081
4082 pGetNumberOfConsoleFonts = (void *)GetProcAddress(hmod, "GetNumberOfConsoleFonts");
4083 if (!pGetNumberOfConsoleFonts)
4084 {
4085 win_skip("GetNumberOfConsoleFonts is not available\n");
4086 return;
4087 }
4088
4089 num_fonts = pGetNumberOfConsoleFonts();
4090
4091 SetLastError(0xdeadbeef);
4092 ret = pSetConsoleFont(std_output, num_fonts);
4093 ok(!ret, "got %d, expected zero\n", ret);
4094 todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
4095}
4096
4097static void test_GetConsoleScreenBufferInfoEx(HANDLE std_output)
4098{
4099 HANDLE hmod;
4100 BOOL (WINAPI *pGetConsoleScreenBufferInfoEx)(HANDLE, CONSOLE_SCREEN_BUFFER_INFOEX *);
4101 CONSOLE_SCREEN_BUFFER_INFOEX csbix;
4102 HANDLE pipe1, pipe2;
4103 BOOL ret;
4104 HANDLE std_input = GetStdHandle(STD_INPUT_HANDLE);
4105
4106 hmod = GetModuleHandleA("kernel32.dll");
4107 pGetConsoleScreenBufferInfoEx = (void *)GetProcAddress(hmod, "GetConsoleScreenBufferInfoEx");
4108 if (!pGetConsoleScreenBufferInfoEx)
4109 {
4110 win_skip("GetConsoleScreenBufferInfoEx is not available\n");
4111 return;
4112 }
4113
4114 SetLastError(0xdeadbeef);
4115 ret = pGetConsoleScreenBufferInfoEx(NULL, &csbix);
4116 ok(!ret, "got %d, expected zero\n", ret);
4117 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
4118
4119 SetLastError(0xdeadbeef);
4120 ret = pGetConsoleScreenBufferInfoEx(std_input, &csbix);
4121 ok(!ret, "got %d, expected zero\n", ret);
4122 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
4123
4124 SetLastError(0xdeadbeef);
4125 ret = pGetConsoleScreenBufferInfoEx(std_output, &csbix);
4126 ok(!ret, "got %d, expected zero\n", ret);
4127 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
4128
4129 csbix.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
4130
4131 SetLastError(0xdeadbeef);
4132 ret = pGetConsoleScreenBufferInfoEx(NULL, &csbix);
4133 ok(!ret, "got %d, expected zero\n", ret);
4134 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
4135
4136 SetLastError(0xdeadbeef);
4137 ret = pGetConsoleScreenBufferInfoEx(std_input, &csbix);
4138 ok(!ret, "got %d, expected zero\n", ret);
4139 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
4140
4141 CreatePipe(&pipe1, &pipe2, NULL, 0);
4142 SetLastError(0xdeadbeef);
4143 ret = pGetConsoleScreenBufferInfoEx(std_input, &csbix);
4144 ok(!ret, "got %d, expected zero\n", ret);
4145 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
4146 CloseHandle(pipe1);
4147 CloseHandle(pipe2);
4148
4149 SetLastError(0xdeadbeef);
4150 ret = pGetConsoleScreenBufferInfoEx(std_output, &csbix);
4151 ok(ret, "got %d, expected non-zero\n", ret);
4152 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
4153}
4154
4155static void test_FreeConsole(void)
4156{
4157 HANDLE handle, unbound_output = NULL, unbound_input = NULL;
4158 DWORD size, mode, type;
4159 WCHAR title[16];
4160 char buf[32];
4161 HWND hwnd;
4162 UINT cp;
4163 BOOL ret;
4164
4165 ok(RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle != NULL, "ConsoleHandle is NULL\n");
4166 ok(!SetConsoleCtrlHandler(mydummych, FALSE), "dummy ctrl handler shouldn't be set\n");
4167 ret = SetConsoleCtrlHandler(mydummych, TRUE);
4168 ok(ret, "SetConsoleCtrlHandler failed: %lu\n", GetLastError());
4169 if (!skip_nt)
4170 {
4171 unbound_input = create_unbound_handle(FALSE, TRUE);
4172 unbound_output = create_unbound_handle(TRUE, TRUE);
4173 }
4174
4175 ret = FreeConsole();
4176 ok(ret, "FreeConsole failed: %lu\n", GetLastError());
4177
4178 ok(RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle == NULL, "ConsoleHandle = %p\n",
4179 RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle);
4180
4181 handle = CreateFileA("CONOUT$", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
4182 ok(handle == INVALID_HANDLE_VALUE &&
4183 (GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == ERROR_ACCESS_DENIED /* winxp */)),
4184 "CreateFileA failed: %lu\n", GetLastError());
4185
4186 handle = CreateFileA("CONIN$", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
4187 ok(handle == INVALID_HANDLE_VALUE &&
4188 (GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == ERROR_ACCESS_DENIED /* winxp */)),
4189 "CreateFileA failed: %lu\n", GetLastError());
4190
4191 handle = CreateFileA("CON", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
4192 ok(handle == INVALID_HANDLE_VALUE &&
4193 (GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == ERROR_ACCESS_DENIED /* winxp */)),
4194 "CreateFileA failed: %lu\n", GetLastError());
4195
4196 handle = CreateFileA("CON", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
4197 ok(handle == INVALID_HANDLE_VALUE &&
4198 (GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == ERROR_FILE_NOT_FOUND /* winxp */)),
4199 "CreateFileA failed: %lu\n", GetLastError());
4200
4201 handle = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
4202 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
4203 CONSOLE_TEXTMODE_BUFFER, NULL);
4204 ok(handle == INVALID_HANDLE_VALUE && GetLastError() == ERROR_INVALID_HANDLE,
4205 "CreateConsoleScreenBuffer returned: %p (%lu)\n", handle, GetLastError());
4206
4207 SetLastError(0xdeadbeef);
4208 cp = GetConsoleCP();
4209 ok(!cp, "cp = %x\n", cp);
4210 ok(GetLastError() == ERROR_INVALID_HANDLE, "last error %lu\n", GetLastError());
4211
4212 SetLastError(0xdeadbeef);
4213 cp = GetConsoleOutputCP();
4214 ok(!cp, "cp = %x\n", cp);
4215 ok(GetLastError() == ERROR_INVALID_HANDLE, "last error %lu\n", GetLastError());
4216
4217 SetLastError(0xdeadbeef);
4218 ret = SetConsoleCP(GetOEMCP());
4219 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "SetConsoleCP returned %x(%lu)\n", ret, GetLastError());
4220
4221 SetLastError(0xdeadbeef);
4222 ret = SetConsoleOutputCP(GetOEMCP());
4223 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "SetConsoleCP returned %x(%lu)\n", ret, GetLastError());
4224
4225 if (skip_nt) return;
4226
4227 SetLastError(0xdeadbeef);
4228 memset( title, 0xc0, sizeof(title) );
4229 size = GetConsoleTitleW( title, ARRAY_SIZE(title) );
4230 ok(!size, "GetConsoleTitleW returned %lu\n", size);
4231 ok(title[0] == 0xc0c0, "title byffer changed\n");
4232 ok(GetLastError() == ERROR_INVALID_HANDLE, "last error %lu\n", GetLastError());
4233
4234 SetLastError(0xdeadbeef);
4235 ret = SetConsoleTitleW( L"test" );
4236 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "SetConsoleTitleW returned %x(%lu)\n", ret, GetLastError());
4237
4238 SetLastError(0xdeadbeef);
4239 hwnd = GetConsoleWindow();
4240 ok(!hwnd, "hwnd = %p\n", hwnd);
4241 ok(GetLastError() == ERROR_INVALID_HANDLE, "last error %lu\n", GetLastError());
4242
4243 ret = GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
4244 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "GenerateConsoleCtrlEvent returned %x(%lu)\n",
4245 ret, GetLastError());
4246
4247 SetStdHandle( STD_INPUT_HANDLE, (HANDLE)0xdeadbeef );
4248 handle = GetConsoleInputWaitHandle();
4249 ok(handle == (HANDLE)0xdeadbeef, "GetConsoleInputWaitHandle returned %p\n", handle);
4250 SetStdHandle( STD_INPUT_HANDLE, NULL );
4251 handle = GetConsoleInputWaitHandle();
4252 ok(!handle, "GetConsoleInputWaitHandle returned %p\n", handle);
4253
4254 ret = ReadFile(unbound_input, buf, sizeof(buf), &size, NULL);
4255 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
4256 "ReadFile returned %x %lu\n", ret, GetLastError());
4257
4258 ret = FlushFileBuffers(unbound_input);
4259 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
4260 "ReadFile returned %x %lu\n", ret, GetLastError());
4261
4262 ret = WriteFile(unbound_input, "test", 4, &size, NULL);
4263 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
4264 "ReadFile returned %x %lu\n", ret, GetLastError());
4265
4266 ret = GetConsoleMode(unbound_input, &mode);
4267 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
4268 "GetConsoleMode returned %x %lu\n", ret, GetLastError());
4269 ret = GetConsoleMode(unbound_output, &mode);
4270 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE,
4271 "GetConsoleMode returned %x %lu\n", ret, GetLastError());
4272
4273 type = GetFileType(unbound_input);
4274 ok(type == FILE_TYPE_CHAR, "GetFileType returned %lu\n", type);
4275 type = GetFileType(unbound_output);
4276 ok(type == FILE_TYPE_CHAR, "GetFileType returned %lu\n", type);
4277
4278 todo_wine
4279 ok(!SetConsoleCtrlHandler(mydummych, FALSE), "FreeConsole() should have reset ctrl handlers' list\n");
4280
4281 CloseHandle(unbound_input);
4282 CloseHandle(unbound_output);
4283}
4284
4285static void test_SetConsoleScreenBufferInfoEx(HANDLE std_output)
4286{
4287#if defined(__REACTOS__) && DLL_EXPORT_VERSION < 0x600
4288 UNREFERENCED_PARAMETER(std_output);
4289 skip("Cannot build test_SetConsoleScreenBufferInfoEx() unless DLL_EXPORT_VERSION >= 0x600.\n");
4290#else
4291 BOOL ret;
4292 HANDLE hmod;
4293 HANDLE std_input = CreateFileA("CONIN$", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
4294 BOOL (WINAPI *pSetConsoleScreenBufferInfoEx)(HANDLE, CONSOLE_SCREEN_BUFFER_INFOEX *);
4295 BOOL (WINAPI *pGetConsoleScreenBufferInfoEx)(HANDLE, CONSOLE_SCREEN_BUFFER_INFOEX *);
4296 CONSOLE_SCREEN_BUFFER_INFOEX info;
4297
4298 hmod = GetModuleHandleA("kernel32.dll");
4299 pSetConsoleScreenBufferInfoEx = (void *)GetProcAddress(hmod, "SetConsoleScreenBufferInfoEx");
4300 pGetConsoleScreenBufferInfoEx = (void *)GetProcAddress(hmod, "GetConsoleScreenBufferInfoEx");
4301 if (!pSetConsoleScreenBufferInfoEx || !pGetConsoleScreenBufferInfoEx)
4302 {
4303 win_skip("SetConsoleScreenBufferInfoEx is not available\n");
4304 return;
4305 }
4306
4307 memset(&info, 0, sizeof(CONSOLE_SCREEN_BUFFER_INFOEX));
4308 info.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
4309 pGetConsoleScreenBufferInfoEx(std_output, &info);
4310
4311 SetLastError(0xdeadbeef);
4312 ret = pSetConsoleScreenBufferInfoEx(NULL, &info);
4313 ok(!ret, "got %d, expected zero\n", ret);
4314 ok(GetLastError() == ERROR_INVALID_HANDLE, "got %lu, expected 6\n", GetLastError());
4315
4316 SetLastError(0xdeadbeef);
4317 ret = pSetConsoleScreenBufferInfoEx(std_output, &info);
4318 ok(ret, "got %d, expected one\n", ret);
4319 ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError());
4320
4321 SetLastError(0xdeadbeef);
4322 ret = pSetConsoleScreenBufferInfoEx(std_input, &info);
4323 ok(!ret, "got %d, expected zero\n", ret);
4324 ok(GetLastError() == ERROR_INVALID_HANDLE || GetLastError() == ERROR_ACCESS_DENIED,
4325 "got %lu, expected 5 or 6\n", GetLastError());
4326
4327 info.cbSize = 0;
4328 SetLastError(0xdeadbeef);
4329 ret = pSetConsoleScreenBufferInfoEx(std_output, &info);
4330 ok(!ret, "got %d, expected zero\n", ret);
4331 ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %lu, expected 87\n", GetLastError());
4332
4333 CloseHandle(std_input);
4334#endif
4335}
4336
4337static void test_GetConsoleOriginalTitleA(void)
4338{
4339#if defined(__REACTOS__) && DLL_EXPORT_VERSION < 0x600
4340 skip("Cannot build test_GetConsoleOriginalTitleA() unless DLL_EXPORT_VERSION >= 0x600.\n");
4341#else
4342 char title[] = "Original Console Title";
4343 char buf[64];
4344 DWORD ret, title_len = strlen(title);
4345
4346 ret = GetConsoleOriginalTitleA(NULL, 0);
4347 ok(!ret, "Unexpected string length; error %lu\n", GetLastError());
4348
4349 ret = GetConsoleOriginalTitleA(buf, 0);
4350 ok(!ret, "Unexpected string length; error %lu\n", GetLastError());
4351
4352 ret = GetConsoleOriginalTitleA(buf, ARRAY_SIZE(buf));
4353 ok(ret, "GetConsoleOriginalTitleA failed: %lu\n", GetLastError());
4354 ok(!strcmp(buf, title), "got %s, expected %s\n", wine_dbgstr_a(buf), wine_dbgstr_a(title));
4355 ok(ret == title_len, "got %lu, expected %lu\n", ret, title_len);
4356
4357 ret = SetConsoleTitleA("test");
4358 ok(ret, "SetConsoleTitleA failed: %lu\n", GetLastError());
4359
4360 ret = GetConsoleOriginalTitleA(buf, ARRAY_SIZE(buf));
4361 ok(ret, "GetConsoleOriginalTitleA failed: %lu\n", GetLastError());
4362 ok(!strcmp(buf, title), "got %s, expected %s\n", wine_dbgstr_a(buf), wine_dbgstr_a(title));
4363 ok(ret == title_len, "got %lu, expected %lu\n", ret, title_len);
4364#endif
4365}
4366
4367static void test_GetConsoleOriginalTitleW(void)
4368{
4369#if defined(__REACTOS__) && DLL_EXPORT_VERSION < 0x600
4370 skip("Cannot build test_GetConsoleOriginalTitleW() unless DLL_EXPORT_VERSION >= 0x600.\n");
4371#else
4372 WCHAR title[] = L"Original Console Title";
4373 WCHAR buf[64];
4374 DWORD ret, title_len = lstrlenW(title);
4375
4376 ret = GetConsoleOriginalTitleW(NULL, 0);
4377 ok(!ret, "Unexpected string length; error %lu\n", GetLastError());
4378
4379 ret = GetConsoleOriginalTitleW(buf, 0);
4380 ok(!ret, "Unexpected string length; error %lu\n", GetLastError());
4381
4382 ret = GetConsoleOriginalTitleW(buf, ARRAY_SIZE(buf));
4383 ok(ret, "GetConsoleOriginalTitleW failed: %lu\n", GetLastError());
4384 buf[ret] = 0;
4385 ok(!wcscmp(buf, title), "got %s, expected %s\n", wine_dbgstr_w(buf), wine_dbgstr_w(title));
4386 ok(ret == title_len, "got %lu, expected %lu\n", ret, title_len);
4387
4388 ret = SetConsoleTitleW(L"test");
4389 ok(ret, "SetConsoleTitleW failed: %lu\n", GetLastError());
4390
4391 ret = GetConsoleOriginalTitleW(buf, ARRAY_SIZE(buf));
4392 ok(ret, "GetConsoleOriginalTitleW failed: %lu\n", GetLastError());
4393 ok(!wcscmp(buf, title), "got %s, expected %s\n", wine_dbgstr_w(buf), wine_dbgstr_w(title));
4394 ok(ret == title_len, "got %lu, expected %lu\n", ret, title_len);
4395
4396 ret = GetConsoleOriginalTitleW(buf, 5);
4397 ok(ret, "GetConsoleOriginalTitleW failed: %lu\n", GetLastError());
4398 ok(!wcscmp(buf, L"Orig"), "got %s, expected 'Orig'\n", wine_dbgstr_w(buf));
4399 ok(ret == title_len, "got %lu, expected %lu\n", ret, title_len);
4400#endif
4401}
4402
4403static void test_GetConsoleOriginalTitleW_empty(void)
4404{
4405#if defined(__REACTOS__) && DLL_EXPORT_VERSION < 0x600
4406 skip("Cannot build test_GetConsoleOriginalTitleW_empty() unless DLL_EXPORT_VERSION >= 0x600.\n");
4407#else
4408 WCHAR buf[64];
4409 DWORD ret;
4410
4411 ret = GetConsoleOriginalTitleW(buf, ARRAY_SIZE(buf));
4412 ok(!ret, "GetConsoleOriginalTitleW failed: %lu\n", GetLastError());
4413#endif
4414}
4415
4416static void test_GetConsoleOriginalTitle(void)
4417{
4418 STARTUPINFOA si = { sizeof(si) };
4419 PROCESS_INFORMATION info;
4420 char **argv, buf[MAX_PATH];
4421 char title[] = "Original Console Title";
4422 BOOL ret;
4423
4424#ifdef __REACTOS__
4425 if (GetNTVersion() < _WIN32_WINNT_VISTA) {
4426 skip("This test is incredibly broken on WS03\n");
4427 return;
4428 }
4429#endif
4430 winetest_get_mainargs(&argv);
4431 sprintf(buf, "\"%s\" console title_test", argv[0]);
4432 si.lpTitle = title;
4433 ret = CreateProcessA(NULL, buf, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &info);
4434 ok(ret, "CreateProcess failed: %lu\n", GetLastError());
4435 CloseHandle(info.hThread);
4436 wait_child_process(info.hProcess);
4437 CloseHandle(info.hProcess);
4438
4439 strcat(buf, " empty");
4440 title[0] = 0;
4441 ret = CreateProcessA(NULL, buf, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &info);
4442 ok(ret, "CreateProcess failed: %lu\n", GetLastError());
4443 CloseHandle(info.hThread);
4444 wait_child_process(info.hProcess);
4445 CloseHandle(info.hProcess);
4446}
4447
4448static void test_GetConsoleTitleA(void)
4449{
4450 char buf[64], str[] = "test";
4451 DWORD ret;
4452
4453 ret = SetConsoleTitleA(str);
4454 ok(ret, "SetConsoleTitleA failed: %lu\n", GetLastError());
4455
4456 ret = GetConsoleTitleA(NULL, 0);
4457 ok(!ret, "Unexpected string length; error %lu\n", GetLastError());
4458
4459 ret = GetConsoleTitleA(buf, 0);
4460 ok(!ret, "Unexpected string length; error %lu\n", GetLastError());
4461
4462 ret = GetConsoleTitleA(buf, ARRAY_SIZE(buf));
4463 ok(ret, "GetConsoleTitleW failed: %lu\n", GetLastError());
4464 ok(ret == strlen(str), "Got string length %lu, expected %Iu\n", ret, strlen(str));
4465 ok(!strcmp(buf, str), "Title = %s\n", wine_dbgstr_a(buf));
4466
4467 ret = SetConsoleTitleA("");
4468 ok(ret, "SetConsoleTitleA failed: %lu\n", GetLastError());
4469
4470 ret = GetConsoleTitleA(buf, ARRAY_SIZE(buf));
4471 ok(!ret, "Unexpected string length; error %lu\n", GetLastError());
4472}
4473
4474static void test_GetConsoleTitleW(void)
4475{
4476 WCHAR buf[64], str[] = L"test";
4477 DWORD ret;
4478
4479 ret = SetConsoleTitleW(str);
4480 ok(ret, "SetConsoleTitleW failed: %lu\n", GetLastError());
4481
4482 ret = GetConsoleTitleW(NULL, 0);
4483 ok(!ret, "Unexpected string length; error %lu\n", GetLastError());
4484
4485 ret = GetConsoleTitleW(buf, 0);
4486 ok(!ret, "Unexpected string length; error %lu\n", GetLastError());
4487
4488 ret = GetConsoleTitleW(buf, ARRAY_SIZE(buf));
4489 ok(ret, "GetConsoleTitleW failed: %lu\n", GetLastError());
4490 ok(ret == wcslen(str), "Got string length %lu, expected %Iu\n", ret, wcslen(str));
4491 ok(!wcscmp(buf, str), "Title = %s\n", wine_dbgstr_w(buf));
4492
4493 ret = GetConsoleTitleW(buf, 2);
4494 ok(ret, "GetConsoleTitleW failed: %lu\n", GetLastError());
4495#ifdef __REACTOS__
4496 if (GetNTVersion() >= _WIN32_WINNT_VISTA)
4497#endif
4498 ok(ret == wcslen(str), "Got string length %lu, expected %Iu\n", ret, wcslen(str));
4499 if (!skip_nt) ok(!wcscmp(buf, L"t"), "Title = %s\n", wine_dbgstr_w(buf));
4500
4501 ret = GetConsoleTitleW(buf, 4);
4502 ok(ret, "GetConsoleTitleW failed: %lu\n", GetLastError());
4503#ifdef __REACTOS__
4504 if (GetNTVersion() >= _WIN32_WINNT_VISTA)
4505#endif
4506 ok(ret == wcslen(str), "Got string length %lu, expected %Iu\n", ret, wcslen(str));
4507 if (!skip_nt) ok(!wcscmp(buf, L"tes"), "Title = %s\n", wine_dbgstr_w(buf));
4508
4509 ret = SetConsoleTitleW(L"");
4510 ok(ret, "SetConsoleTitleW failed: %lu\n", GetLastError());
4511
4512 ret = GetConsoleTitleW(buf, ARRAY_SIZE(buf));
4513 ok(!ret, "Unexpected string length; error %lu\n", GetLastError());
4514}
4515
4516static void test_file_info(HANDLE input, HANDLE output)
4517{
4518 FILE_STANDARD_INFORMATION std_info;
4519 FILE_FS_DEVICE_INFORMATION fs_info;
4520 LARGE_INTEGER size;
4521 IO_STATUS_BLOCK io;
4522 DWORD type;
4523 NTSTATUS status;
4524 BOOL ret;
4525
4526 if (skip_nt) return;
4527
4528 status = NtQueryInformationFile(input, &io, &std_info, sizeof(std_info), FileStandardInformation);
4529 ok(status == STATUS_INVALID_DEVICE_REQUEST, "NtQueryInformationFile returned: %#lx\n", status);
4530
4531 status = NtQueryInformationFile(output, &io, &std_info, sizeof(std_info), FileStandardInformation);
4532 ok(status == STATUS_INVALID_DEVICE_REQUEST, "NtQueryInformationFile returned: %#lx\n", status);
4533
4534 ret = GetFileSizeEx(input, &size);
4535 ok(!ret && GetLastError() == ERROR_INVALID_FUNCTION,
4536 "GetFileSizeEx returned %x(%lu)\n", ret, GetLastError());
4537
4538 ret = GetFileSizeEx(output, &size);
4539 ok(!ret && GetLastError() == ERROR_INVALID_FUNCTION,
4540 "GetFileSizeEx returned %x(%lu)\n", ret, GetLastError());
4541
4542 status = NtQueryVolumeInformationFile(input, &io, &fs_info, sizeof(fs_info), FileFsDeviceInformation);
4543 ok(!status, "NtQueryVolumeInformationFile failed: %#lx\n", status);
4544 ok(fs_info.DeviceType == FILE_DEVICE_CONSOLE, "DeviceType = %lu\n", fs_info.DeviceType);
4545 ok(fs_info.Characteristics == FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL,
4546 "Characteristics = %lx\n", fs_info.Characteristics);
4547
4548 status = NtQueryVolumeInformationFile(output, &io, &fs_info, sizeof(fs_info), FileFsDeviceInformation);
4549 ok(!status, "NtQueryVolumeInformationFile failed: %#lx\n", status);
4550 ok(fs_info.DeviceType == FILE_DEVICE_CONSOLE, "DeviceType = %lu\n", fs_info.DeviceType);
4551 ok(fs_info.Characteristics == FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL,
4552 "Characteristics = %lx\n", fs_info.Characteristics);
4553
4554 type = GetFileType(input);
4555 ok(type == FILE_TYPE_CHAR, "GetFileType returned %lu\n", type);
4556 type = GetFileType(output);
4557 ok(type == FILE_TYPE_CHAR, "GetFileType returned %lu\n", type);
4558}
4559
4560static void test_console_as_root_directory(void)
4561{
4562 OBJECT_ATTRIBUTES attr;
4563 IO_STATUS_BLOCK iosb;
4564 UNICODE_STRING name;
4565 HANDLE handle, h2;
4566 NTSTATUS status;
4567
4568 handle = CreateFileA( "CON", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0 );
4569 ok( handle != INVALID_HANDLE_VALUE, "CreateFileA error %lu\n", GetLastError() );
4570
4571 RtlInitUnicodeString( &name, L"" );
4572 InitializeObjectAttributes( &attr, &name, 0, handle, NULL );
4573 status = NtCreateFile( &h2, SYNCHRONIZE, &attr, &iosb, NULL, 0,
4574 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
4575 FILE_OPEN, 0, NULL, 0 );
4576#ifdef __REACTOS__
4577 ok( status == STATUS_NOT_FOUND || broken( status == STATUS_OBJECT_TYPE_MISMATCH ) /* Win7 */ || broken( status == STATUS_INVALID_HANDLE ) /* WS03 */,
4578#else
4579 ok( status == STATUS_NOT_FOUND || broken( status == STATUS_OBJECT_TYPE_MISMATCH ) /* Win7 */,
4580#endif
4581 "NtCreateFile returned %#lx\n", status );
4582
4583 CloseHandle( handle );
4584}
4585
4586static void test_condrv_server_as_root_directory(void)
4587{
4588 OBJECT_ATTRIBUTES attr;
4589 IO_STATUS_BLOCK iosb;
4590 UNICODE_STRING name;
4591 HANDLE handle, h2;
4592 NTSTATUS status;
4593
4594 FreeConsole();
4595
4596 RtlInitUnicodeString( &name, L"\\Device\\ConDrv\\Server" );
4597 InitializeObjectAttributes( &attr, &name, 0, NULL, NULL );
4598 status = NtCreateFile( &handle, SYNCHRONIZE, &attr, &iosb, NULL, 0,
4599 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
4600 FILE_OPEN, 0, NULL, 0 );
4601 ok( !status || broken( status == STATUS_OBJECT_PATH_NOT_FOUND ) /* Win7 */,
4602 "NtCreateFile returned %#lx\n", status );
4603
4604 if (status)
4605 {
4606 win_skip( "cannot open \\Device\\ConDrv\\Server, skipping RootDirectory test" );
4607 }
4608 else
4609 {
4610 RtlInitUnicodeString( &name, L"" );
4611 InitializeObjectAttributes( &attr, &name, 0, handle, NULL );
4612 status = NtCreateFile( &h2, SYNCHRONIZE, &attr, &iosb, NULL, 0,
4613 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
4614 FILE_OPEN, 0, NULL, 0 );
4615 ok( status == STATUS_NOT_FOUND, "NtCreateFile returned %#lx\n", status );
4616
4617 CloseHandle( handle );
4618 }
4619}
4620
4621static void test_AttachConsole_child(DWORD console_pid)
4622{
4623 HANDLE pipe_in, pipe_out;
4624 COORD c = {0,0};
4625 HANDLE console;
4626 char buf[32];
4627 DWORD len;
4628 BOOL res;
4629
4630 res = CreatePipe(&pipe_in, &pipe_out, NULL, 0);
4631 ok(res, "CreatePipe failed: %lu\n", GetLastError());
4632
4633 res = AttachConsole(console_pid);
4634 ok(!res && GetLastError() == ERROR_ACCESS_DENIED,
4635 "AttachConsole returned: %x(%lu)\n", res, GetLastError());
4636
4637 ok(RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle != NULL, "ConsoleHandle is NULL\n");
4638 res = FreeConsole();
4639 ok(res, "FreeConsole failed: %lu\n", GetLastError());
4640 ok(RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle == NULL, "ConsoleHandle = %p\n",
4641 RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle);
4642
4643 SetStdHandle(STD_ERROR_HANDLE, pipe_out);
4644
4645 ok(!SetConsoleCtrlHandler(mydummych, FALSE), "dummy ctrl handler shouldn't be set\n");
4646 res = SetConsoleCtrlHandler(mydummych, TRUE);
4647 ok(res, "SetConsoleCtrlHandler failed: %lu\n", GetLastError());
4648
4649 res = AttachConsole(console_pid);
4650 ok(res, "AttachConsole failed: %lu\n", GetLastError());
4651
4652 ok(pipe_out != GetStdHandle(STD_ERROR_HANDLE), "std handle not set to console\n");
4653 ok(RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle != NULL, "ConsoleHandle is NULL\n");
4654
4655 console = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
4656 ok(console != INVALID_HANDLE_VALUE, "Could not open console\n");
4657
4658 res = ReadConsoleOutputCharacterA(console, buf, 6, c, &len);
4659 ok(res, "ReadConsoleOutputCharacterA failed: %lu\n", GetLastError());
4660 ok(len == 6, "len = %lu\n", len);
4661 ok(!memcmp(buf, "Parent", 6), "Unexpected console output\n");
4662
4663 todo_wine
4664 ok(!SetConsoleCtrlHandler(mydummych, FALSE), "AttachConsole() should have reset ctrl handlers' list\n");
4665
4666 res = FreeConsole();
4667 ok(res, "FreeConsole failed: %lu\n", GetLastError());
4668
4669 SetStdHandle(STD_INPUT_HANDLE, pipe_in);
4670 SetStdHandle(STD_OUTPUT_HANDLE, pipe_out);
4671
4672 res = AttachConsole(ATTACH_PARENT_PROCESS);
4673 ok(res, "AttachConsole failed: %lu\n", GetLastError());
4674
4675 if (pGetConsoleProcessList)
4676 {
4677 DWORD list[2] = { 0xbabebabe };
4678 DWORD pid = GetCurrentProcessId();
4679
4680 SetLastError(0xdeadbeef);
4681 len = pGetConsoleProcessList(list, 1);
4682 ok(len == 2, "Expected 2 processes, got %ld\n", len);
4683 ok(list[0] == 0xbabebabe, "Unexpected value in list %lu\n", list[0]);
4684
4685 len = pGetConsoleProcessList(list, 2);
4686 ok(len == 2, "Expected 2 processes, got %ld\n", len);
4687 ok(list[0] == console_pid || list[1] == console_pid, "Parent PID not in list\n");
4688 ok(list[0] == pid || list[1] == pid, "PID not in list\n");
4689 ok(GetLastError() == 0xdeadbeef, "Unexpected last error: %lu\n", GetLastError());
4690 }
4691
4692 ok(pipe_in != GetStdHandle(STD_INPUT_HANDLE), "std handle not set to console\n");
4693 ok(pipe_out != GetStdHandle(STD_OUTPUT_HANDLE), "std handle not set to console\n");
4694
4695 console = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
4696 ok(console != INVALID_HANDLE_VALUE, "Could not open console\n");
4697
4698 res = ReadConsoleOutputCharacterA(console, buf, 6, c, &len);
4699 ok(res, "ReadConsoleOutputCharacterA failed: %lu\n", GetLastError());
4700 ok(len == 6, "len = %lu\n", len);
4701 ok(!memcmp(buf, "Parent", 6), "Unexpected console output\n");
4702
4703 simple_write_console(console, "Child");
4704 CloseHandle(console);
4705
4706 res = FreeConsole();
4707 ok(res, "FreeConsole failed: %lu\n", GetLastError());
4708
4709 res = CloseHandle(pipe_in);
4710 ok(res, "pipe_in is no longer valid\n");
4711 res = CloseHandle(pipe_out);
4712 ok(res, "pipe_out is no longer valid\n");
4713}
4714
4715static void test_AttachConsole(HANDLE console)
4716{
4717 STARTUPINFOA si = { sizeof(si) };
4718 PROCESS_INFORMATION info;
4719 char **argv, buf[MAX_PATH];
4720 COORD c = {0,0};
4721 DWORD len;
4722 BOOL res;
4723
4724 simple_write_console(console, "Parent console");
4725
4726 winetest_get_mainargs(&argv);
4727 sprintf(buf, "\"%s\" console attach_console %lx", argv[0], GetCurrentProcessId());
4728 res = CreateProcessA(NULL, buf, NULL, NULL, TRUE, 0, NULL, NULL, &si, &info);
4729 ok(res, "CreateProcess failed: %lu\n", GetLastError());
4730 CloseHandle(info.hThread);
4731
4732 wait_child_process(info.hProcess);
4733 CloseHandle(info.hProcess);
4734
4735 res = ReadConsoleOutputCharacterA(console, buf, 5, c, &len);
4736 ok(res, "ReadConsoleOutputCharacterA failed: %lu\n", GetLastError());
4737 ok(len == 5, "len = %lu\n", len);
4738 ok(!memcmp(buf, "Child", 5), "Unexpected console output\n");
4739}
4740
4741static void test_AllocConsole_child(void)
4742{
4743 HANDLE unbound_output;
4744 HANDLE prev_output, prev_error;
4745 STARTUPINFOW si;
4746 DWORD mode;
4747 BOOL res;
4748
4749 GetStartupInfoW(&si);
4750
4751 prev_output = GetStdHandle(STD_OUTPUT_HANDLE);
4752 res = DuplicateHandle(GetCurrentProcess(), prev_output, GetCurrentProcess(), &unbound_output,
4753 0, FALSE, DUPLICATE_SAME_ACCESS);
4754 ok(res, "DuplicateHandle failed: %lu\n", GetLastError());
4755
4756 res = GetConsoleMode(unbound_output, &mode);
4757 ok(res, "GetConsoleMode failed: %lu\n", GetLastError());
4758
4759 prev_error = GetStdHandle(STD_ERROR_HANDLE);
4760 if (si.dwFlags & STARTF_USESTDHANDLES)
4761 {
4762 res = GetConsoleMode(prev_error, &mode);
4763 ok(!res && GetLastError() == ERROR_INVALID_HANDLE, "GetConsoleMode failed: %lu\n", GetLastError());
4764 }
4765
4766 FreeConsole();
4767
4768 ok(GetStdHandle(STD_OUTPUT_HANDLE) == prev_output, "GetStdHandle(STD_OUTPUT_HANDLE) = %p\n", GetStdHandle(STD_OUTPUT_HANDLE));
4769 ok(GetStdHandle(STD_ERROR_HANDLE) == prev_error, "GetStdHandle(STD_ERROR_HANDLE) = %p\n", GetStdHandle(STD_ERROR_HANDLE));
4770 res = GetConsoleMode(unbound_output, &mode);
4771 ok(!res && GetLastError() == ERROR_INVALID_HANDLE, "GetConsoleMode failed: %lu\n", GetLastError());
4772
4773 ok(!SetConsoleCtrlHandler(mydummych, FALSE), "dummy ctrl handler shouldn't be set\n");
4774 res = SetConsoleCtrlHandler(mydummych, TRUE);
4775 ok(res, "SetConsoleCtrlHandler failed: %lu\n", GetLastError());
4776 res = AllocConsole();
4777 ok(res, "AllocConsole failed: %lu\n", GetLastError());
4778
4779 if (si.dwFlags & STARTF_USESTDHANDLES)
4780 {
4781 ok(GetStdHandle(STD_OUTPUT_HANDLE) == prev_output, "GetStdHandle(STD_OUTPUT_HANDLE) = %p\n", GetStdHandle(STD_OUTPUT_HANDLE));
4782 ok(GetStdHandle(STD_ERROR_HANDLE) == prev_error, "GetStdHandle(STD_ERROR_HANDLE) = %p\n", GetStdHandle(STD_ERROR_HANDLE));
4783 }
4784
4785 res = GetConsoleMode(unbound_output, &mode);
4786 ok(res, "GetConsoleMode failed: %lu\n", GetLastError());
4787
4788 todo_wine
4789 ok(!SetConsoleCtrlHandler(mydummych, FALSE), "AllocConsole() should have reset ctrl handlers' list\n");
4790
4791 FreeConsole();
4792 SetStdHandle(STD_OUTPUT_HANDLE, NULL);
4793 SetStdHandle(STD_ERROR_HANDLE, NULL);
4794 res = AllocConsole();
4795 ok(res, "AllocConsole failed: %lu\n", GetLastError());
4796
4797 ok(GetStdHandle(STD_OUTPUT_HANDLE) != NULL, "GetStdHandle(STD_OUTPUT_HANDLE) = %p\n", GetStdHandle(STD_OUTPUT_HANDLE));
4798 ok(GetStdHandle(STD_ERROR_HANDLE) != NULL, "GetStdHandle(STD_ERROR_HANDLE) = %p\n", GetStdHandle(STD_ERROR_HANDLE));
4799
4800 res = GetConsoleMode(unbound_output, &mode);
4801 ok(res, "GetConsoleMode failed: %lu\n", GetLastError());
4802 res = GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &mode);
4803 ok(res, "GetConsoleMode failed: %lu\n", GetLastError());
4804 res = GetConsoleMode(GetStdHandle(STD_ERROR_HANDLE), &mode);
4805 ok(res, "GetConsoleMode failed: %lu\n", GetLastError());
4806
4807 res = CloseHandle(unbound_output);
4808 ok(res, "CloseHandle failed: %lu\n", GetLastError());
4809}
4810
4811static void test_AllocConsole(void)
4812{
4813 SECURITY_ATTRIBUTES inheritable_attr = { sizeof(inheritable_attr), NULL, TRUE };
4814 STARTUPINFOA si = { sizeof(si) };
4815 PROCESS_INFORMATION info;
4816 char **argv, buf[MAX_PATH];
4817 HANDLE pipe_read, pipe_write;
4818 BOOL res;
4819
4820 if (skip_nt) return;
4821
4822 winetest_get_mainargs(&argv);
4823 sprintf(buf, "\"%s\" console alloc_console", argv[0]);
4824 res = CreateProcessA(NULL, buf, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &info);
4825 ok(res, "CreateProcess failed: %lu\n", GetLastError());
4826 CloseHandle(info.hThread);
4827 wait_child_process(info.hProcess);
4828 CloseHandle(info.hProcess);
4829
4830 res = CreatePipe(&pipe_read, &pipe_write, &inheritable_attr, 0);
4831 ok(res, "CreatePipe failed: %lu\n", GetLastError());
4832
4833 si.dwFlags = STARTF_USESTDHANDLES;
4834 si.hStdError = pipe_write;
4835 res = CreateProcessA(NULL, buf, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &info);
4836 ok(res, "CreateProcess failed: %lu\n", GetLastError());
4837 CloseHandle(info.hThread);
4838 wait_child_process(info.hProcess);
4839 CloseHandle(info.hProcess);
4840
4841 CloseHandle(pipe_read);
4842 CloseHandle(pipe_write);
4843}
4844
4845static void test_pseudo_console_child(HANDLE input, HANDLE output)
4846{
4847 CONSOLE_SCREEN_BUFFER_INFO sb_info;
4848 CONSOLE_CURSOR_INFO cursor_info;
4849 DWORD mode;
4850 HWND hwnd;
4851 BOOL ret;
4852
4853 ret = GetConsoleMode(input, &mode);
4854 ok(ret, "GetConsoleMode failed: %lu\n", GetLastError());
4855 ok(mode == (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT |
4856 ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS | ENABLE_AUTO_POSITION),
4857 "mode = %lx\n", mode);
4858
4859 ret = SetConsoleMode(input, mode & ~ENABLE_AUTO_POSITION);
4860 ok(ret, "SetConsoleMode failed: %lu\n", GetLastError());
4861
4862 ret = GetConsoleMode(input, &mode);
4863 ok(ret, "GetConsoleMode failed: %lu\n", GetLastError());
4864 ok(mode == (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT |
4865 ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS), "mode = %lx\n", mode);
4866
4867 ret = SetConsoleMode(input, mode | ENABLE_AUTO_POSITION);
4868 ok(ret, "SetConsoleMode failed: %lu\n", GetLastError());
4869
4870 ret = GetConsoleMode(output, &mode);
4871 ok(ret, "GetConsoleMode failed: %lu\n", GetLastError());
4872 mode &= ~ENABLE_VIRTUAL_TERMINAL_PROCESSING;
4873 ok(mode == (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT), "mode = %lx\n", mode);
4874
4875 ret = SetConsoleMode(output, mode & ~ENABLE_WRAP_AT_EOL_OUTPUT);
4876 ok(ret, "SetConsoleMode failed: %lu\n", GetLastError());
4877
4878 ret = GetConsoleMode(output, &mode);
4879 ok(ret, "GetConsoleMode failed: %lu\n", GetLastError());
4880 ok(mode == ENABLE_PROCESSED_OUTPUT, "mode = %lx\n", mode);
4881
4882 ret = SetConsoleMode(output, mode | ENABLE_WRAP_AT_EOL_OUTPUT);
4883 ok(ret, "SetConsoleMode failed: %lu\n", GetLastError());
4884
4885 ret = GetConsoleScreenBufferInfo(output, &sb_info);
4886 ok(ret, "GetConsoleScreenBufferInfo failed: %lu\n", GetLastError());
4887 ok(sb_info.dwSize.X == 40, "dwSize.X = %u\n", sb_info.dwSize.X);
4888 ok(sb_info.dwSize.Y == 30, "dwSize.Y = %u\n", sb_info.dwSize.Y);
4889 ok(sb_info.dwCursorPosition.X == 0, "dwCursorPosition.X = %u\n", sb_info.dwCursorPosition.X);
4890 ok(sb_info.dwCursorPosition.Y == 0, "dwCursorPosition.Y = %u\n", sb_info.dwCursorPosition.Y);
4891 ok(sb_info.wAttributes == 7, "wAttributes = %x\n", sb_info.wAttributes);
4892 ok(sb_info.srWindow.Left == 0, "srWindow.Left = %u\n", sb_info.srWindow.Left);
4893 ok(sb_info.srWindow.Top == 0, "srWindow.Top = %u\n", sb_info.srWindow.Top);
4894 ok(sb_info.srWindow.Right == 39, "srWindow.Right = %u\n", sb_info.srWindow.Right);
4895 ok(sb_info.srWindow.Bottom == 29, "srWindow.Bottom = %u\n", sb_info.srWindow.Bottom);
4896 ok(sb_info.dwMaximumWindowSize.X == 40, "dwMaximumWindowSize.X = %u\n", sb_info.dwMaximumWindowSize.X);
4897 ok(sb_info.dwMaximumWindowSize.Y == 30, "dwMaximumWindowSize.Y = %u\n", sb_info.dwMaximumWindowSize.Y);
4898
4899 ret = GetConsoleCursorInfo(output, &cursor_info);
4900 ok(ret, "GetConsoleCursorInfo failed: %lu\n", GetLastError());
4901 ok(cursor_info.dwSize == 25, "dwSize = %lu\n", cursor_info.dwSize);
4902 ok(cursor_info.bVisible == TRUE, "bVisible = %x\n", cursor_info.bVisible);
4903
4904 hwnd = GetConsoleWindow();
4905 ok(IsWindow(hwnd), "no console window\n");
4906
4907 test_GetConsoleTitleA();
4908 test_GetConsoleTitleW();
4909 test_WriteConsoleInputW(input);
4910}
4911
4912static DWORD WINAPI read_pipe_proc( void *handle )
4913{
4914 char buf[64];
4915 DWORD size;
4916 while (ReadFile(handle, buf, sizeof(buf), &size, NULL));
4917 ok(GetLastError() == ERROR_BROKEN_PIPE, "ReadFile returned %lu\n", GetLastError());
4918 CloseHandle(handle);
4919 return 0;
4920}
4921
4922static void test_pseudo_console(void)
4923{
4924 STARTUPINFOEXA startup = {{ sizeof(startup) }};
4925 HANDLE console_pipe, console_pipe2, thread;
4926 char **argv, cmdline[MAX_PATH];
4927 PROCESS_INFORMATION info;
4928 HPCON pseudo_console;
4929 SIZE_T attr_size;
4930 COORD size;
4931 BOOL ret;
4932 HRESULT hres;
4933
4934 if (!pCreatePseudoConsole)
4935 {
4936 win_skip("CreatePseudoConsole not available\n");
4937 return;
4938 }
4939
4940 console_pipe = CreateNamedPipeW(L"\\\\.\\pipe\\pseudoconsoleconn", PIPE_ACCESS_DUPLEX,
4941 PIPE_WAIT | PIPE_TYPE_BYTE, 1, 4096, 4096, NMPWAIT_USE_DEFAULT_WAIT, NULL);
4942 ok(console_pipe != INVALID_HANDLE_VALUE, "CreateNamedPipeW failed: %lu\n", GetLastError());
4943
4944 console_pipe2 = CreateFileW(L"\\\\.\\pipe\\pseudoconsoleconn", GENERIC_READ | GENERIC_WRITE, 0, NULL,
4945 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
4946 ok(console_pipe2 != INVALID_HANDLE_VALUE, "CreateFile failed: %lu\n", GetLastError());
4947
4948 thread = CreateThread( NULL, 0, read_pipe_proc, console_pipe, 0, NULL );
4949 CloseHandle(thread);
4950
4951 size.X = 0;
4952 size.Y = 30;
4953 hres = pCreatePseudoConsole(size, console_pipe2, console_pipe2, 0, &pseudo_console);
4954 ok(hres == E_INVALIDARG, "CreatePseudoConsole failed: %08lx\n", hres);
4955
4956 size.X = 40;
4957 size.Y = 0;
4958 hres = pCreatePseudoConsole(size, console_pipe2, console_pipe2, 0, &pseudo_console);
4959 ok(hres == E_INVALIDARG, "CreatePseudoConsole failed: %08lx\n", hres);
4960
4961 size.X = 40;
4962 size.Y = 30;
4963 hres = pCreatePseudoConsole(size, console_pipe2, console_pipe2, 0, &pseudo_console);
4964 ok(hres == S_OK, "CreatePseudoConsole failed: %08lx\n", hres);
4965 CloseHandle(console_pipe2);
4966
4967#if !defined(__REACTOS__) || DLL_EXPORT_VERSION >= 0x600
4968 InitializeProcThreadAttributeList(NULL, 1, 0, &attr_size);
4969 startup.lpAttributeList = HeapAlloc(GetProcessHeap(), 0, attr_size);
4970 InitializeProcThreadAttributeList(startup.lpAttributeList, 1, 0, &attr_size);
4971 UpdateProcThreadAttribute(startup.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, pseudo_console,
4972 sizeof(pseudo_console), NULL, NULL);
4973#endif
4974
4975 winetest_get_mainargs(&argv);
4976 sprintf(cmdline, "\"%s\" %s --pseudo-console", argv[0], argv[1]);
4977 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, &startup.StartupInfo, &info);
4978 ok(ret, "CreateProcessW failed: %lu\n", GetLastError());
4979
4980 CloseHandle(info.hThread);
4981 HeapFree(GetProcessHeap(), 0, startup.lpAttributeList);
4982 wait_child_process(info.hProcess);
4983 CloseHandle(info.hProcess);
4984
4985 pClosePseudoConsole(pseudo_console);
4986}
4987
4988/* copy an executable, but changing its subsystem */
4989static void copy_change_subsystem(const char* in, const char* out, DWORD subsyst)
4990{
4991 BOOL ret;
4992 HANDLE hFile, hMap;
4993 void* mapping;
4994 IMAGE_NT_HEADERS *nthdr;
4995
4996 ret = CopyFileA(in, out, FALSE);
4997 ok(ret, "Failed to copy executable %s in %s (%lu)\n", in, out, GetLastError());
4998
4999 hFile = CreateFileA(out, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
5000 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5001 ok(hFile != INVALID_HANDLE_VALUE, "Couldn't open file %s (%lu)\n", out, GetLastError());
5002 hMap = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
5003 ok(hMap != NULL, "Couldn't create map (%lu)\n", GetLastError());
5004 mapping = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
5005 ok(mapping != NULL, "Couldn't map (%lu)\n", GetLastError());
5006 nthdr = RtlImageNtHeader(mapping);
5007 ok(nthdr != NULL, "Cannot get NT headers out of %s\n", out);
5008 if (nthdr) nthdr->OptionalHeader.Subsystem = subsyst;
5009 ret = UnmapViewOfFile(mapping);
5010 ok(ret, "Couldn't unmap (%lu)\n", GetLastError());
5011 CloseHandle(hMap);
5012 CloseHandle(hFile);
5013}
5014
5015enum inheritance_model {NULL_STD, CONSOLE_STD, STARTUPINFO_STD};
5016
5017static DWORD check_child_console_bits(const char* exec, DWORD flags, enum inheritance_model inherit)
5018{
5019 SECURITY_ATTRIBUTES sa = {0, NULL, TRUE};
5020 STARTUPINFOA si = { sizeof(si) };
5021 PROCESS_INFORMATION info;
5022 char buf[MAX_PATH];
5023 HANDLE handle;
5024 DWORD exit_code;
5025 BOOL res;
5026 DWORD ret;
5027 BOOL inherit_handles = FALSE;
5028
5029 sprintf(buf, "\"%s\" console check_console", exec);
5030 switch (inherit)
5031 {
5032 case NULL_STD:
5033 SetStdHandle(STD_INPUT_HANDLE, NULL);
5034 SetStdHandle(STD_OUTPUT_HANDLE, NULL);
5035 SetStdHandle(STD_ERROR_HANDLE, NULL);
5036 break;
5037 case CONSOLE_STD:
5038 handle = CreateFileA("CONIN$", GENERIC_READ, 0, &sa, OPEN_EXISTING, 0, 0);
5039 ok(handle != INVALID_HANDLE_VALUE, "Couldn't create input to console\n");
5040 SetStdHandle(STD_INPUT_HANDLE, handle);
5041 handle = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
5042 ok(handle != INVALID_HANDLE_VALUE, "Couldn't create input to console\n");
5043 SetStdHandle(STD_OUTPUT_HANDLE, handle);
5044 SetStdHandle(STD_ERROR_HANDLE, handle);
5045 break;
5046 case STARTUPINFO_STD:
5047 si.dwFlags |= STARTF_USESTDHANDLES;
5048 si.hStdInput = CreateFileA("CONIN$", GENERIC_READ, 0, &sa, OPEN_EXISTING, 0, 0);
5049 ok(si.hStdInput != INVALID_HANDLE_VALUE, "Couldn't create input to console\n");
5050 si.hStdOutput = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
5051 ok(si.hStdInput != INVALID_HANDLE_VALUE, "Couldn't create output to console\n");
5052 si.hStdError = INVALID_HANDLE_VALUE;
5053 inherit_handles = TRUE;
5054 break;
5055 }
5056 res = CreateProcessA(NULL, buf, NULL, NULL, inherit_handles, flags, NULL, NULL, &si, &info);
5057 ok(res, "CreateProcess failed: %lu %s\n", GetLastError(), buf);
5058 CloseHandle(info.hThread);
5059 ret = WaitForSingleObject(info.hProcess, 30000);
5060 ok(ret == WAIT_OBJECT_0, "Could not wait for the child process: %ld le=%lu\n",
5061 ret, GetLastError());
5062 res = GetExitCodeProcess(info.hProcess, &exit_code);
5063 ok(res && exit_code <= 255, "Couldn't get exit_code\n");
5064 CloseHandle(info.hProcess);
5065 switch (inherit)
5066 {
5067 case NULL_STD:
5068 break;
5069 case CONSOLE_STD:
5070 CloseHandle(GetStdHandle(STD_INPUT_HANDLE));
5071 CloseHandle(GetStdHandle(STD_OUTPUT_HANDLE));
5072 break;
5073 case STARTUPINFO_STD:
5074 CloseHandle(si.hStdInput);
5075 CloseHandle(si.hStdOutput);
5076 break;
5077 }
5078 return exit_code;
5079}
5080
5081#define CP_WITH_CONSOLE 0x01 /* attached to a console */
5082#define CP_WITH_HANDLE 0x02 /* child has a console handle */
5083#define CP_WITH_WINDOW 0x04 /* child has a console window */
5084#define CP_ALONE 0x08 /* whether child is the single process attached to console */
5085#define CP_GROUP_LEADER 0x10 /* whether the child is the process group leader */
5086#define CP_INPUT_VALID 0x20 /* whether StdHandle(INPUT) is a valid console handle */
5087#define CP_OUTPUT_VALID 0x40 /* whether StdHandle(OUTPUT) is a valid console handle */
5088#define CP_ENABLED_CTRLC 0x80 /* whether the ctrl-c handling isn't blocked */
5089
5090#define CP_OWN_CONSOLE (CP_WITH_CONSOLE | CP_WITH_HANDLE | CP_INPUT_VALID | CP_OUTPUT_VALID | CP_ALONE)
5091#define CP_INH_CONSOLE (CP_WITH_CONSOLE | CP_WITH_HANDLE | CP_INPUT_VALID | CP_OUTPUT_VALID)
5092
5093static void test_CreateProcessCUI(void)
5094{
5095 HANDLE hstd[3];
5096 static char guiexec[MAX_PATH];
5097 static char cuiexec[MAX_PATH];
5098 char **argv;
5099 BOOL res;
5100 int i;
5101 BOOL saved_console_flags;
5102
5103 static struct
5104 {
5105 BOOL use_cui;
5106 DWORD cp_flags;
5107 enum inheritance_model inherit;
5108 DWORD expected;
5109 DWORD is_broken;
5110 }
5111 no_console_tests[] =
5112 {
5113/* 0*/ {FALSE, 0, NULL_STD, 0},
5114 {FALSE, DETACHED_PROCESS, NULL_STD, 0},
5115 {FALSE, CREATE_NEW_CONSOLE, NULL_STD, 0},
5116 {FALSE, CREATE_NO_WINDOW, NULL_STD, 0},
5117 {FALSE, DETACHED_PROCESS | CREATE_NO_WINDOW, NULL_STD, 0},
5118/* 5*/ {FALSE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, NULL_STD, 0},
5119
5120 {TRUE, 0, NULL_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW},
5121 {TRUE, DETACHED_PROCESS, NULL_STD, 0},
5122 {TRUE, CREATE_NEW_CONSOLE, NULL_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW},
5123 {TRUE, CREATE_NO_WINDOW, NULL_STD, CP_OWN_CONSOLE},
5124/*10*/ {TRUE, DETACHED_PROCESS | CREATE_NO_WINDOW, NULL_STD, 0},
5125 {TRUE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, NULL_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW},
5126 },
5127 with_console_tests[] =
5128 {
5129/* 0*/ {FALSE, 0, NULL_STD, 0},
5130 {FALSE, DETACHED_PROCESS, NULL_STD, 0},
5131 {FALSE, CREATE_NEW_CONSOLE, NULL_STD, 0},
5132 {FALSE, CREATE_NO_WINDOW, NULL_STD, 0},
5133 {FALSE, DETACHED_PROCESS | CREATE_NO_WINDOW, NULL_STD, 0},
5134/* 5*/ {FALSE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, NULL_STD, 0},
5135
5136 {FALSE, 0, CONSOLE_STD, 0},
5137 {FALSE, DETACHED_PROCESS, CONSOLE_STD, 0},
5138 {FALSE, CREATE_NEW_CONSOLE, CONSOLE_STD, 0},
5139 {FALSE, CREATE_NO_WINDOW, CONSOLE_STD, 0},
5140/*10*/ {FALSE, DETACHED_PROCESS | CREATE_NO_WINDOW, CONSOLE_STD, 0},
5141 {FALSE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, CONSOLE_STD, 0},
5142
5143 {FALSE, 0, STARTUPINFO_STD, 0},
5144 {FALSE, DETACHED_PROCESS, STARTUPINFO_STD, 0},
5145 {FALSE, CREATE_NEW_CONSOLE, STARTUPINFO_STD, 0},
5146/*15*/ {FALSE, CREATE_NO_WINDOW, STARTUPINFO_STD, 0},
5147 {FALSE, DETACHED_PROCESS | CREATE_NO_WINDOW, STARTUPINFO_STD, 0},
5148 {FALSE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, STARTUPINFO_STD, 0},
5149
5150 {TRUE, 0, NULL_STD, CP_WITH_CONSOLE | CP_WITH_HANDLE | CP_WITH_WINDOW},
5151 {TRUE, DETACHED_PROCESS, NULL_STD, 0},
5152/*20*/ {TRUE, CREATE_NEW_CONSOLE, NULL_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW},
5153#ifndef __REACTOS__
5154 {TRUE, CREATE_NO_WINDOW, NULL_STD, CP_OWN_CONSOLE},
5155#endif
5156 {TRUE, DETACHED_PROCESS | CREATE_NO_WINDOW, NULL_STD, 0},
5157 {TRUE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, NULL_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW},
5158
5159 {TRUE, 0, CONSOLE_STD, CP_INH_CONSOLE | CP_WITH_WINDOW},
5160/*25*/ {TRUE, DETACHED_PROCESS, CONSOLE_STD, 0},
5161 {TRUE, CREATE_NEW_CONSOLE, CONSOLE_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW},
5162#ifndef __REACTOS__
5163 {TRUE, CREATE_NO_WINDOW, CONSOLE_STD, CP_OWN_CONSOLE},
5164#endif
5165 {TRUE, DETACHED_PROCESS | CREATE_NO_WINDOW, CONSOLE_STD, 0},
5166 {TRUE, CREATE_NEW_CONSOLE | CREATE_NO_WINDOW, CONSOLE_STD, CP_OWN_CONSOLE | CP_WITH_WINDOW},
5167
5168/*30*/ {TRUE, 0, STARTUPINFO_STD, CP_INH_CONSOLE | CP_WITH_WINDOW},
5169 {TRUE, DETACHED_PROCESS, STARTUPINFO_STD, CP_INPUT_VALID | CP_OUTPUT_VALID, .is_broken = 0x100},
5170 {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},
5171#ifndef __REACTOS__
5172 {TRUE, CREATE_NO_WINDOW, STARTUPINFO_STD, CP_OWN_CONSOLE, .is_broken = CP_WITH_CONSOLE | CP_WITH_HANDLE | CP_ALONE},
5173#endif
5174 {TRUE, DETACHED_PROCESS | CREATE_NO_WINDOW, STARTUPINFO_STD, CP_INPUT_VALID | CP_OUTPUT_VALID, .is_broken = 0x100},
5175/*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},
5176 };
5177 static struct group_flags_tests
5178 {
5179 /* input */
5180 BOOL use_cui;
5181 DWORD cp_flags;
5182 enum inheritance_model inherit;
5183 BOOL noctrl_flag;
5184 /* output */
5185 DWORD expected;
5186 }
5187 group_flags_tests[] =
5188 {
5189/* 0 */ {TRUE, 0, CONSOLE_STD, TRUE, CP_INH_CONSOLE | CP_WITH_WINDOW},
5190 {TRUE, CREATE_NEW_PROCESS_GROUP, CONSOLE_STD, TRUE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_GROUP_LEADER},
5191 {TRUE, 0, CONSOLE_STD, FALSE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_ENABLED_CTRLC},
5192 {TRUE, CREATE_NEW_PROCESS_GROUP, CONSOLE_STD, FALSE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_GROUP_LEADER},
5193 {TRUE, 0, STARTUPINFO_STD, TRUE, CP_INH_CONSOLE | CP_WITH_WINDOW},
5194/* 5 */ {TRUE, CREATE_NEW_PROCESS_GROUP, STARTUPINFO_STD, TRUE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_GROUP_LEADER},
5195 {TRUE, 0, STARTUPINFO_STD, FALSE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_ENABLED_CTRLC},
5196 {TRUE, CREATE_NEW_PROCESS_GROUP, STARTUPINFO_STD, FALSE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_GROUP_LEADER},
5197 {FALSE, 0, CONSOLE_STD, TRUE, 0},
5198#ifndef __REACTOS__
5199 {FALSE, CREATE_NEW_PROCESS_GROUP, CONSOLE_STD, TRUE, CP_GROUP_LEADER},
5200#endif
5201/* 10 */ {FALSE, 0, CONSOLE_STD, FALSE, CP_ENABLED_CTRLC},
5202 {FALSE, CREATE_NEW_PROCESS_GROUP, CONSOLE_STD, FALSE, CP_GROUP_LEADER},
5203 {FALSE, 0, STARTUPINFO_STD, TRUE, 0},
5204 {FALSE, CREATE_NEW_PROCESS_GROUP, STARTUPINFO_STD, TRUE, CP_GROUP_LEADER},
5205 {FALSE, 0, STARTUPINFO_STD, FALSE, CP_ENABLED_CTRLC},
5206/* 15 */ {FALSE, CREATE_NEW_PROCESS_GROUP, STARTUPINFO_STD, FALSE, CP_GROUP_LEADER},
5207 {TRUE, CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE, CONSOLE_STD, TRUE, CP_INH_CONSOLE | CP_WITH_WINDOW | CP_GROUP_LEADER | CP_ALONE},
5208 {FALSE, CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE, CONSOLE_STD, TRUE, CP_GROUP_LEADER},
5209 {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},
5210 {FALSE, CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE, CONSOLE_STD, FALSE, CP_GROUP_LEADER | CP_ENABLED_CTRLC},
5211/* 20 */ {TRUE, CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, CONSOLE_STD, TRUE, CP_GROUP_LEADER},
5212 {FALSE, CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, CONSOLE_STD, TRUE, CP_GROUP_LEADER},
5213 {TRUE, CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, CONSOLE_STD, FALSE, CP_GROUP_LEADER},
5214 {FALSE, CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS, CONSOLE_STD, FALSE, CP_GROUP_LEADER},
5215 };
5216
5217 hstd[0] = GetStdHandle(STD_INPUT_HANDLE);
5218 hstd[1] = GetStdHandle(STD_OUTPUT_HANDLE);
5219 hstd[2] = GetStdHandle(STD_ERROR_HANDLE);
5220
5221 winetest_get_mainargs(&argv);
5222 GetTempPathA(ARRAY_SIZE(guiexec), guiexec);
5223 strcat(guiexec, "console_gui.exe");
5224 copy_change_subsystem(argv[0], guiexec, IMAGE_SUBSYSTEM_WINDOWS_GUI);
5225 GetTempPathA(ARRAY_SIZE(cuiexec), cuiexec);
5226 strcat(cuiexec, "console_cui.exe");
5227 copy_change_subsystem(argv[0], cuiexec, IMAGE_SUBSYSTEM_WINDOWS_CUI);
5228
5229 FreeConsole();
5230
5231 for (i = 0; i < ARRAY_SIZE(no_console_tests); i++)
5232 {
5233#ifdef __REACTOS__
5234 if (i == 9 && GetNTVersion() < _WIN32_WINNT_WIN7)
5235 continue;
5236#endif
5237 res = check_child_console_bits(no_console_tests[i].use_cui ? cuiexec : guiexec,
5238 no_console_tests[i].cp_flags,
5239 no_console_tests[i].inherit);
5240 ok(res == no_console_tests[i].expected, "[%d] Unexpected result %x (%lx)\n",
5241 i, res, no_console_tests[i].expected);
5242 }
5243
5244 AllocConsole();
5245
5246 for (i = 0; i < ARRAY_SIZE(with_console_tests); i++)
5247 {
5248 res = check_child_console_bits(with_console_tests[i].use_cui ? cuiexec : guiexec,
5249 with_console_tests[i].cp_flags,
5250 with_console_tests[i].inherit);
5251 ok(res == with_console_tests[i].expected ||
5252 broken(with_console_tests[i].is_broken && res == (with_console_tests[i].is_broken & 0xff)),
5253 "[%d] Unexpected result %x (%lx)\n",
5254 i, res, with_console_tests[i].expected);
5255 }
5256
5257 saved_console_flags = RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags;
5258
5259 for (i = 0; i < ARRAY_SIZE(group_flags_tests); i++)
5260 {
5261 res = SetConsoleCtrlHandler(NULL, group_flags_tests[i].noctrl_flag);
5262 ok(res, "Couldn't set ctrl handler\n");
5263 res = check_child_console_bits(group_flags_tests[i].use_cui ? cuiexec : guiexec,
5264 group_flags_tests[i].cp_flags,
5265 group_flags_tests[i].inherit);
5266 ok(res == group_flags_tests[i].expected ||
5267 /* Win7 doesn't report group id */
5268 broken(res == (group_flags_tests[i].expected & ~CP_GROUP_LEADER)),
5269 "[%d] Unexpected result %x (%lx)\n",
5270 i, res, group_flags_tests[i].expected);
5271 }
5272
5273 RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags = saved_console_flags;
5274
5275 DeleteFileA(guiexec);
5276 DeleteFileA(cuiexec);
5277
5278 SetStdHandle(STD_INPUT_HANDLE, hstd[0]);
5279 SetStdHandle(STD_OUTPUT_HANDLE, hstd[1]);
5280 SetStdHandle(STD_ERROR_HANDLE, hstd[2]);
5281}
5282
5283#define NO_EVENT 0xfe
5284
5285static HANDLE mch_child_kill_event;
5286static DWORD mch_child_event = NO_EVENT;
5287static BOOL WINAPI mch_child(DWORD event)
5288{
5289 mch_child_event = event;
5290 SetEvent(mch_child_kill_event);
5291 return TRUE;
5292}
5293
5294static void test_CtrlHandlerSubsystem(void)
5295{
5296 static char guiexec[MAX_PATH];
5297 static char cuiexec[MAX_PATH];
5298
5299 static struct
5300 {
5301 /* input */
5302 BOOL use_cui;
5303 DWORD cp_flags;
5304 enum pgid {PGID_PARENT, PGID_ZERO, PGID_CHILD} pgid_kind;
5305 /* output */
5306 unsigned child_event;
5307 }
5308 tests[] =
5309 {
5310/* 0 */ {FALSE, 0, PGID_PARENT, NO_EVENT},
5311 {FALSE, 0, PGID_ZERO, NO_EVENT},
5312 {FALSE, CREATE_NEW_PROCESS_GROUP, PGID_CHILD, NO_EVENT},
5313 {FALSE, CREATE_NEW_PROCESS_GROUP, PGID_PARENT, NO_EVENT},
5314 {FALSE, CREATE_NEW_PROCESS_GROUP, PGID_ZERO, NO_EVENT},
5315/* 5 */ {TRUE, 0, PGID_PARENT, CTRL_C_EVENT},
5316 {TRUE, 0, PGID_ZERO, CTRL_C_EVENT},
5317 {TRUE, CREATE_NEW_PROCESS_GROUP, PGID_CHILD, NO_EVENT},
5318 {TRUE, CREATE_NEW_PROCESS_GROUP, PGID_PARENT, NO_EVENT},
5319 {TRUE, CREATE_NEW_PROCESS_GROUP, PGID_ZERO, NO_EVENT},
5320/* 10 */ {TRUE, CREATE_NEW_CONSOLE, PGID_PARENT, NO_EVENT},
5321 {TRUE, CREATE_NEW_CONSOLE, PGID_ZERO, NO_EVENT},
5322 {TRUE, DETACHED_PROCESS, PGID_PARENT, NO_EVENT},
5323 {TRUE, DETACHED_PROCESS, PGID_ZERO, NO_EVENT},
5324 };
5325 SECURITY_ATTRIBUTES inheritable_attr = { sizeof(inheritable_attr), NULL, TRUE };
5326 STARTUPINFOA si = { sizeof(si) };
5327 PROCESS_INFORMATION info;
5328 char buf[MAX_PATH];
5329 DWORD exit_code;
5330 HANDLE event_child;
5331 char **argv;
5332 DWORD saved_console_flags;
5333 DWORD pgid;
5334 BOOL ret;
5335 DWORD res;
5336 int i;
5337
5338 winetest_get_mainargs(&argv);
5339 GetTempPathA(ARRAY_SIZE(guiexec), guiexec);
5340 strcat(guiexec, "console_gui.exe");
5341 copy_change_subsystem(argv[0], guiexec, IMAGE_SUBSYSTEM_WINDOWS_GUI);
5342 GetTempPathA(ARRAY_SIZE(cuiexec), cuiexec);
5343 strcat(cuiexec, "console_cui.exe");
5344 copy_change_subsystem(argv[0], cuiexec, IMAGE_SUBSYSTEM_WINDOWS_CUI);
5345
5346 event_child = CreateEventA(&inheritable_attr, FALSE, FALSE, NULL);
5347 ok(event_child != NULL, "Couldn't create event\n");
5348
5349 saved_console_flags = RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags;
5350
5351 /* protect self against ctrl-c, but don't mask it on child */
5352 ret = SetConsoleCtrlHandler(NULL, FALSE);
5353 ret = SetConsoleCtrlHandler(mydummych, TRUE);
5354 ok(ret, "Couldn't set ctrl-c handler flag\n");
5355
5356 for (i = 0; i < ARRAY_SIZE(tests); i++)
5357 {
5358 winetest_push_context("test #%u", i);
5359
5360 res = snprintf(buf, ARRAY_SIZE(buf), "\"%s\" console ctrl_handler %p", tests[i].use_cui ? cuiexec : guiexec, event_child);
5361 ok((LONG)res >= 0 && res < ARRAY_SIZE(buf), "Truncated string %s (%lu)\n", buf, res);
5362
5363 ret = CreateProcessA(NULL, buf, NULL, NULL, TRUE, tests[i].cp_flags,
5364 NULL, NULL, &si, &info);
5365 ok(ret, "CreateProcess failed: %lu %s\n", GetLastError(), tests[i].use_cui ? cuiexec : guiexec);
5366
5367 res = WaitForSingleObject(event_child, 5000);
5368 ok(res == WAIT_OBJECT_0, "Child didn't init %lu %p\n", res, event_child);
5369
5370 switch (tests[i].pgid_kind)
5371 {
5372 case PGID_PARENT:
5373 pgid = RtlGetCurrentPeb()->ProcessParameters->ProcessGroupId;
5374 break;
5375 case PGID_CHILD:
5376 ok((tests[i].cp_flags & CREATE_NEW_PROCESS_GROUP) != 0,
5377 "PGID should only be used with new process groupw\n");
5378 pgid = info.dwProcessId;
5379 break;
5380 case PGID_ZERO:
5381 pgid = 0;
5382 break;
5383 default:
5384 ok(0, "Unexpected pgid kind %u\n", tests[i].pgid_kind);
5385 pgid = 0;
5386 }
5387
5388 ret = GenerateConsoleCtrlEvent(CTRL_C_EVENT, pgid);
5389 ok(ret || broken(GetLastError() == ERROR_INVALID_PARAMETER) /* Win7 */,
5390 "GenerateConsoleCtrlEvent failed: %lu\n", GetLastError());
5391
5392 res = WaitForSingleObject(info.hProcess, 2000);
5393 ok(res == WAIT_OBJECT_0, "Expecting child to be terminated\n");
5394
5395 if (ret)
5396 {
5397 ret = GetExitCodeProcess(info.hProcess, &exit_code);
5398 ok(ret, "Couldn't get exit code\n");
5399
5400 ok(tests[i].child_event == exit_code, "Unexpected exit code %#lx, instead of %#x\n",
5401 exit_code, tests[i].child_event);
5402 }
5403
5404 CloseHandle(info.hProcess);
5405 CloseHandle(info.hThread);
5406 winetest_pop_context();
5407 }
5408
5409 /* test default handlers return code */
5410 res = snprintf(buf, ARRAY_SIZE(buf), "\"%s\" console no_ctrl_handler %p", cuiexec, event_child);
5411 ok((LONG)res >= 0 && res < ARRAY_SIZE(buf), "Truncated string %s (%lu)\n", buf, res);
5412
5413 ret = CreateProcessA(NULL, buf, NULL, NULL, TRUE, 0, NULL, NULL, &si, &info);
5414 ok(ret, "CreateProcess failed: %lu %s\n", GetLastError(), cuiexec);
5415
5416 res = WaitForSingleObject(event_child, 5000);
5417 ok(res == WAIT_OBJECT_0, "Child didn't init %lu\n", res);
5418
5419 pgid = RtlGetCurrentPeb()->ProcessParameters->ProcessGroupId;
5420 ret = GenerateConsoleCtrlEvent(CTRL_C_EVENT, pgid);
5421 if (!ret && broken(GetLastError() == ERROR_INVALID_PARAMETER) /* Win7 */)
5422 {
5423 win_skip("Skip test on Win7\n");
5424 TerminateProcess(info.hProcess, 0);
5425 }
5426 else
5427 {
5428 ok(ret, "GenerateConsoleCtrlEvent failed: %lu\n", GetLastError());
5429
5430 res = WaitForSingleObject(info.hProcess, 2000);
5431 ok(res == WAIT_OBJECT_0, "Expecting child to be terminated\n");
5432
5433 if (ret)
5434 {
5435 ret = GetExitCodeProcess(info.hProcess, &exit_code);
5436 ok(ret, "Couldn't get exit code\n");
5437
5438 ok(exit_code == STATUS_CONTROL_C_EXIT, "Unexpected exit code %#lx, instead of %#lx\n",
5439 exit_code, STATUS_CONTROL_C_EXIT);
5440 }
5441#ifdef __REACTOS__
5442 /* If the test fails to close when it should, force close.
5443 * This prevents an issue where the test hangs on ReactOS. */
5444 if (res != WAIT_OBJECT_0)
5445 TerminateProcess(info.hProcess, 0);
5446#endif
5447 }
5448
5449 CloseHandle(info.hProcess);
5450 CloseHandle(info.hThread);
5451
5452 CloseHandle(event_child);
5453
5454 RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags = saved_console_flags;
5455 ret = SetConsoleCtrlHandler(mydummych, FALSE);
5456 ok(ret, "Couldn't remove ctrl-c handler flag\n");
5457
5458 DeleteFileA(guiexec);
5459 DeleteFileA(cuiexec);
5460}
5461
5462START_TEST(console)
5463{
5464 HANDLE hConIn, hConOut, revert_output = NULL, unbound_output;
5465 BOOL ret, test_current;
5466 CONSOLE_SCREEN_BUFFER_INFO sbi;
5467 BOOL using_pseudo_console;
5468 DWORD size;
5469 char **argv;
5470 int argc;
5471
5472 init_function_pointers();
5473
5474 argc = winetest_get_mainargs(&argv);
5475
5476 if (argc > 3 && !strcmp(argv[2], "attach_console"))
5477 {
5478 DWORD parent_pid;
5479 sscanf(argv[3], "%lx", &parent_pid);
5480 test_AttachConsole_child(parent_pid);
5481 return;
5482 }
5483
5484 if (argc == 3 && !strcmp(argv[2], "alloc_console"))
5485 {
5486 test_AllocConsole_child();
5487 return;
5488 }
5489
5490 if (argc == 4 && !strcmp(argv[2], "ctrl_handler"))
5491 {
5492 HANDLE event;
5493
5494 SetConsoleCtrlHandler(mch_child, TRUE);
5495 mch_child_kill_event = CreateEventA(NULL, FALSE, FALSE, NULL);
5496 ok(mch_child_kill_event != NULL, "Couldn't create event\n");
5497 sscanf(argv[3], "%p", &event);
5498 ret = SetEvent(event);
5499 ok(ret, "SetEvent failed\n");
5500
5501 WaitForSingleObject(mch_child_kill_event, 1000); /* enough for all events to be distributed? */
5502 ExitProcess(mch_child_event);
5503 }
5504
5505 if (argc == 4 && !strcmp(argv[2], "no_ctrl_handler"))
5506 {
5507 HANDLE event;
5508
5509 SetConsoleCtrlHandler(NULL, FALSE);
5510 sscanf(argv[3], "%p", &event);
5511 ret = SetEvent(event);
5512 ok(ret, "SetEvent failed\n");
5513
5514 event = CreateEventA(NULL, FALSE, FALSE, NULL);
5515 ok(event != NULL, "Couldn't create event\n");
5516
5517 /* wait for parent to kill us */
5518 WaitForSingleObject(event, INFINITE);
5519 ok(0, "Shouldn't happen\n");
5520 ExitProcess(0xff);
5521 }
5522
5523 if (argc == 3 && !strcmp(argv[2], "check_console"))
5524 {
5525 DWORD exit_code = 0, pcslist;
5526 if (GetConsoleCP() != 0) exit_code |= CP_WITH_CONSOLE;
5527 if (RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle) exit_code |= CP_WITH_HANDLE;
5528 if (IsWindow(GetConsoleWindow())) exit_code |= CP_WITH_WINDOW;
5529 if (pGetConsoleProcessList && GetConsoleProcessList(&pcslist, 1) == 1)
5530 exit_code |= CP_ALONE;
5531 if (RtlGetCurrentPeb()->ProcessParameters->Size >=
5532 offsetof(RTL_USER_PROCESS_PARAMETERS, ProcessGroupId) +
5533 sizeof(RtlGetCurrentPeb()->ProcessParameters->ProcessGroupId) &&
5534 RtlGetCurrentPeb()->ProcessParameters->ProcessGroupId == GetCurrentProcessId())
5535 exit_code |= CP_GROUP_LEADER;
5536 if (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR)
5537 exit_code |= CP_INPUT_VALID;
5538 if (GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)) == FILE_TYPE_CHAR)
5539 exit_code |= CP_OUTPUT_VALID;
5540 if (!(RtlGetCurrentPeb()->ProcessParameters->ConsoleFlags & 1))
5541 exit_code |= CP_ENABLED_CTRLC;
5542 ExitProcess(exit_code);
5543 }
5544
5545 if (argc >= 3 && !strcmp(argv[2], "title_test"))
5546 {
5547 if (argc == 3)
5548 {
5549 test_GetConsoleOriginalTitleA();
5550 test_GetConsoleOriginalTitleW();
5551 }
5552 else
5553 test_GetConsoleOriginalTitleW_empty();
5554 return;
5555 }
5556
5557 test_current = argc >= 3 && !strcmp(argv[2], "--current");
5558 using_pseudo_console = argc >= 3 && !strcmp(argv[2], "--pseudo-console");
5559
5560 if (!test_current && !using_pseudo_console)
5561 {
5562 static const char font_name[] = "Lucida Console";
5563 HKEY console_key;
5564 char old_font[LF_FACESIZE];
5565 BOOL delete = FALSE;
5566 LONG err;
5567
5568 /* ReadConsoleOutputW doesn't retrieve characters from the output buffer
5569 * correctly for characters that don't have a glyph in the console font. So,
5570 * we first set the console font to Lucida Console (which has a wider
5571 * selection of glyphs available than the default raster fonts). We want
5572 * to be able to restore the original font afterwards, so don't change
5573 * if we can't read the original font.
5574 */
5575 err = RegOpenKeyExA(HKEY_CURRENT_USER, "Console", 0,
5576 KEY_QUERY_VALUE | KEY_SET_VALUE, &console_key);
5577 if (err == ERROR_SUCCESS)
5578 {
5579 size = sizeof(old_font);
5580 err = RegQueryValueExA(console_key, "FaceName", NULL, NULL,
5581 (LPBYTE) old_font, &size);
5582 if (err == ERROR_SUCCESS || err == ERROR_FILE_NOT_FOUND)
5583 {
5584 delete = (err == ERROR_FILE_NOT_FOUND);
5585 err = RegSetValueExA(console_key, "FaceName", 0, REG_SZ,
5586 (const BYTE *) font_name, sizeof(font_name));
5587 if (err != ERROR_SUCCESS)
5588 trace("Unable to change default console font, error %ld\n", err);
5589 }
5590 else
5591 {
5592 trace("Unable to query default console font, error %ld\n", err);
5593 RegCloseKey(console_key);
5594 console_key = NULL;
5595 }
5596 }
5597 else
5598 {
5599 trace("Unable to open HKCU\\Console, error %ld\n", err);
5600 console_key = NULL;
5601 }
5602
5603 /* Now detach and open a fresh console to play with */
5604 FreeConsole();
5605 ok(AllocConsole(), "Couldn't alloc console\n");
5606
5607 /* Restore default console font if needed */
5608 if (console_key != NULL)
5609 {
5610 if (delete)
5611 err = RegDeleteValueA(console_key, "FaceName");
5612 else
5613 err = RegSetValueExA(console_key, "FaceName", 0, REG_SZ,
5614 (const BYTE *) old_font, strlen(old_font) + 1);
5615 ok(err == ERROR_SUCCESS, "Unable to restore default console font, error %ld\n", err);
5616 }
5617 }
5618
5619 unbound_output = create_unbound_handle(TRUE, FALSE);
5620 if (!unbound_output)
5621 {
5622 win_skip("Skipping NT path tests, not supported on this Windows version\n");
5623 skip_nt = TRUE;
5624 }
5625
5626 if (test_current)
5627 {
5628 HANDLE sb;
5629 revert_output = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
5630 sb = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
5631 CONSOLE_TEXTMODE_BUFFER, NULL);
5632 ok(sb != INVALID_HANDLE_VALUE, "Could not allocate screen buffer: %lu\n", GetLastError());
5633 SetConsoleActiveScreenBuffer(sb);
5634 }
5635
5636 hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
5637 hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
5638
5639 /* now verify everything's ok */
5640 ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n");
5641 ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n");
5642
5643 if (using_pseudo_console)
5644 {
5645 test_pseudo_console_child(hConIn, hConOut);
5646 return;
5647 }
5648
5649 ret = GetConsoleScreenBufferInfo(hConOut, &sbi);
5650 ok(ret, "Getting sb info\n");
5651 if (!ret) return;
5652
5653 /* Reduce the size of the buffer to the visible area plus 3 lines to speed
5654 * up the tests.
5655 */
5656 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);
5657 sbi.dwSize.Y = size = (sbi.srWindow.Bottom + 1) + 3;
5658 ret = SetConsoleScreenBufferSize(hConOut, sbi.dwSize);
5659 ok(ret, "Setting sb info\n");
5660 ret = GetConsoleScreenBufferInfo(hConOut, &sbi);
5661 ok(ret, "Getting sb info\n");
5662 ok(sbi.dwSize.Y == size, "Unexpected buffer size: %d instead of %ld\n", sbi.dwSize.Y, size);
5663 if (!ret) return;
5664
5665 test_ReadConsole(hConIn);
5666 /* Non interactive tests */
5667 testCursor(hConOut, sbi.dwSize);
5668 /* test parameters (FIXME: test functionality) */
5669 testCursorInfo(hConOut);
5670 /* will test wrapped (on/off) & processed (on/off) strings output */
5671 testWrite(hConOut, sbi.dwSize);
5672 /* will test line scrolling at the bottom of the screen */
5673 /* testBottomScroll(); */
5674 /* will test all the scrolling operations */
5675 testScroll(hConOut, sbi.dwSize);
5676 /* will test sb creation / modification / codepage handling */
5677 if (!test_current) testScreenBuffer(hConOut);
5678 test_new_screen_buffer_properties(hConOut);
5679 test_new_screen_buffer_color_attributes(hConOut);
5680 /* Test waiting for a console handle */
5681 testWaitForConsoleInput(hConIn);
5682 test_wait(hConIn, hConOut);
5683
5684 if (!test_current)
5685 {
5686 /* clear duplicated console font table */
5687 CloseHandle(hConIn);
5688 CloseHandle(hConOut);
5689 FreeConsole();
5690 ok(AllocConsole(), "Couldn't alloc console\n");
5691 hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
5692 hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
5693 ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n");
5694 ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n");
5695 }
5696
5697 testCtrlHandler();
5698 /* still to be done: access rights & access on objects */
5699
5700 if (!pGetConsoleInputExeNameA || !pSetConsoleInputExeNameA)
5701 win_skip("GetConsoleInputExeNameA and/or SetConsoleInputExeNameA is not available\n");
5702 else
5703 test_GetSetConsoleInputExeName();
5704
5705 if (!test_current) test_GetConsoleProcessList();
5706 test_OpenConsoleW();
5707 test_CreateFileW();
5708 test_OpenCON();
5709 test_VerifyConsoleIoHandle(hConOut);
5710 test_GetSetStdHandle();
5711 test_DuplicateConsoleHandle();
5712 test_GetNumberOfConsoleInputEvents(hConIn);
5713 test_WriteConsoleInputA(hConIn);
5714 test_WriteConsoleInputW(hConIn);
5715 test_FlushConsoleInputBuffer(hConIn, hConOut);
5716 test_WriteConsoleOutputCharacterA(hConOut);
5717 test_WriteConsoleOutputCharacterW(hConOut);
5718 test_WriteConsoleOutputAttribute(hConOut);
5719 test_WriteConsoleOutput(hConOut);
5720 test_FillConsoleOutputCharacterA(hConOut);
5721 test_FillConsoleOutputCharacterW(hConOut);
5722 test_FillConsoleOutputAttribute(hConOut);
5723 test_ReadConsoleOutputCharacterA(hConOut);
5724 test_ReadConsoleOutputCharacterW(hConOut);
5725 test_ReadConsoleOutputAttribute(hConOut);
5726 test_ReadConsoleOutput(hConOut);
5727 if (!test_current)
5728 {
5729 test_GetCurrentConsoleFont(hConOut);
5730 test_GetCurrentConsoleFontEx(hConOut);
5731 test_SetCurrentConsoleFontEx(hConOut);
5732 test_GetConsoleFontSize(hConOut);
5733 test_GetLargestConsoleWindowSize(hConOut);
5734 test_GetConsoleFontInfo(hConOut);
5735 test_SetConsoleFont(hConOut);
5736 }
5737 test_GetConsoleScreenBufferInfoEx(hConOut);
5738 test_SetConsoleScreenBufferInfoEx(hConOut);
5739 test_file_info(hConIn, hConOut);
5740 test_GetConsoleOriginalTitle();
5741 test_GetConsoleTitleA();
5742 test_GetConsoleTitleW();
5743 test_console_as_root_directory();
5744 if (!test_current)
5745 {
5746 test_pseudo_console();
5747 test_AttachConsole(hConOut);
5748 test_AllocConsole();
5749 test_FreeConsole();
5750 test_condrv_server_as_root_directory();
5751 test_CreateProcessCUI();
5752 test_CtrlHandlerSubsystem();
5753 }
5754 else if (revert_output) SetConsoleActiveScreenBuffer(revert_output);
5755
5756 CloseHandle(unbound_output);
5757}