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