[KERNEL32]
[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
31 /* DEFAULT_ATTRIB is used for all initial filling of the console.
32 * all modifications are made with TEST_ATTRIB so that we could check
33 * what has to be modified or not
34 */
35 #define TEST_ATTRIB (BACKGROUND_BLUE | FOREGROUND_GREEN)
36 #define DEFAULT_ATTRIB (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED)
37 /* when filling the screen with non-blank chars, this macro defines
38 * what character should be at position 'c'
39 */
40 #define CONTENT(c) ('A' + (((c).Y * 17 + (c).X) % 23))
41
42 #define okCURSOR(hCon, c) do { \
43 CONSOLE_SCREEN_BUFFER_INFO __sbi; \
44 BOOL expect = GetConsoleScreenBufferInfo((hCon), &__sbi) && \
45 __sbi.dwCursorPosition.X == (c).X && __sbi.dwCursorPosition.Y == (c).Y; \
46 ok(expect, "Expected cursor at (%d,%d), got (%d,%d)\n", \
47 (c).X, (c).Y, __sbi.dwCursorPosition.X, __sbi.dwCursorPosition.Y); \
48 } while (0)
49
50 #define okCHAR(hCon, c, ch, attr) do { \
51 char __ch; WORD __attr; DWORD __len; BOOL expect; \
52 expect = ReadConsoleOutputCharacter((hCon), &__ch, 1, (c), &__len) == 1 && __len == 1 && __ch == (ch); \
53 ok(expect, "At (%d,%d): expecting char '%c'/%02x got '%c'/%02x\n", (c).X, (c).Y, (ch), (ch), __ch, __ch); \
54 expect = ReadConsoleOutputAttribute((hCon), &__attr, 1, (c), &__len) == 1 && __len == 1 && __attr == (attr); \
55 ok(expect, "At (%d,%d): expecting attr %04x got %04x\n", (c).X, (c).Y, (attr), __attr); \
56 } while (0)
57
58 static void init_function_pointers(void)
59 {
60 HMODULE hKernel32;
61
62 #define KERNEL32_GET_PROC(func) \
63 p##func = (void *)GetProcAddress(hKernel32, #func); \
64 if(!p##func) trace("GetProcAddress(hKernel32, '%s') failed\n", #func);
65
66 hKernel32 = GetModuleHandleA("kernel32.dll");
67 KERNEL32_GET_PROC(GetConsoleInputExeNameA);
68 KERNEL32_GET_PROC(GetConsoleProcessList);
69 KERNEL32_GET_PROC(OpenConsoleW);
70 KERNEL32_GET_PROC(SetConsoleInputExeNameA);
71
72 #undef KERNEL32_GET_PROC
73 }
74
75 /* FIXME: this could be optimized on a speed point of view */
76 static void resetContent(HANDLE hCon, COORD sbSize, BOOL content)
77 {
78 COORD c;
79 WORD attr = DEFAULT_ATTRIB;
80 char ch;
81 DWORD len;
82
83 for (c.X = 0; c.X < sbSize.X; c.X++)
84 {
85 for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
86 {
87 ch = (content) ? CONTENT(c) : ' ';
88 WriteConsoleOutputAttribute(hCon, &attr, 1, c, &len);
89 WriteConsoleOutputCharacterA(hCon, &ch, 1, c, &len);
90 }
91 }
92 }
93
94 static void testCursor(HANDLE hCon, COORD sbSize)
95 {
96 COORD c;
97
98 c.X = c.Y = 0;
99 ok(SetConsoleCursorPosition(0, c) == 0, "No handle\n");
100 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n",
101 ERROR_INVALID_HANDLE, GetLastError());
102
103 c.X = c.Y = 0;
104 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
105 okCURSOR(hCon, c);
106
107 c.X = sbSize.X - 1;
108 c.Y = sbSize.Y - 1;
109 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in lower-right\n");
110 okCURSOR(hCon, c);
111
112 c.X = sbSize.X;
113 c.Y = sbSize.Y - 1;
114 ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
115 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n",
116 ERROR_INVALID_PARAMETER, GetLastError());
117
118 c.X = sbSize.X - 1;
119 c.Y = sbSize.Y;
120 ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
121 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n",
122 ERROR_INVALID_PARAMETER, GetLastError());
123
124 c.X = -1;
125 c.Y = 0;
126 ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
127 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n",
128 ERROR_INVALID_PARAMETER, GetLastError());
129
130 c.X = 0;
131 c.Y = -1;
132 ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
133 ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n",
134 ERROR_INVALID_PARAMETER, GetLastError());
135 }
136
137 static void testCursorInfo(HANDLE hCon)
138 {
139 BOOL ret;
140 CONSOLE_CURSOR_INFO info;
141
142 SetLastError(0xdeadbeef);
143 ret = GetConsoleCursorInfo(NULL, NULL);
144 ok(!ret, "Expected failure\n");
145 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n",
146 ERROR_INVALID_HANDLE, GetLastError());
147
148 SetLastError(0xdeadbeef);
149 info.dwSize = -1;
150 ret = GetConsoleCursorInfo(NULL, &info);
151 ok(!ret, "Expected failure\n");
152 ok(info.dwSize == -1, "Expected no change for dwSize\n");
153 ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n",
154 ERROR_INVALID_HANDLE, GetLastError());
155
156 /* Test the correct call first to distinguish between win9x and the rest */
157 SetLastError(0xdeadbeef);
158 ret = GetConsoleCursorInfo(hCon, &info);
159 ok(ret, "Expected success\n");
160 ok(info.dwSize == 25 ||
161 info.dwSize == 12 /* win9x */,
162 "Expected 12 or 25, got %d\n", info.dwSize);
163 ok(info.bVisible, "Expected the cursor to be visible\n");
164 ok(GetLastError() == 0xdeadbeef, "GetLastError: expecting %u got %u\n",
165 0xdeadbeef, GetLastError());
166
167 /* Don't test NULL CONSOLE_CURSOR_INFO, it crashes on win9x and win7 */
168 }
169
170 static void testEmptyWrite(HANDLE hCon)
171 {
172 COORD c;
173 DWORD len;
174 const char* mytest = "";
175
176 c.X = c.Y = 0;
177 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
178
179 len = -1;
180 ok(WriteConsole(hCon, NULL, 0, &len, NULL) != 0 && len == 0, "WriteConsole\n");
181 okCURSOR(hCon, c);
182
183 /* Passing a NULL lpBuffer with sufficiently large non-zero length succeeds
184 * on native Windows and result in memory-like contents being written to
185 * the console. Calling WriteConsoleW like this will crash on Wine. */
186 if (0)
187 {
188 len = -1;
189 ok(!WriteConsole(hCon, NULL, 16, &len, NULL) && len == -1, "WriteConsole\n");
190 okCURSOR(hCon, c);
191
192 /* Cursor advances for this call. */
193 len = -1;
194 ok(WriteConsole(hCon, NULL, 128, &len, NULL) != 0 && len == 128, "WriteConsole\n");
195 }
196
197 len = -1;
198 ok(WriteConsole(hCon, mytest, 0, &len, NULL) != 0 && len == 0, "WriteConsole\n");
199 okCURSOR(hCon, c);
200
201 /* WriteConsole does not halt on a null terminator and is happy to write
202 * memory contents beyond the actual size of the buffer. */
203 len = -1;
204 ok(WriteConsole(hCon, mytest, 16, &len, NULL) != 0 && len == 16, "WriteConsole\n");
205 c.X += 16;
206 okCURSOR(hCon, c);
207 }
208
209 static void testWriteSimple(HANDLE hCon)
210 {
211 COORD c;
212 DWORD len;
213 const char* mytest = "abcdefg";
214 const int mylen = strlen(mytest);
215
216 /* single line write */
217 c.X = c.Y = 0;
218 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
219
220 ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
221 c.Y = 0;
222 for (c.X = 0; c.X < mylen; c.X++)
223 {
224 okCHAR(hCon, c, mytest[c.X], TEST_ATTRIB);
225 }
226
227 okCURSOR(hCon, c);
228 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
229 }
230
231 static void testWriteNotWrappedNotProcessed(HANDLE hCon, COORD sbSize)
232 {
233 COORD c;
234 DWORD len, mode;
235 const char* mytest = "123";
236 const int mylen = strlen(mytest);
237 int ret;
238 int p;
239
240 ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode & ~(ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT)),
241 "clearing wrap at EOL & processed output\n");
242
243 /* write line, wrapping disabled, buffer exceeds sb width */
244 c.X = sbSize.X - 3; c.Y = 0;
245 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
246
247 ret = WriteConsole(hCon, mytest, mylen, &len, NULL);
248 ok(ret != 0 && len == mylen, "Couldn't write, ret = %d, len = %d\n", ret, len);
249 c.Y = 0;
250 for (p = mylen - 3; p < mylen; p++)
251 {
252 c.X = sbSize.X - 3 + p % 3;
253 okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
254 }
255
256 c.X = 0; c.Y = 1;
257 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
258
259 p = sbSize.X - 3 + mylen % 3;
260 c.X = p; c.Y = 0;
261
262 /* write line, wrapping disabled, strings end on end of line */
263 c.X = sbSize.X - mylen; c.Y = 0;
264 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
265
266 ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
267 }
268
269 static void testWriteNotWrappedProcessed(HANDLE hCon, COORD sbSize)
270 {
271 COORD c;
272 DWORD len, mode;
273 const char* mytest = "abcd\nf\tg";
274 const int mylen = strlen(mytest);
275 const int mylen2 = strchr(mytest, '\n') - mytest;
276 int p;
277 WORD attr;
278
279 ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, (mode | ENABLE_PROCESSED_OUTPUT) & ~ENABLE_WRAP_AT_EOL_OUTPUT),
280 "clearing wrap at EOL & setting processed output\n");
281
282 /* write line, wrapping disabled, buffer exceeds sb width */
283 c.X = sbSize.X - 5; c.Y = 0;
284 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-5\n");
285
286 ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
287 c.Y = 0;
288 for (c.X = sbSize.X - 5; c.X < sbSize.X - 1; c.X++)
289 {
290 okCHAR(hCon, c, mytest[c.X - sbSize.X + 5], TEST_ATTRIB);
291 }
292
293 ReadConsoleOutputAttribute(hCon, &attr, 1, c, &len);
294 /* Win9x and WinMe change the attribs for '\n' up to 'f' */
295 if (attr == TEST_ATTRIB)
296 {
297 win_skip("Win9x/WinMe don't respect ~ENABLE_WRAP_AT_EOL_OUTPUT\n");
298 return;
299 }
300
301 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
302
303 c.X = 0; c.Y++;
304 okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
305 for (c.X = 1; c.X < 8; c.X++)
306 okCHAR(hCon, c, ' ', TEST_ATTRIB);
307 okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
308 c.X++;
309 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
310
311 okCURSOR(hCon, c);
312
313 /* write line, wrapping disabled, strings end on end of line */
314 c.X = sbSize.X - 4; c.Y = 0;
315 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-4\n");
316
317 ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
318 c.Y = 0;
319 for (c.X = sbSize.X - 4; c.X < sbSize.X; c.X++)
320 {
321 okCHAR(hCon, c, mytest[c.X - sbSize.X + 4], TEST_ATTRIB);
322 }
323 c.X = 0; c.Y++;
324 okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
325 for (c.X = 1; c.X < 8; c.X++)
326 okCHAR(hCon, c, ' ', TEST_ATTRIB);
327 okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
328 c.X++;
329 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
330
331 okCURSOR(hCon, c);
332
333 /* write line, wrapping disabled, strings end after end of line */
334 c.X = sbSize.X - 3; c.Y = 0;
335 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-4\n");
336
337 ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
338 c.Y = 0;
339 for (p = mylen2 - 3; p < mylen2; p++)
340 {
341 c.X = sbSize.X - 3 + p % 3;
342 okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
343 }
344 c.X = 0; c.Y = 1;
345 okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
346 for (c.X = 1; c.X < 8; c.X++)
347 okCHAR(hCon, c, ' ', TEST_ATTRIB);
348 okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
349 c.X++;
350 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
351
352 okCURSOR(hCon, c);
353 }
354
355 static void testWriteWrappedNotProcessed(HANDLE hCon, COORD sbSize)
356 {
357 COORD c;
358 DWORD len, mode;
359 const char* mytest = "abcd\nf\tg";
360 const int mylen = strlen(mytest);
361 int p;
362
363 ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon,(mode | ENABLE_WRAP_AT_EOL_OUTPUT) & ~(ENABLE_PROCESSED_OUTPUT)),
364 "setting wrap at EOL & clearing processed output\n");
365
366 /* write line, wrapping enabled, buffer doesn't exceed sb width */
367 c.X = sbSize.X - 9; c.Y = 0;
368 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-9\n");
369
370 ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
371 c.Y = 0;
372 for (p = 0; p < mylen; p++)
373 {
374 c.X = sbSize.X - 9 + p;
375 okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
376 }
377 c.X = sbSize.X - 9 + mylen;
378 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
379 c.X = 0; c.Y = 1;
380 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
381
382 /* write line, wrapping enabled, buffer does exceed sb width */
383 c.X = sbSize.X - 3; c.Y = 0;
384 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
385
386 c.Y = 1;
387 c.X = mylen - 3;
388 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
389 }
390
391 static void testWriteWrappedProcessed(HANDLE hCon, COORD sbSize)
392 {
393 COORD c;
394 DWORD len, mode;
395 const char* mytest = "abcd\nf\tg";
396 const int mylen = strlen(mytest);
397 int p;
398 WORD attr;
399
400 ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode | (ENABLE_WRAP_AT_EOL_OUTPUT|ENABLE_PROCESSED_OUTPUT)),
401 "setting wrap at EOL & processed output\n");
402
403 /* write line, wrapping enabled, buffer doesn't exceed sb width */
404 c.X = sbSize.X - 9; c.Y = 0;
405 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-9\n");
406
407 ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
408 for (p = 0; p < 4; p++)
409 {
410 c.X = sbSize.X - 9 + p;
411 okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
412 }
413 c.X = sbSize.X - 9 + p;
414 ReadConsoleOutputAttribute(hCon, &attr, 1, c, &len);
415 if (attr == TEST_ATTRIB)
416 win_skip("Win9x/WinMe changes attribs for '\\n' up to 'f'\n");
417 else
418 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
419 c.X = 0; c.Y++;
420 okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
421 for (c.X = 1; c.X < 8; c.X++)
422 okCHAR(hCon, c, ' ', TEST_ATTRIB);
423 okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
424 c.X++;
425 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
426 okCURSOR(hCon, c);
427
428 /* write line, wrapping enabled, buffer does exceed sb width */
429 c.X = sbSize.X - 3; c.Y = 2;
430 ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
431
432 ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
433 for (p = 0; p < 3; p++)
434 {
435 c.X = sbSize.X - 3 + p;
436 okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
437 }
438 c.X = 0; c.Y++;
439 okCHAR(hCon, c, mytest[3], TEST_ATTRIB);
440 c.X++;
441 ReadConsoleOutputAttribute(hCon, &attr, 1, c, &len);
442 if (attr == TEST_ATTRIB)
443 win_skip("Win9x/WinMe changes attribs for '\\n' up to 'f'\n");
444 else
445 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
446
447 c.X = 0; c.Y++;
448 okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
449 for (c.X = 1; c.X < 8; c.X++)
450 okCHAR(hCon, c, ' ', TEST_ATTRIB);
451 okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
452 c.X++;
453 okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
454 okCURSOR(hCon, c);
455 }
456
457 static void testWrite(HANDLE hCon, COORD sbSize)
458 {
459 /* FIXME: should in fact insure that the sb is at least 10 character wide */
460 ok(SetConsoleTextAttribute(hCon, TEST_ATTRIB), "Setting default text color\n");
461 resetContent(hCon, sbSize, FALSE);
462 testEmptyWrite(hCon);
463 resetContent(hCon, sbSize, FALSE);
464 testWriteSimple(hCon);
465 resetContent(hCon, sbSize, FALSE);
466 testWriteNotWrappedNotProcessed(hCon, sbSize);
467 resetContent(hCon, sbSize, FALSE);
468 testWriteNotWrappedProcessed(hCon, sbSize);
469 resetContent(hCon, sbSize, FALSE);
470 testWriteWrappedNotProcessed(hCon, sbSize);
471 resetContent(hCon, sbSize, FALSE);
472 testWriteWrappedProcessed(hCon, sbSize);
473 }
474
475 static void testScroll(HANDLE hCon, COORD sbSize)
476 {
477 SMALL_RECT scroll, clip;
478 COORD dst, c, tc;
479 CHAR_INFO ci;
480 BOOL ret;
481
482 #define W 11
483 #define H 7
484
485 #define IN_SRECT(r,c) ((r).Left <= (c).X && (c).X <= (r).Right && (r).Top <= (c).Y && (c).Y <= (r).Bottom)
486 #define IN_SRECT2(r,d,c) ((d).X <= (c).X && (c).X <= (d).X + (r).Right - (r).Left && (d).Y <= (c).Y && (c).Y <= (d).Y + (r).Bottom - (r).Top)
487
488 /* no clipping, src & dst rect don't overlap */
489 resetContent(hCon, sbSize, TRUE);
490
491 scroll.Left = 0;
492 scroll.Right = W - 1;
493 scroll.Top = 0;
494 scroll.Bottom = H - 1;
495 dst.X = W + 3;
496 dst.Y = H + 3;
497 ci.Char.UnicodeChar = '#';
498 ci.Attributes = TEST_ATTRIB;
499
500 clip.Left = 0;
501 clip.Right = sbSize.X - 1;
502 clip.Top = 0;
503 clip.Bottom = sbSize.Y - 1;
504
505 ok(ScrollConsoleScreenBuffer(hCon, &scroll, NULL, dst, &ci), "Scrolling SB\n");
506
507 for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
508 {
509 for (c.X = 0; c.X < sbSize.X; c.X++)
510 {
511 if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
512 {
513 tc.X = c.X - dst.X;
514 tc.Y = c.Y - dst.Y;
515 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
516 }
517 else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
518 okCHAR(hCon, c, '#', TEST_ATTRIB);
519 else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
520 }
521 }
522
523 /* no clipping, src & dst rect do overlap */
524 resetContent(hCon, sbSize, TRUE);
525
526 scroll.Left = 0;
527 scroll.Right = W - 1;
528 scroll.Top = 0;
529 scroll.Bottom = H - 1;
530 dst.X = W /2;
531 dst.Y = H / 2;
532 ci.Char.UnicodeChar = '#';
533 ci.Attributes = TEST_ATTRIB;
534
535 clip.Left = 0;
536 clip.Right = sbSize.X - 1;
537 clip.Top = 0;
538 clip.Bottom = sbSize.Y - 1;
539
540 ok(ScrollConsoleScreenBuffer(hCon, &scroll, NULL, dst, &ci), "Scrolling SB\n");
541
542 for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
543 {
544 for (c.X = 0; c.X < sbSize.X; c.X++)
545 {
546 if (dst.X <= c.X && c.X < dst.X + W && dst.Y <= c.Y && c.Y < dst.Y + H)
547 {
548 tc.X = c.X - dst.X;
549 tc.Y = c.Y - dst.Y;
550 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
551 }
552 else if (c.X < W && c.Y < H) okCHAR(hCon, c, '#', TEST_ATTRIB);
553 else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
554 }
555 }
556
557 /* clipping, src & dst rect don't overlap */
558 resetContent(hCon, sbSize, TRUE);
559
560 scroll.Left = 0;
561 scroll.Right = W - 1;
562 scroll.Top = 0;
563 scroll.Bottom = H - 1;
564 dst.X = W + 3;
565 dst.Y = H + 3;
566 ci.Char.UnicodeChar = '#';
567 ci.Attributes = TEST_ATTRIB;
568
569 clip.Left = W / 2;
570 clip.Right = min(W + W / 2, sbSize.X - 1);
571 clip.Top = H / 2;
572 clip.Bottom = min(H + H / 2, sbSize.Y - 1);
573
574 SetLastError(0xdeadbeef);
575 ret = ScrollConsoleScreenBuffer(hCon, &scroll, &clip, dst, &ci);
576 if (ret)
577 {
578 for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
579 {
580 for (c.X = 0; c.X < sbSize.X; c.X++)
581 {
582 if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
583 {
584 tc.X = c.X - dst.X;
585 tc.Y = c.Y - dst.Y;
586 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
587 }
588 else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
589 okCHAR(hCon, c, '#', TEST_ATTRIB);
590 else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
591 }
592 }
593 }
594 else
595 {
596 /* Win9x will fail, Only accept ERROR_NOT_ENOUGH_MEMORY */
597 ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY,
598 "Expected ERROR_NOT_ENOUGH_MEMORY, got %u\n", GetLastError());
599 }
600
601 /* clipping, src & dst rect do overlap */
602 resetContent(hCon, sbSize, TRUE);
603
604 scroll.Left = 0;
605 scroll.Right = W - 1;
606 scroll.Top = 0;
607 scroll.Bottom = H - 1;
608 dst.X = W / 2 - 3;
609 dst.Y = H / 2 - 3;
610 ci.Char.UnicodeChar = '#';
611 ci.Attributes = TEST_ATTRIB;
612
613 clip.Left = W / 2;
614 clip.Right = min(W + W / 2, sbSize.X - 1);
615 clip.Top = H / 2;
616 clip.Bottom = min(H + H / 2, sbSize.Y - 1);
617
618 ok(ScrollConsoleScreenBuffer(hCon, &scroll, &clip, dst, &ci), "Scrolling SB\n");
619
620 for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
621 {
622 for (c.X = 0; c.X < sbSize.X; c.X++)
623 {
624 if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
625 {
626 tc.X = c.X - dst.X;
627 tc.Y = c.Y - dst.Y;
628 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
629 }
630 else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
631 okCHAR(hCon, c, '#', TEST_ATTRIB);
632 else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
633 }
634 }
635 }
636
637 static int mch_count;
638 /* we need the event as Wine console event generation isn't synchronous
639 * (ie GenerateConsoleCtrlEvent returns before all ctrl-handlers in all
640 * processes have been called).
641 */
642 static HANDLE mch_event;
643 static BOOL WINAPI mch(DWORD event)
644 {
645 mch_count++;
646 SetEvent(mch_event);
647 return TRUE;
648 }
649
650 static void testCtrlHandler(void)
651 {
652 ok(!SetConsoleCtrlHandler(mch, FALSE), "Shouldn't succeed\n");
653 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %u\n", GetLastError());
654 ok(SetConsoleCtrlHandler(mch, TRUE), "Couldn't set handler\n");
655 /* wine requires the event for the test, as we cannot insure, so far, that event
656 * are processed synchronously in GenerateConsoleCtrlEvent()
657 */
658 mch_event = CreateEventA(NULL, TRUE, FALSE, NULL);
659 mch_count = 0;
660 ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n");
661 /* FIXME: it isn't synchronous on wine but it can still happen before we test */
662 if (0) ok(mch_count == 1, "Event isn't synchronous\n");
663 ok(WaitForSingleObject(mch_event, 3000) == WAIT_OBJECT_0, "event sending didn't work\n");
664 CloseHandle(mch_event);
665
666 /* Turning off ctrl-c handling doesn't work on win9x such way ... */
667 ok(SetConsoleCtrlHandler(NULL, TRUE), "Couldn't turn off ctrl-c handling\n");
668 mch_event = CreateEventA(NULL, TRUE, FALSE, NULL);
669 mch_count = 0;
670 if(!(GetVersion() & 0x80000000))
671 /* ... and next line leads to an unhandled exception on 9x. Avoid it on 9x. */
672 ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n");
673 ok(WaitForSingleObject(mch_event, 3000) == WAIT_TIMEOUT && mch_count == 0, "Event shouldn't have been sent\n");
674 CloseHandle(mch_event);
675 ok(SetConsoleCtrlHandler(mch, FALSE), "Couldn't remove handler\n");
676 ok(!SetConsoleCtrlHandler(mch, FALSE), "Shouldn't succeed\n");
677 ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %u\n", GetLastError());
678 }
679
680 /*
681 * Test console screen buffer:
682 * 1) Try to set invalid handle.
683 * 2) Try to set non-console handles.
684 * 3) Use CONOUT$ file as active SB.
685 * 4) Test cursor.
686 * 5) Test output codepage to show it is not a property of SB.
687 * 6) Test switching to old SB if we close all handles to current SB - works
688 * in Windows, TODO in wine.
689 *
690 * What is not tested but should be:
691 * 1) ScreenBufferInfo
692 */
693 static void testScreenBuffer(HANDLE hConOut)
694 {
695 HANDLE hConOutRW, hConOutRO, hConOutWT;
696 HANDLE hFileOutRW, hFileOutRO, hFileOutWT;
697 HANDLE hConOutNew;
698 char test_str1[] = "Test for SB1";
699 char test_str2[] = "Test for SB2";
700 char test_cp866[] = {0xe2, 0xa5, 0xe1, 0xe2, 0};
701 char test_cp1251[] = {0xf2, 0xe5, 0xf1, 0xf2, 0};
702 WCHAR test_unicode[] = {0x0442, 0x0435, 0x0441, 0x0442, 0};
703 WCHAR str_wbuf[20];
704 char str_buf[20];
705 DWORD len;
706 COORD c;
707 BOOL ret;
708 DWORD oldcp;
709
710 if (!IsValidCodePage(866))
711 {
712 skip("Codepage 866 not available\n");
713 return;
714 }
715
716 /* In the beginning set output codepage to 866 */
717 oldcp = GetConsoleOutputCP();
718 SetLastError(0xdeadbeef);
719 ret = SetConsoleOutputCP(866);
720 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
721 {
722 win_skip("SetConsoleOutputCP is not implemented\n");
723 return;
724 }
725 ok(ret, "Cannot set output codepage to 866\n");
726
727 hConOutRW = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
728 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
729 CONSOLE_TEXTMODE_BUFFER, NULL);
730 ok(hConOutRW != INVALID_HANDLE_VALUE,
731 "Cannot create a new screen buffer for ReadWrite\n");
732 hConOutRO = CreateConsoleScreenBuffer(GENERIC_READ,
733 FILE_SHARE_READ, NULL,
734 CONSOLE_TEXTMODE_BUFFER, NULL);
735 ok(hConOutRO != INVALID_HANDLE_VALUE,
736 "Cannot create a new screen buffer for ReadOnly\n");
737 hConOutWT = CreateConsoleScreenBuffer(GENERIC_WRITE,
738 FILE_SHARE_WRITE, NULL,
739 CONSOLE_TEXTMODE_BUFFER, NULL);
740 ok(hConOutWT != INVALID_HANDLE_VALUE,
741 "Cannot create a new screen buffer for WriteOnly\n");
742
743 hFileOutRW = CreateFileA("NUL", GENERIC_READ | GENERIC_WRITE,
744 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
745 OPEN_EXISTING, 0, NULL);
746 ok(hFileOutRW != INVALID_HANDLE_VALUE, "Cannot open NUL for ReadWrite\n");
747 hFileOutRO = CreateFileA("NUL", GENERIC_READ, FILE_SHARE_READ,
748 NULL, OPEN_EXISTING, 0, NULL);
749 ok(hFileOutRO != INVALID_HANDLE_VALUE, "Cannot open NUL for ReadOnly\n");
750 hFileOutWT = CreateFileA("NUL", GENERIC_WRITE, FILE_SHARE_WRITE,
751 NULL, OPEN_EXISTING, 0, NULL);
752 ok(hFileOutWT != INVALID_HANDLE_VALUE, "Cannot open NUL for WriteOnly\n");
753
754 /* Trying to set invalid handle */
755 SetLastError(0);
756 ok(!SetConsoleActiveScreenBuffer(INVALID_HANDLE_VALUE),
757 "Shouldn't succeed\n");
758 ok(GetLastError() == ERROR_INVALID_HANDLE,
759 "GetLastError: expecting %u got %u\n",
760 ERROR_INVALID_HANDLE, GetLastError());
761
762 /* Trying to set non-console handles */
763 SetLastError(0);
764 ok(!SetConsoleActiveScreenBuffer(hFileOutRW), "Shouldn't succeed\n");
765 ok(GetLastError() == ERROR_INVALID_HANDLE,
766 "GetLastError: expecting %u got %u\n",
767 ERROR_INVALID_HANDLE, GetLastError());
768
769 SetLastError(0);
770 ok(!SetConsoleActiveScreenBuffer(hFileOutRO), "Shouldn't succeed\n");
771 ok(GetLastError() == ERROR_INVALID_HANDLE,
772 "GetLastError: expecting %u got %u\n",
773 ERROR_INVALID_HANDLE, GetLastError());
774
775 SetLastError(0);
776 ok(!SetConsoleActiveScreenBuffer(hFileOutWT), "Shouldn't succeed\n");
777 ok(GetLastError() == ERROR_INVALID_HANDLE,
778 "GetLastError: expecting %u got %u\n",
779 ERROR_INVALID_HANDLE, GetLastError());
780
781 CloseHandle(hFileOutRW);
782 CloseHandle(hFileOutRO);
783 CloseHandle(hFileOutWT);
784
785 /* Trying to set SB handles with various access modes */
786 SetLastError(0);
787 ok(!SetConsoleActiveScreenBuffer(hConOutRO), "Shouldn't succeed\n");
788 ok(GetLastError() == ERROR_INVALID_HANDLE,
789 "GetLastError: expecting %u got %u\n",
790 ERROR_INVALID_HANDLE, GetLastError());
791
792 ok(SetConsoleActiveScreenBuffer(hConOutWT), "Couldn't set new WriteOnly SB\n");
793
794 ok(SetConsoleActiveScreenBuffer(hConOutRW), "Couldn't set new ReadWrite SB\n");
795
796 CloseHandle(hConOutWT);
797 CloseHandle(hConOutRO);
798
799 /* Now we have two ReadWrite SB, active must be hConOutRW */
800 /* Open current SB via CONOUT$ */
801 hConOutNew = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0,
802 NULL, OPEN_EXISTING, 0, 0);
803 ok(hConOutNew != INVALID_HANDLE_VALUE, "CONOUT$ is not opened\n");
804
805
806 /* test cursor */
807 c.X = c.Y = 10;
808 SetConsoleCursorPosition(hConOut, c);
809 c.X = c.Y = 5;
810 SetConsoleCursorPosition(hConOutRW, c);
811 okCURSOR(hConOutNew, c);
812 c.X = c.Y = 10;
813 okCURSOR(hConOut, c);
814
815
816 c.X = c.Y = 0;
817
818 /* Write using hConOutNew... */
819 SetConsoleCursorPosition(hConOutNew, c);
820 ret = WriteConsoleA(hConOutNew, test_str2, lstrlenA(test_str2), &len, NULL);
821 ok (ret && len == lstrlenA(test_str2), "WriteConsoleA failed\n");
822 /* ... and read it back via hConOutRW */
823 ret = ReadConsoleOutputCharacterA(hConOutRW, str_buf, lstrlenA(test_str2), c, &len);
824 ok(ret && len == lstrlenA(test_str2), "ReadConsoleOutputCharacterA failed\n");
825 str_buf[lstrlenA(test_str2)] = 0;
826 ok(!lstrcmpA(str_buf, test_str2), "got '%s' expected '%s'\n", str_buf, test_str2);
827
828
829 /* Now test output codepage handling. Current is 866 as we set earlier. */
830 SetConsoleCursorPosition(hConOutRW, c);
831 ret = WriteConsoleA(hConOutRW, test_cp866, lstrlenA(test_cp866), &len, NULL);
832 ok(ret && len == lstrlenA(test_cp866), "WriteConsoleA failed\n");
833 ret = ReadConsoleOutputCharacterW(hConOutRW, str_wbuf, lstrlenA(test_cp866), c, &len);
834 ok(ret && len == lstrlenA(test_cp866), "ReadConsoleOutputCharacterW failed\n");
835 str_wbuf[lstrlenA(test_cp866)] = 0;
836 ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n");
837
838 /*
839 * cp866 is OK, let's switch to cp1251.
840 * We expect that this codepage will be used in every SB - active and not.
841 */
842 ok(SetConsoleOutputCP(1251), "Cannot set output cp to 1251\n");
843 SetConsoleCursorPosition(hConOutRW, c);
844 ret = WriteConsoleA(hConOutRW, test_cp1251, lstrlenA(test_cp1251), &len, NULL);
845 ok(ret && len == lstrlenA(test_cp1251), "WriteConsoleA failed\n");
846 ret = ReadConsoleOutputCharacterW(hConOutRW, str_wbuf, lstrlenA(test_cp1251), c, &len);
847 ok(ret && len == lstrlenA(test_cp1251), "ReadConsoleOutputCharacterW failed\n");
848 str_wbuf[lstrlenA(test_cp1251)] = 0;
849 ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n");
850
851 /* Check what has happened to hConOut. */
852 SetConsoleCursorPosition(hConOut, c);
853 ret = WriteConsoleA(hConOut, test_cp1251, lstrlenA(test_cp1251), &len, NULL);
854 ok(ret && len == lstrlenA(test_cp1251), "WriteConsoleA failed\n");
855 ret = ReadConsoleOutputCharacterW(hConOut, str_wbuf, lstrlenA(test_cp1251), c, &len);
856 ok(ret && len == lstrlenA(test_cp1251), "ReadConsoleOutputCharacterW failed\n");
857 str_wbuf[lstrlenA(test_cp1251)] = 0;
858 ok(!lstrcmpW(str_wbuf, test_unicode), "string does not match the pattern\n");
859
860 /* Close all handles of current console SB */
861 CloseHandle(hConOutNew);
862 CloseHandle(hConOutRW);
863
864 /* Now active SB should be hConOut */
865 hConOutNew = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0,
866 NULL, OPEN_EXISTING, 0, 0);
867 ok(hConOutNew != INVALID_HANDLE_VALUE, "CONOUT$ is not opened\n");
868
869 /* Write using hConOutNew... */
870 SetConsoleCursorPosition(hConOutNew, c);
871 ret = WriteConsoleA(hConOutNew, test_str1, lstrlenA(test_str1), &len, NULL);
872 ok (ret && len == lstrlenA(test_str1), "WriteConsoleA failed\n");
873 /* ... and read it back via hConOut */
874 ret = ReadConsoleOutputCharacterA(hConOut, str_buf, lstrlenA(test_str1), c, &len);
875 ok(ret && len == lstrlenA(test_str1), "ReadConsoleOutputCharacterA failed\n");
876 str_buf[lstrlenA(test_str1)] = 0;
877 todo_wine ok(!lstrcmpA(str_buf, test_str1), "got '%s' expected '%s'\n", str_buf, test_str1);
878 CloseHandle(hConOutNew);
879
880 /* This is not really needed under Windows */
881 SetConsoleActiveScreenBuffer(hConOut);
882
883 /* restore codepage */
884 SetConsoleOutputCP(oldcp);
885 }
886
887 static void test_GetSetConsoleInputExeName(void)
888 {
889 BOOL ret;
890 DWORD error;
891 char buffer[MAX_PATH], module[MAX_PATH], *p;
892 static char input_exe[MAX_PATH] = "winetest.exe";
893
894 SetLastError(0xdeadbeef);
895 ret = pGetConsoleInputExeNameA(0, NULL);
896 error = GetLastError();
897 ok(ret, "GetConsoleInputExeNameA failed\n");
898 ok(error == ERROR_BUFFER_OVERFLOW, "got %u expected ERROR_BUFFER_OVERFLOW\n", error);
899
900 SetLastError(0xdeadbeef);
901 ret = pGetConsoleInputExeNameA(0, buffer);
902 error = GetLastError();
903 ok(ret, "GetConsoleInputExeNameA failed\n");
904 ok(error == ERROR_BUFFER_OVERFLOW, "got %u expected ERROR_BUFFER_OVERFLOW\n", error);
905
906 GetModuleFileNameA(GetModuleHandle(NULL), module, sizeof(module));
907 p = strrchr(module, '\\') + 1;
908
909 ret = pGetConsoleInputExeNameA(sizeof(buffer)/sizeof(buffer[0]), buffer);
910 ok(ret, "GetConsoleInputExeNameA failed\n");
911 todo_wine ok(!lstrcmpA(buffer, p), "got %s expected %s\n", buffer, p);
912
913 SetLastError(0xdeadbeef);
914 ret = pSetConsoleInputExeNameA(NULL);
915 error = GetLastError();
916 ok(!ret, "SetConsoleInputExeNameA failed\n");
917 ok(error == ERROR_INVALID_PARAMETER, "got %u expected ERROR_INVALID_PARAMETER\n", error);
918
919 SetLastError(0xdeadbeef);
920 ret = pSetConsoleInputExeNameA("");
921 error = GetLastError();
922 ok(!ret, "SetConsoleInputExeNameA failed\n");
923 ok(error == ERROR_INVALID_PARAMETER, "got %u expected ERROR_INVALID_PARAMETER\n", error);
924
925 ret = pSetConsoleInputExeNameA(input_exe);
926 ok(ret, "SetConsoleInputExeNameA failed\n");
927
928 ret = pGetConsoleInputExeNameA(sizeof(buffer)/sizeof(buffer[0]), buffer);
929 ok(ret, "GetConsoleInputExeNameA failed\n");
930 ok(!lstrcmpA(buffer, input_exe), "got %s expected %s\n", buffer, input_exe);
931 }
932
933 static void test_GetConsoleProcessList(void)
934 {
935 DWORD ret, *list = NULL;
936
937 if (!pGetConsoleProcessList)
938 {
939 win_skip("GetConsoleProcessList is not available\n");
940 return;
941 }
942
943 SetLastError(0xdeadbeef);
944 ret = pGetConsoleProcessList(NULL, 0);
945 ok(ret == 0, "Expected failure\n");
946 ok(GetLastError() == ERROR_INVALID_PARAMETER,
947 "Expected ERROR_INVALID_PARAMETER, got %d\n",
948 GetLastError());
949
950 SetLastError(0xdeadbeef);
951 ret = pGetConsoleProcessList(NULL, 1);
952 ok(ret == 0, "Expected failure\n");
953 ok(GetLastError() == ERROR_INVALID_PARAMETER,
954 "Expected ERROR_INVALID_PARAMETER, got %d\n",
955 GetLastError());
956
957 /* We should only have 1 process but only for these specific unit tests as
958 * we created our own console. An AttachConsole(ATTACH_PARENT_PROCESS) would
959 * give us two processes for example.
960 */
961 list = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD));
962
963 SetLastError(0xdeadbeef);
964 ret = pGetConsoleProcessList(list, 0);
965 ok(ret == 0, "Expected failure\n");
966 ok(GetLastError() == ERROR_INVALID_PARAMETER,
967 "Expected ERROR_INVALID_PARAMETER, got %d\n",
968 GetLastError());
969
970 SetLastError(0xdeadbeef);
971 ret = pGetConsoleProcessList(list, 1);
972 todo_wine
973 ok(ret == 1, "Expected 1, got %d\n", ret);
974
975 HeapFree(GetProcessHeap(), 0, list);
976
977 list = HeapAlloc(GetProcessHeap(), 0, ret * sizeof(DWORD));
978
979 SetLastError(0xdeadbeef);
980 ret = pGetConsoleProcessList(list, ret);
981 todo_wine
982 ok(ret == 1, "Expected 1, got %d\n", ret);
983
984 if (ret == 1)
985 {
986 DWORD pid = GetCurrentProcessId();
987 ok(list[0] == pid, "Expected %d, got %d\n", pid, list[0]);
988 }
989
990 HeapFree(GetProcessHeap(), 0, list);
991 }
992
993 static void test_OpenConsoleW(void)
994 {
995 static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
996 static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
997 static const WCHAR emptyW[] = {0};
998 static const WCHAR invalidW[] = {'I','N','V','A','L','I','D',0};
999
1000 static const struct
1001 {
1002 LPCWSTR name;
1003 DWORD access;
1004 BOOL inherit;
1005 DWORD creation;
1006 DWORD gle;
1007 } invalid_table[] = {
1008 {NULL, 0, FALSE, 0, ERROR_INVALID_PARAMETER},
1009 {NULL, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, ERROR_INVALID_PARAMETER},
1010 {NULL, 0, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER},
1011 {NULL, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_INVALID_PARAMETER},
1012 {NULL, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER},
1013 {NULL, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING, ERROR_INVALID_PARAMETER},
1014 {emptyW, 0, FALSE, 0, ERROR_INVALID_PARAMETER},
1015 {emptyW, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, ERROR_INVALID_PARAMETER},
1016 {emptyW, 0, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER},
1017 {emptyW, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_INVALID_PARAMETER},
1018 {emptyW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER},
1019 {emptyW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING, ERROR_INVALID_PARAMETER},
1020 {invalidW, 0, FALSE, 0, ERROR_INVALID_PARAMETER},
1021 {invalidW, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, ERROR_INVALID_PARAMETER},
1022 {invalidW, 0, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER},
1023 {invalidW, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_INVALID_PARAMETER},
1024 {invalidW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER},
1025 {invalidW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING, ERROR_INVALID_PARAMETER},
1026 {coninW, 0, FALSE, 0, ERROR_SHARING_VIOLATION},
1027 {coninW, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, ERROR_INVALID_PARAMETER},
1028 {coninW, 0, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER},
1029 {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_SHARING_VIOLATION},
1030 {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_NEW, ERROR_SHARING_VIOLATION},
1031 {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_ALWAYS, ERROR_SHARING_VIOLATION},
1032 {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER},
1033 {coninW, GENERIC_READ | GENERIC_WRITE, FALSE, TRUNCATE_EXISTING, ERROR_INVALID_PARAMETER},
1034 {conoutW, 0, FALSE, 0, ERROR_SHARING_VIOLATION},
1035 {conoutW, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, ERROR_INVALID_PARAMETER},
1036 {conoutW, 0, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER},
1037 {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, 0, ERROR_SHARING_VIOLATION},
1038 {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_NEW, ERROR_SHARING_VIOLATION},
1039 {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, CREATE_ALWAYS, ERROR_SHARING_VIOLATION},
1040 {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_ALWAYS, ERROR_INVALID_PARAMETER},
1041 {conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, TRUNCATE_EXISTING, ERROR_INVALID_PARAMETER},
1042 };
1043
1044 int index;
1045 HANDLE ret;
1046
1047 if (!pOpenConsoleW)
1048 {
1049 win_skip("OpenConsoleW is not available\n");
1050 return;
1051 }
1052
1053 for (index = 0; index < sizeof(invalid_table)/sizeof(invalid_table[0]); index++)
1054 {
1055 SetLastError(0xdeadbeef);
1056 ret = pOpenConsoleW(invalid_table[index].name, invalid_table[index].access,
1057 invalid_table[index].inherit, invalid_table[index].creation);
1058 ok(ret == INVALID_HANDLE_VALUE,
1059 "Expected OpenConsoleW to return INVALID_HANDLE_VALUE for index %d, got %p\n",
1060 index, ret);
1061 ok(GetLastError() == invalid_table[index].gle,
1062 "Expected GetLastError() to return %u for index %d, got %u\n",
1063 invalid_table[index].gle, index, GetLastError());
1064 }
1065
1066 /* OpenConsoleW should not touch the last error on success. */
1067 SetLastError(0xdeadbeef);
1068 ret = pOpenConsoleW(coninW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING);
1069 ok(ret != INVALID_HANDLE_VALUE,
1070 "Expected OpenConsoleW to return a valid handle\n");
1071 ok(GetLastError() == 0xdeadbeef,
1072 "Expected the last error to be untouched, got %u\n", GetLastError());
1073 if (ret != INVALID_HANDLE_VALUE)
1074 CloseHandle(ret);
1075
1076 SetLastError(0xdeadbeef);
1077 ret = pOpenConsoleW(conoutW, GENERIC_READ | GENERIC_WRITE, FALSE, OPEN_EXISTING);
1078 ok(ret != INVALID_HANDLE_VALUE,
1079 "Expected OpenConsoleW to return a valid handle\n");
1080 ok(GetLastError() == 0xdeadbeef,
1081 "Expected the last error to be untouched, got %u\n", GetLastError());
1082 if (ret != INVALID_HANDLE_VALUE)
1083 CloseHandle(ret);
1084 }
1085
1086 START_TEST(console)
1087 {
1088 HANDLE hConIn, hConOut;
1089 BOOL ret;
1090 CONSOLE_SCREEN_BUFFER_INFO sbi;
1091
1092 init_function_pointers();
1093
1094 /* be sure we have a clean console (and that's our own)
1095 * FIXME: this will make the test fail (currently) if we don't run
1096 * under X11
1097 * Another solution would be to rerun the test under wineconsole with
1098 * the curses backend
1099 */
1100
1101 /* first, we detach and open a fresh console to play with */
1102 FreeConsole();
1103 ok(AllocConsole(), "Couldn't alloc console\n");
1104 hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
1105 hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
1106
1107 /* now verify everything's ok */
1108 ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn\n");
1109 ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut\n");
1110
1111 ret = GetConsoleScreenBufferInfo(hConOut, &sbi);
1112 ok(ret, "Getting sb info\n");
1113 if (!ret) return;
1114
1115 /* Non interactive tests */
1116 testCursor(hConOut, sbi.dwSize);
1117 /* test parameters (FIXME: test functionality) */
1118 testCursorInfo(hConOut);
1119 /* will test wrapped (on/off) & processed (on/off) strings output */
1120 testWrite(hConOut, sbi.dwSize);
1121 /* will test line scrolling at the bottom of the screen */
1122 /* testBottomScroll(); */
1123 /* will test all the scrolling operations */
1124 testScroll(hConOut, sbi.dwSize);
1125 /* will test sb creation / modification / codepage handling */
1126 testScreenBuffer(hConOut);
1127 testCtrlHandler();
1128 /* still to be done: access rights & access on objects */
1129
1130 if (!pGetConsoleInputExeNameA || !pSetConsoleInputExeNameA)
1131 win_skip("GetConsoleInputExeNameA and/or SetConsoleInputExeNameA is not available\n");
1132 else
1133 test_GetSetConsoleInputExeName();
1134
1135 test_GetConsoleProcessList();
1136 test_OpenConsoleW();
1137 }