~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/kernel32/tests/console.c

Version: ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  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 BOOL (WINAPI *pSetConsoleInputExeNameA)(LPCSTR);
 28 
 29 /* DEFAULT_ATTRIB is used for all initial filling of the console.
 30  * all modifications are made with TEST_ATTRIB so that we could check
 31  * what has to be modified or not
 32  */
 33 #define TEST_ATTRIB    (BACKGROUND_BLUE | FOREGROUND_GREEN)
 34 #define DEFAULT_ATTRIB (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED)
 35 /* when filling the screen with non-blank chars, this macro defines
 36  * what character should be at position 'c'
 37  */
 38 #define CONTENT(c)    ('A' + (((c).Y * 17 + (c).X) % 23))
 39 
 40 #define okCURSOR(hCon, c) do { \
 41   CONSOLE_SCREEN_BUFFER_INFO __sbi; \
 42   BOOL expect = GetConsoleScreenBufferInfo((hCon), &__sbi) && \
 43                 __sbi.dwCursorPosition.X == (c).X && __sbi.dwCursorPosition.Y == (c).Y; \
 44   ok(expect, "Expected cursor at (%d,%d), got (%d,%d)\n", \
 45      (c).X, (c).Y, __sbi.dwCursorPosition.X, __sbi.dwCursorPosition.Y); \
 46 } while (0)
 47 
 48 #define okCHAR(hCon, c, ch, attr) do { \
 49   char __ch; WORD __attr; DWORD __len; BOOL expect; \
 50   expect = ReadConsoleOutputCharacter((hCon), &__ch, 1, (c), &__len) == 1 && __len == 1 && __ch == (ch); \
 51   ok(expect, "At (%d,%d): expecting char '%c'/%02x got '%c'/%02x\n", (c).X, (c).Y, (ch), (ch), __ch, __ch); \
 52   expect = ReadConsoleOutputAttribute((hCon), &__attr, 1, (c), &__len) == 1 && __len == 1 && __attr == (attr); \
 53   ok(expect, "At (%d,%d): expecting attr %04x got %04x\n", (c).X, (c).Y, (attr), __attr); \
 54 } while (0)
 55 
 56 static void init_function_pointers(void)
 57 {
 58     HMODULE hKernel32;
 59 
 60 #define KERNEL32_GET_PROC(func)                                     \
 61     p##func = (void *)GetProcAddress(hKernel32, #func);             \
 62     if(!p##func) trace("GetProcAddress(hKernel32, '%s') failed\n", #func);
 63 
 64     hKernel32 = GetModuleHandleA("kernel32.dll");
 65     KERNEL32_GET_PROC(GetConsoleInputExeNameA);
 66     KERNEL32_GET_PROC(SetConsoleInputExeNameA);
 67 
 68 #undef KERNEL32_GET_PROC
 69 }
 70 
 71 /* FIXME: this could be optimized on a speed point of view */
 72 static void resetContent(HANDLE hCon, COORD sbSize, BOOL content)
 73 {
 74     COORD       c;
 75     WORD        attr = DEFAULT_ATTRIB;
 76     char        ch;
 77     DWORD       len;
 78 
 79     for (c.X = 0; c.X < sbSize.X; c.X++)
 80     {
 81         for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
 82         {
 83             ch = (content) ? CONTENT(c) : ' ';
 84             WriteConsoleOutputAttribute(hCon, &attr, 1, c, &len);
 85             WriteConsoleOutputCharacterA(hCon, &ch, 1, c, &len);
 86         }
 87     }
 88 }
 89 
 90 static void testCursor(HANDLE hCon, COORD sbSize)
 91 {
 92     COORD               c;
 93 
 94     c.X = c.Y = 0;
 95     ok(SetConsoleCursorPosition(0, c) == 0, "No handle\n");
 96     ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n",
 97        ERROR_INVALID_HANDLE, GetLastError());
 98 
 99     c.X = c.Y = 0;
100     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
101     okCURSOR(hCon, c);
102 
103     c.X = sbSize.X - 1;
104     c.Y = sbSize.Y - 1;
105     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in lower-right\n");
106     okCURSOR(hCon, c);
107 
108     c.X = sbSize.X;
109     c.Y = sbSize.Y - 1;
110     ok(SetConsoleCursorPosition(hCon, c) == 0, "Cursor is outside\n");
111     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError: expecting %u got %u\n",
112        ERROR_INVALID_PARAMETER, GetLastError());
113 
114     c.X = sbSize.X - 1;
115     c.Y = sbSize.Y;
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 = -1;
121     c.Y = 0;
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 = 0;
127     c.Y = -1;
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 
133 static void testCursorInfo(HANDLE hCon)
134 {
135     BOOL ret;
136     CONSOLE_CURSOR_INFO info;
137 
138     SetLastError(0xdeadbeef);
139     ret = GetConsoleCursorInfo(NULL, NULL);
140     ok(!ret, "Expected failure\n");
141     ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n",
142        ERROR_INVALID_HANDLE, GetLastError());
143 
144     SetLastError(0xdeadbeef);
145     info.dwSize = -1;
146     ret = GetConsoleCursorInfo(NULL, &info);
147     ok(!ret, "Expected failure\n");
148     ok(info.dwSize == -1, "Expected no change for dwSize\n");
149     ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n",
150        ERROR_INVALID_HANDLE, GetLastError());
151 
152     /* Test the correct call first to distinguish between win9x and the rest */
153     SetLastError(0xdeadbeef);
154     ret = GetConsoleCursorInfo(hCon, &info);
155     ok(ret, "Expected success\n");
156     ok(info.dwSize == 25 ||
157        info.dwSize == 12 /* win9x */,
158        "Expected 12 or 25, got %d\n", info.dwSize);
159     ok(info.bVisible, "Expected the cursor to be visible\n");
160     ok(GetLastError() == 0xdeadbeef, "GetLastError: expecting %u got %u\n",
161        0xdeadbeef, GetLastError());
162 
163     if (info.dwSize == 12)
164     {
165         skip("NULL CONSOLE_CURSOR_INFO will crash on win9x\n");
166         return;
167     }
168 
169     SetLastError(0xdeadbeef);
170     ret = GetConsoleCursorInfo(hCon, NULL);
171     ok(!ret, "Expected failure\n");
172     ok(GetLastError() == ERROR_INVALID_ACCESS, "GetLastError: expecting %u got %u\n",
173        ERROR_INVALID_ACCESS, GetLastError());
174 }
175 
176 static void testWriteSimple(HANDLE hCon, COORD sbSize)
177 {
178     COORD               c;
179     DWORD               len;
180     const char*         mytest = "abcdefg";
181     const int   mylen = strlen(mytest);
182 
183     /* single line write */
184     c.X = c.Y = 0;
185     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
186 
187     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
188     c.Y = 0;
189     for (c.X = 0; c.X < mylen; c.X++)
190     {
191         okCHAR(hCon, c, mytest[c.X], TEST_ATTRIB);
192     }
193 
194     okCURSOR(hCon, c);
195     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
196 }
197 
198 static void testWriteNotWrappedNotProcessed(HANDLE hCon, COORD sbSize)
199 {
200     COORD               c;
201     DWORD               len, mode;
202     const char*         mytest = "123";
203     const int           mylen = strlen(mytest);
204     int                 ret;
205     int                 p;
206 
207     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode & ~(ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT)),
208        "clearing wrap at EOL & processed output\n");
209 
210     /* write line, wrapping disabled, buffer exceeds sb width */
211     c.X = sbSize.X - 3; c.Y = 0;
212     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
213 
214     ret = WriteConsole(hCon, mytest, mylen, &len, NULL);
215     ok(ret != 0 && len == mylen, "Couldn't write, ret = %d, len = %d\n", ret, len);
216     c.Y = 0;
217     for (p = mylen - 3; p < mylen; p++)
218     {
219         c.X = sbSize.X - 3 + p % 3;
220         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
221     }
222 
223     c.X = 0; c.Y = 1;
224     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
225 
226     p = sbSize.X - 3 + mylen % 3;
227     c.X = p; c.Y = 0;
228 
229     /* write line, wrapping disabled, strings end on end of line */
230     c.X = sbSize.X - mylen; c.Y = 0;
231     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
232 
233     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
234 }
235 
236 static void testWriteNotWrappedProcessed(HANDLE hCon, COORD sbSize)
237 {
238     COORD               c;
239     DWORD               len, mode;
240     const char*         mytest = "abcd\nf\tg";
241     const int   mylen = strlen(mytest);
242     const int   mylen2 = strchr(mytest, '\n') - mytest;
243     int                 p;
244 
245     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, (mode | ENABLE_PROCESSED_OUTPUT) & ~ENABLE_WRAP_AT_EOL_OUTPUT),
246        "clearing wrap at EOL & setting processed output\n");
247 
248     /* write line, wrapping disabled, buffer exceeds sb width */
249     c.X = sbSize.X - 5; c.Y = 0;
250     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-5\n");
251 
252     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
253     c.Y = 0;
254     for (c.X = sbSize.X - 5; c.X < sbSize.X - 1; c.X++)
255     {
256         okCHAR(hCon, c, mytest[c.X - sbSize.X + 5], TEST_ATTRIB);
257     }
258     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
259 
260     c.X = 0; c.Y++;
261     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
262     for (c.X = 1; c.X < 8; c.X++)
263         okCHAR(hCon, c, ' ', TEST_ATTRIB);
264     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
265     c.X++;
266     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
267 
268     okCURSOR(hCon, c);
269 
270     /* write line, wrapping disabled, strings end on end of line */
271     c.X = sbSize.X - 4; c.Y = 0;
272     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-4\n");
273 
274     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
275     c.Y = 0;
276     for (c.X = sbSize.X - 4; c.X < sbSize.X; c.X++)
277     {
278         okCHAR(hCon, c, mytest[c.X - sbSize.X + 4], TEST_ATTRIB);
279     }
280     c.X = 0; c.Y++;
281     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
282     for (c.X = 1; c.X < 8; c.X++)
283         okCHAR(hCon, c, ' ', TEST_ATTRIB);
284     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
285     c.X++;
286     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
287 
288     okCURSOR(hCon, c);
289 
290     /* write line, wrapping disabled, strings end after end of line */
291     c.X = sbSize.X - 3; c.Y = 0;
292     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-4\n");
293 
294     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
295     c.Y = 0;
296     for (p = mylen2 - 3; p < mylen2; p++)
297     {
298         c.X = sbSize.X - 3 + p % 3;
299         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
300     }
301     c.X = 0; c.Y = 1;
302     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
303     for (c.X = 1; c.X < 8; c.X++)
304         okCHAR(hCon, c, ' ', TEST_ATTRIB);
305     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
306     c.X++;
307     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
308 
309     okCURSOR(hCon, c);
310 }
311 
312 static void testWriteWrappedNotProcessed(HANDLE hCon, COORD sbSize)
313 {
314     COORD               c;
315     DWORD               len, mode;
316     const char*         mytest = "abcd\nf\tg";
317     const int   mylen = strlen(mytest);
318     int                 p;
319 
320     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon,(mode | ENABLE_WRAP_AT_EOL_OUTPUT) & ~(ENABLE_PROCESSED_OUTPUT)),
321        "setting wrap at EOL & clearing processed output\n");
322 
323     /* write line, wrapping enabled, buffer doesn't exceed sb width */
324     c.X = sbSize.X - 9; c.Y = 0;
325     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-9\n");
326 
327     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
328     c.Y = 0;
329     for (p = 0; p < mylen; p++)
330     {
331         c.X = sbSize.X - 9 + p;
332         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
333     }
334     c.X = sbSize.X - 9 + mylen;
335     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
336     c.X = 0; c.Y = 1;
337     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
338 
339     /* write line, wrapping enabled, buffer does exceed sb width */
340     c.X = sbSize.X - 3; c.Y = 0;
341     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
342 
343     c.Y = 1;
344     c.X = mylen - 3;
345     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
346 }
347 
348 static void testWriteWrappedProcessed(HANDLE hCon, COORD sbSize)
349 {
350     COORD               c;
351     DWORD               len, mode;
352     const char*         mytest = "abcd\nf\tg";
353     const int   mylen = strlen(mytest);
354     int                 p;
355 
356     ok(GetConsoleMode(hCon, &mode) && SetConsoleMode(hCon, mode | (ENABLE_WRAP_AT_EOL_OUTPUT|ENABLE_PROCESSED_OUTPUT)),
357        "setting wrap at EOL & processed output\n");
358 
359     /* write line, wrapping enabled, buffer doesn't exceed sb width */
360     c.X = sbSize.X - 9; c.Y = 0;
361     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-9\n");
362 
363     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
364     for (p = 0; p < 4; p++)
365     {
366         c.X = sbSize.X - 9 + p;
367         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
368     }
369     c.X = sbSize.X - 9 + p;
370     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
371     c.X = 0; c.Y++;
372     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
373     for (c.X = 1; c.X < 8; c.X++)
374         okCHAR(hCon, c, ' ', TEST_ATTRIB);
375     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
376     c.X++;
377     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
378     okCURSOR(hCon, c);
379 
380     /* write line, wrapping enabled, buffer does exceed sb width */
381     c.X = sbSize.X - 3; c.Y = 2;
382     ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left-3\n");
383 
384     ok(WriteConsole(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
385     for (p = 0; p < 3; p++)
386     {
387         c.X = sbSize.X - 3 + p;
388         okCHAR(hCon, c, mytest[p], TEST_ATTRIB);
389     }
390     c.X = 0; c.Y++;
391     okCHAR(hCon, c, mytest[3], TEST_ATTRIB);
392     c.X++;
393     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
394 
395     c.X = 0; c.Y++;
396     okCHAR(hCon, c, mytest[5], TEST_ATTRIB);
397     for (c.X = 1; c.X < 8; c.X++)
398         okCHAR(hCon, c, ' ', TEST_ATTRIB);
399     okCHAR(hCon, c, mytest[7], TEST_ATTRIB);
400     c.X++;
401     okCHAR(hCon, c, ' ', DEFAULT_ATTRIB);
402     okCURSOR(hCon, c);
403 }
404 
405 static void testWrite(HANDLE hCon, COORD sbSize)
406 {
407     /* FIXME: should in fact insure that the sb is at least 10 character wide */
408     ok(SetConsoleTextAttribute(hCon, TEST_ATTRIB), "Setting default text color\n");
409     resetContent(hCon, sbSize, FALSE);
410     testWriteSimple(hCon, sbSize);
411     resetContent(hCon, sbSize, FALSE);
412     testWriteNotWrappedNotProcessed(hCon, sbSize);
413     resetContent(hCon, sbSize, FALSE);
414     testWriteNotWrappedProcessed(hCon, sbSize);
415     resetContent(hCon, sbSize, FALSE);
416     testWriteWrappedNotProcessed(hCon, sbSize);
417     resetContent(hCon, sbSize, FALSE);
418     testWriteWrappedProcessed(hCon, sbSize);
419 }
420 
421 static void testScroll(HANDLE hCon, COORD sbSize)
422 {
423     SMALL_RECT  scroll, clip;
424     COORD       dst, c, tc;
425     CHAR_INFO   ci;
426     BOOL ret;
427 
428 #define W 11
429 #define H 7
430 
431 #define IN_SRECT(r,c) ((r).Left <= (c).X && (c).X <= (r).Right && (r).Top <= (c).Y && (c).Y <= (r).Bottom)
432 #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)
433 
434     /* no clipping, src & dst rect don't overlap */
435     resetContent(hCon, sbSize, TRUE);
436 
437     scroll.Left = 0;
438     scroll.Right = W - 1;
439     scroll.Top = 0;
440     scroll.Bottom = H - 1;
441     dst.X = W + 3;
442     dst.Y = H + 3;
443     ci.Char.UnicodeChar = '#';
444     ci.Attributes = TEST_ATTRIB;
445 
446     clip.Left = 0;
447     clip.Right = sbSize.X - 1;
448     clip.Top = 0;
449     clip.Bottom = sbSize.Y - 1;
450 
451     ok(ScrollConsoleScreenBuffer(hCon, &scroll, NULL, dst, &ci), "Scrolling SB\n");
452 
453     for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
454     {
455         for (c.X = 0; c.X < sbSize.X; c.X++)
456         {
457             if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
458             {
459                 tc.X = c.X - dst.X;
460                 tc.Y = c.Y - dst.Y;
461                 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
462             }
463             else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
464                 okCHAR(hCon, c, '#', TEST_ATTRIB);
465             else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
466         }
467     }
468 
469     /* no clipping, src & dst rect do overlap */
470     resetContent(hCon, sbSize, TRUE);
471 
472     scroll.Left = 0;
473     scroll.Right = W - 1;
474     scroll.Top = 0;
475     scroll.Bottom = H - 1;
476     dst.X = W /2;
477     dst.Y = H / 2;
478     ci.Char.UnicodeChar = '#';
479     ci.Attributes = TEST_ATTRIB;
480 
481     clip.Left = 0;
482     clip.Right = sbSize.X - 1;
483     clip.Top = 0;
484     clip.Bottom = sbSize.Y - 1;
485 
486     ok(ScrollConsoleScreenBuffer(hCon, &scroll, NULL, dst, &ci), "Scrolling SB\n");
487 
488     for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
489     {
490         for (c.X = 0; c.X < sbSize.X; c.X++)
491         {
492             if (dst.X <= c.X && c.X < dst.X + W && dst.Y <= c.Y && c.Y < dst.Y + H)
493             {
494                 tc.X = c.X - dst.X;
495                 tc.Y = c.Y - dst.Y;
496                 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
497             }
498             else if (c.X < W && c.Y < H) okCHAR(hCon, c, '#', TEST_ATTRIB);
499             else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
500         }
501     }
502 
503     /* clipping, src & dst rect don't overlap */
504     resetContent(hCon, sbSize, TRUE);
505 
506     scroll.Left = 0;
507     scroll.Right = W - 1;
508     scroll.Top = 0;
509     scroll.Bottom = H - 1;
510     dst.X = W + 3;
511     dst.Y = H + 3;
512     ci.Char.UnicodeChar = '#';
513     ci.Attributes = TEST_ATTRIB;
514 
515     clip.Left = W / 2;
516     clip.Right = min(W + W / 2, sbSize.X - 1);
517     clip.Top = H / 2;
518     clip.Bottom = min(H + H / 2, sbSize.Y - 1);
519 
520     SetLastError(0xdeadbeef);
521     ret = ScrollConsoleScreenBuffer(hCon, &scroll, &clip, dst, &ci);
522     if (ret)
523     {
524         for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
525         {
526             for (c.X = 0; c.X < sbSize.X; c.X++)
527             {
528                 if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
529                 {
530                     tc.X = c.X - dst.X;
531                     tc.Y = c.Y - dst.Y;
532                     okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
533                 }
534                 else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
535                     okCHAR(hCon, c, '#', TEST_ATTRIB);
536                 else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
537             }
538         }
539     }
540     else
541     {
542         /* Win9x will fail, Only accept ERROR_NOT_ENOUGH_MEMORY */
543         ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY,
544             "Expected ERROR_NOT_ENOUGH_MEMORY, got %u\n", GetLastError());
545     }
546 
547     /* clipping, src & dst rect do overlap */
548     resetContent(hCon, sbSize, TRUE);
549 
550     scroll.Left = 0;
551     scroll.Right = W - 1;
552     scroll.Top = 0;
553     scroll.Bottom = H - 1;
554     dst.X = W / 2 - 3;
555     dst.Y = H / 2 - 3;
556     ci.Char.UnicodeChar = '#';
557     ci.Attributes = TEST_ATTRIB;
558 
559     clip.Left = W / 2;
560     clip.Right = min(W + W / 2, sbSize.X - 1);
561     clip.Top = H / 2;
562     clip.Bottom = min(H + H / 2, sbSize.Y - 1);
563 
564     ok(ScrollConsoleScreenBuffer(hCon, &scroll, &clip, dst, &ci), "Scrolling SB\n");
565 
566     for (c.Y = 0; c.Y < sbSize.Y; c.Y++)
567     {
568         for (c.X = 0; c.X < sbSize.X; c.X++)
569         {
570             if (IN_SRECT2(scroll, dst, c) && IN_SRECT(clip, c))
571             {
572                 tc.X = c.X - dst.X;
573                 tc.Y = c.Y - dst.Y;
574                 okCHAR(hCon, c, CONTENT(tc), DEFAULT_ATTRIB);
575             }
576             else if (IN_SRECT(scroll, c) && IN_SRECT(clip, c))
577                 okCHAR(hCon, c, '#', TEST_ATTRIB);
578             else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
579         }
580     }
581 }
582 
583 static int mch_count;
584 /* we need the event as Wine console event generation isn't synchronous
585  * (ie GenerateConsoleCtrlEvent returns before all ctrl-handlers in all
586  * processes have been called).
587  */
588 static HANDLE mch_event;
589 static BOOL WINAPI mch(DWORD event)
590 {
591     mch_count++;
592     SetEvent(mch_event);
593     return TRUE;
594 }
595 
596 static void testCtrlHandler(void)
597 {
598     ok(!SetConsoleCtrlHandler(mch, FALSE), "Shouldn't succeed\n");
599     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %u\n", GetLastError());
600     ok(SetConsoleCtrlHandler(mch, TRUE), "Couldn't set handler\n");
601     /* wine requires the event for the test, as we cannot insure, so far, that event
602      * are processed synchronously in GenerateConsoleCtrlEvent()
603      */
604     mch_event = CreateEventA(NULL, TRUE, FALSE, NULL);
605     mch_count = 0;
606     ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n");
607     /* FIXME: it isn't synchronous on wine but it can still happen before we test */
608     if (0) ok(mch_count == 1, "Event isn't synchronous\n");
609     ok(WaitForSingleObject(mch_event, 3000) == WAIT_OBJECT_0, "event sending didn't work\n");
610     CloseHandle(mch_event);
611 
612     /* Turning off ctrl-c handling doesn't work on win9x such way ... */
613     ok(SetConsoleCtrlHandler(NULL, TRUE), "Couldn't turn off ctrl-c handling\n");
614     mch_event = CreateEventA(NULL, TRUE, FALSE, NULL);
615     mch_count = 0;
616     if(!(GetVersion() & 0x80000000))
617         /* ... and next line leads to an unhandled exception on 9x.  Avoid it on 9x. */
618         ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n");
619     ok(WaitForSingleObject(mch_event, 3000) == WAIT_TIMEOUT && mch_count == 0, "Event shouldn't have been sent\n");
620     CloseHandle(mch_event);
621     ok(SetConsoleCtrlHandler(mch, FALSE), "Couldn't remove handler\n");
622     ok(!SetConsoleCtrlHandler(mch, FALSE), "Shouldn't succeed\n");
623     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %u\n", GetLastError());
624 }
625 
626 /*
627  * Test console screen buffer:
628  * 1) Try to set invalid handle.
629  * 2) Try to set non-console handles.
630  * 3) Use CONOUT$ file as active SB.
631  * 4) Test cursor.
632  * 5) Test output codepage to show it is not a property of SB.
633  * 6) Test switching to old SB if we close all handles to current SB - works
634  * in Windows, TODO in wine.
635  *
636  * What is not tested but should be:
637  * 1) ScreenBufferInfo
638  */
639 static void testScreenBuffer(HANDLE hConOut)
640 {
641     HANDLE hConOutRW, hConOutRO, hConOutWT;
642     HANDLE hFileOutRW, hFileOutRO, hFileOutWT;
643     HANDLE hConOutNew;
644     char test_str1[] = "Test for SB1";
645     char test_str2[] = "Test for SB2";
646     char test_cp866[] = {0xe2, 0xa5, 0xe1, 0xe2, 0};
647     char test_cp1251[] = {0xf2, 0xe5, 0xf1, 0xf2, 0};
648     WCHAR test_unicode[] = {0x0442, 0x0435, 0x0441, 0x0442, 0};
649     WCHAR str_wbuf[20];
650     char str_buf[20];
651     DWORD len;
652     COORD c;
653     BOOL ret;
654     DWORD oldcp;
655 
656     if (!IsValidCodePage(866))
657     {
658         skip("Codepage 866 not available\n");
659         return;
660     }
661 
662     /* In the beginning set output codepage to 866 */
663     oldcp = GetConsoleOutputCP();
664     SetLastError(0xdeadbeef);
665     ret = SetConsoleOutputCP(866);
666     if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
667     {
668         skip("SetConsoleOutputCP is not implemented\n");
669         return;
670     }
671     ok(ret, "Cannot set output codepage to 866\n");
672 
673     hConOutRW = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
674                          FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
675                          CONSOLE_TEXTMODE_BUFFER, NULL);
676     ok(hConOutRW != INVALID_HANDLE_VALUE,
677        "Cannot create a new screen buffer for ReadWrite\n");
678     hConOutRO = CreateConsoleScreenBuffer(GENERIC_READ,
679                          FILE_SHARE_READ, NULL,
680                          CONSOLE_TEXTMODE_BUFFER, NULL);
681     ok(hConOutRO != INVALID_HANDLE_VALUE,
682        "Cannot create a new screen buffer for ReadOnly\n");
683     hConOutWT = CreateConsoleScreenBuffer(GENERIC_WRITE,
684                          FILE_SHARE_WRITE, NULL,
685                          CONSOLE_TEXTMODE_BUFFER, NULL);
686     ok(hConOutWT != INVALID_HANDLE_VALUE,
687        "Cannot create a new screen buffer for WriteOnly\n");
688 
689     hFileOutRW = CreateFileA("NUL", GENERIC_READ | GENERIC_WRITE,
690                              FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
691                              OPEN_EXISTING, 0, NULL);
692     ok(hFileOutRW != INVALID_HANDLE_VALUE, "Cannot open NUL for ReadWrite\n");
693     hFileOutRO = CreateFileA("NUL", GENERIC_READ, FILE_SHARE_READ,
694                              NULL, OPEN_EXISTING, 0, NULL);
695     ok(hFileOutRO != INVALID_HANDLE_VALUE, "Cannot open NUL for ReadOnly\n");
696     hFileOutWT = CreateFileA("NUL", GENERIC_WRITE, FILE_SHARE_WRITE,
697                              NULL, OPEN_EXISTING, 0, NULL);
698     ok(hFileOutWT != INVALID_HANDLE_VALUE, "Cannot open NUL for WriteOnly\n");
699 
700     /* Trying to set invalid handle */
701     SetLastError(0);
702     ok(!SetConsoleActiveScreenBuffer(INVALID_HANDLE_VALUE),
703        "Shouldn't succeed\n");
704     ok(GetLastError() == ERROR_INVALID_HANDLE,
705        "GetLastError: expecting %u got %u\n",
706        ERROR_INVALID_HANDLE, GetLastError());
707 
708     /* Trying to set non-console handles */
709     SetLastError(0);
710     ok(!SetConsoleActiveScreenBuffer(hFileOutRW), "Shouldn't succeed\n");
711     ok(GetLastError() == ERROR_INVALID_HANDLE,
712        "GetLastError: expecting %u got %u\n",
713        ERROR_INVALID_HANDLE, GetLastError());
714 
715     SetLastError(0);
716     ok(!SetConsoleActiveScreenBuffer(hFileOutRO), "Shouldn't succeed\n");
717     ok(GetLastError() == ERROR_INVALID_HANDLE,
718        "GetLastError: expecting %u got %u\n",
719        ERROR_INVALID_HANDLE, GetLastError());
720 
721     SetLastError(0);
722     ok(!SetConsoleActiveScreenBuffer(hFileOutWT), "Shouldn't succeed\n");
723     ok(GetLastError() == ERROR_INVALID_HANDLE,
724        "GetLastError: expecting %u got %u\n",
725        ERROR_INVALID_HANDLE, GetLastError());
726 
727     CloseHandle(hFileOutRW);
728     CloseHandle(hFileOutRO);
729     CloseHandle(hFileOutWT);
730 
731     /* Trying to set SB handles with various access modes */
732     SetLastError(0);
733     ok(!SetConsoleActiveScreenBuffer(hConOutRO), "Shouldn't succeed\n");
734     ok(GetLastError() == ERROR_INVALID_HANDLE,
735        "GetLastError: expecting %u got %u\n",
736        ERROR_INVALID_HANDLE, GetLastError());
737 
738     ok(SetConsoleActiveScreenBuffer(hConOutWT), "Couldn't set new WriteOnly SB\n");
739 
740     ok(SetConsoleActiveScreenBuffer(hConOutRW), "Couldn't set new ReadWrite SB\n");
741 
742     CloseHandle(hConOutWT);
743     CloseHandle(hConOutRO);
744 
745     /* Now we have two ReadWrite SB, active must be hConOutRW */
746     /* Open current SB via CONOUT$ */
747     hConOutNew = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0,
748                              NULL, OPEN_EXISTING, 0, 0);
749     ok(hConOutNew != INVALID_HANDLE_VALUE, "CONOUT$ is not opened\n");
750 
751 
752     /* test cursor */
753     c.X = c.Y = 10;
754     SetConsoleCursorPosition(hConOut, c);
755     c.X = c.Y = 5;
756     SetConsoleCursorPosition(hConOutRW, c);
757     okCURSOR(hConOutNew, c);