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