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