Reactos
at master 5757 lines 241 kB view raw
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(&region, 10, 7, 15, 11); 2717 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region); 2718 ok(ret, "WriteConsoleOutputW failed: %lu\n", GetLastError()); 2719 check_region(&region, 10, 7, 15, 11); 2720 2721 size.X = 23; 2722 size.Y = 17; 2723 coord.X = 2; 2724 coord.Y = 3; 2725 set_region(&region, 200, 7, 15, 211); 2726 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region); 2727 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError()); 2728 check_region(&region, 200, 7, 15, 211); 2729 2730 size.X = 23; 2731 size.Y = 17; 2732 coord.X = 2; 2733 coord.Y = 3; 2734 set_region(&region, 200, 7, 211, 8); 2735 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region); 2736 ok(ret, "WriteConsoleOutputW failed: %lu\n", GetLastError()); 2737 check_region(&region, 200, 7, 211, 8); 2738 2739 size.X = 23; 2740 size.Y = 17; 2741 coord.X = 2; 2742 coord.Y = 3; 2743 set_region(&region, 10, 7, 9, 11); 2744 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region); 2745 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError()); 2746 check_region(&region, 10, 7, 9, 11); 2747 2748 size.X = 23; 2749 size.Y = 17; 2750 coord.X = 2; 2751 coord.Y = 3; 2752 set_region(&region, 10, 7, 11, 6); 2753 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region); 2754 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError()); 2755 check_region(&region, 10, 7, 11, 6); 2756 2757 size.X = 2; 2758 size.Y = 17; 2759 coord.X = 2; 2760 coord.Y = 3; 2761 set_region(&region, 10, 7, 15, 11); 2762 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region); 2763 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError()); 2764 check_region(&region, 10, 7, 15, 11); 2765 2766 size.X = 23; 2767 size.Y = 3; 2768 coord.X = 2; 2769 coord.Y = 3; 2770 set_region(&region, 10, 7, 15, 11); 2771 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region); 2772 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError()); 2773 check_region(&region, 10, 7, 15, 11); 2774 2775 size.X = 6; 2776 size.Y = 17; 2777 coord.X = 2; 2778 coord.Y = 3; 2779 set_region(&region, 10, 7, 15, 11); 2780 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region); 2781 ok(ret, "WriteConsoleOutputW failed: %lu\n", GetLastError()); 2782 check_region(&region, 10, 7, 13, 11); 2783 2784 size.X = 6; 2785 size.Y = 17; 2786 coord.X = 2; 2787 coord.Y = 3; 2788 set_region(&region, 10, 7, 15, 11); 2789 ret = WriteConsoleOutputW((HANDLE)0xdeadbeef, char_info_buf, size, coord, &region); 2790 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "WriteConsoleOutputW returned: %x(%lu)\n", ret, GetLastError()); 2791 if (!skip_nt) check_region(&region, 10, 7, 13, 11); 2792 2793 size.X = 16; 2794 size.Y = 7; 2795 coord.X = 2; 2796 coord.Y = 3; 2797 set_region(&region, 10, 7, 15, 11); 2798 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region); 2799 ok(ret, "WriteConsoleOutputW failed: %lu\n", GetLastError()); 2800 check_region(&region, 10, 7, 15, 10); 2801 2802 size.X = 16; 2803 size.Y = 7; 2804 coord.X = 2; 2805 coord.Y = 3; 2806 set_region(&region, info.dwSize.X - 2, 7, info.dwSize.X + 2, 7); 2807 ret = WriteConsoleOutputW(console, char_info_buf, size, coord, &region); 2808 ok(ret, "WriteConsoleOutputW failed: %lu\n", GetLastError()); 2809 check_region(&region, 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(&region, 10, 7, 15, 11); 3265 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region); 3266 ok(ret, "ReadConsoleOutputW failed: %lu\n", GetLastError()); 3267 check_region(&region, 10, 7, 15, 11); 3268 3269 size.X = 23; 3270 size.Y = 17; 3271 coord.X = 2; 3272 coord.Y = 3; 3273 set_region(&region, 200, 7, 15, 211); 3274 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region); 3275 ok(!ret, "ReadConsoleOutputW returned: %x(%lu)\n", ret, GetLastError()); 3276 check_region(&region, 200, 7, -15, 0); 3277 3278 size.X = 23; 3279 size.Y = 17; 3280 coord.X = 2; 3281 coord.Y = 3; 3282 set_region(&region, 200, 7, 211, 8); 3283 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region); 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(&region, 200, 7, -211, -8); 3287 3288 size.X = 23; 3289 size.Y = 17; 3290 coord.X = 2; 3291 coord.Y = 3; 3292 set_region(&region, 10, 7, 9, 11); 3293 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region); 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(&region, 10, 7, 9, -11); 3297 3298 size.X = 23; 3299 size.Y = 17; 3300 coord.X = 2; 3301 coord.Y = 3; 3302 set_region(&region, 10, 7, 11, 6); 3303 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region); 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(&region, 10, 7, -11, 6); 3307 3308 size.X = 2; 3309 size.Y = 17; 3310 coord.X = 2; 3311 coord.Y = 3; 3312 set_region(&region, 10, 7, 15, 11); 3313 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region); 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(&region, 10, 7, -15, -11); 3317 3318 size.X = 23; 3319 size.Y = 3; 3320 coord.X = 2; 3321 coord.Y = 3; 3322 set_region(&region, 10, 7, 15, 11); 3323 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region); 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(&region, 10, 7, -15, 6); 3327 3328 size.X = 6; 3329 size.Y = 17; 3330 coord.X = 2; 3331 coord.Y = 3; 3332 set_region(&region, 10, 7, 15, 11); 3333 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region); 3334 ok(ret, "ReadConsoleOutputW failed: %lu\n", GetLastError()); 3335 check_region(&region, 10, 7, 13, 11); 3336 3337 size.X = 6; 3338 size.Y = 17; 3339 coord.X = 2; 3340 coord.Y = 3; 3341 set_region(&region, 10, 7, 15, 11); 3342 ret = ReadConsoleOutputW((HANDLE)0xdeadbeef, char_info_buf, size, coord, &region); 3343 ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "ReadConsoleOutputW returned: %x(%lu)\n", ret, GetLastError()); 3344 if (!skip_nt) check_region(&region, 10, 7, 13, 11); 3345 3346 size.X = 16; 3347 size.Y = 7; 3348 coord.X = 2; 3349 coord.Y = 3; 3350 set_region(&region, 10, 7, 15, 11); 3351 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region); 3352 ok(ret, "ReadConsoleOutputW failed: %lu\n", GetLastError()); 3353 check_region(&region, 10, 7, 15, 10); 3354 3355 size.X = 16; 3356 size.Y = 7; 3357 coord.X = 2; 3358 coord.Y = 3; 3359 set_region(&region, info.dwSize.X - 2, 7, info.dwSize.X + 2, 7); 3360 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region); 3361 ok(ret || GetLastError() == ERROR_INVALID_PARAMETER, "ReadConsoleOutputW failed: %lu\n", GetLastError()); 3362 if (ret) check_region(&region, 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(&region, 2, 3, 5, 3); 3376 ret = ReadConsoleOutputW(console, char_info_buf, size, coord, &region); 3377 ok(ret, "ReadConsoleOutputW failed: %lu\n", GetLastError()); 3378 check_region(&region, 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}