Fixes for -Wmissing-declaration and -Wwrite-string warnings.
[wine] / dlls / kernel / console.c
1 /*
2  * Win32 console functions
3  *
4  * Copyright 1995 Martin von Loewis and Cameron Heide
5  * Copyright 1997 Karl Garrison
6  * Copyright 1998 John Richardson
7  * Copyright 1998 Marcus Meissner
8  * Copyright 2001,2002,2004 Eric Pouech
9  * Copyright 2001 Alexandre Julliard
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  */
25
26 /* Reference applications:
27  * -  IDA (interactive disassembler) full version 3.75. Works.
28  * -  LYNX/W32. Works mostly, some keys crash it.
29  */
30
31 #include "config.h"
32 #include "wine/port.h"
33
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <string.h>
37 #ifdef HAVE_UNISTD_H
38 # include <unistd.h>
39 #endif
40 #include <assert.h>
41
42 #include "windef.h"
43 #include "winbase.h"
44 #include "winnls.h"
45 #include "winerror.h"
46 #include "wincon.h"
47 #include "wine/winbase16.h"
48 #include "wine/server.h"
49 #include "wine/exception.h"
50 #include "wine/unicode.h"
51 #include "wine/debug.h"
52 #include "excpt.h"
53 #include "console_private.h"
54 #include "kernel_private.h"
55
56 WINE_DEFAULT_DEBUG_CHANNEL(console);
57
58 static UINT console_input_codepage;
59 static UINT console_output_codepage;
60
61
62 /* map input records to ASCII */
63 static void input_records_WtoA( INPUT_RECORD *buffer, int count )
64 {
65     int i;
66     char ch;
67
68     for (i = 0; i < count; i++)
69     {
70         if (buffer[i].EventType != KEY_EVENT) continue;
71         WideCharToMultiByte( GetConsoleCP(), 0,
72                              &buffer[i].Event.KeyEvent.uChar.UnicodeChar, 1, &ch, 1, NULL, NULL );
73         buffer[i].Event.KeyEvent.uChar.AsciiChar = ch;
74     }
75 }
76
77 /* map input records to Unicode */
78 static void input_records_AtoW( INPUT_RECORD *buffer, int count )
79 {
80     int i;
81     WCHAR ch;
82
83     for (i = 0; i < count; i++)
84     {
85         if (buffer[i].EventType != KEY_EVENT) continue;
86         MultiByteToWideChar( GetConsoleCP(), 0,
87                              &buffer[i].Event.KeyEvent.uChar.AsciiChar, 1, &ch, 1 );
88         buffer[i].Event.KeyEvent.uChar.UnicodeChar = ch;
89     }
90 }
91
92 /* map char infos to ASCII */
93 static void char_info_WtoA( CHAR_INFO *buffer, int count )
94 {
95     char ch;
96
97     while (count-- > 0)
98     {
99         WideCharToMultiByte( GetConsoleOutputCP(), 0, &buffer->Char.UnicodeChar, 1,
100                              &ch, 1, NULL, NULL );
101         buffer->Char.AsciiChar = ch;
102         buffer++;
103     }
104 }
105
106 /* map char infos to Unicode */
107 static void char_info_AtoW( CHAR_INFO *buffer, int count )
108 {
109     WCHAR ch;
110
111     while (count-- > 0)
112     {
113         MultiByteToWideChar( GetConsoleOutputCP(), 0, &buffer->Char.AsciiChar, 1, &ch, 1 );
114         buffer->Char.UnicodeChar = ch;
115         buffer++;
116     }
117 }
118
119
120 /******************************************************************************
121  * GetConsoleWindow [KERNEL32.@]
122  */
123 HWND WINAPI GetConsoleWindow(VOID)
124 {
125     FIXME("stub\n");
126     return NULL;
127 }
128
129
130 /******************************************************************************
131  * GetConsoleCP [KERNEL32.@]  Returns the OEM code page for the console
132  *
133  * RETURNS
134  *    Code page code
135  */
136 UINT WINAPI GetConsoleCP(VOID)
137 {
138     if (!console_input_codepage) 
139     {
140         console_input_codepage = GetOEMCP();
141         TRACE("%u\n", console_input_codepage);
142     }
143     return console_input_codepage;
144 }
145
146
147 /******************************************************************************
148  *  SetConsoleCP         [KERNEL32.@]
149  */
150 BOOL WINAPI SetConsoleCP(UINT cp)
151 {
152     if (!IsValidCodePage( cp )) return FALSE;
153     console_input_codepage = cp;
154     return TRUE;
155 }
156
157
158 /***********************************************************************
159  *            GetConsoleOutputCP   (KERNEL32.@)
160  */
161 UINT WINAPI GetConsoleOutputCP(VOID)
162 {
163     if (!console_output_codepage)
164     {
165         console_output_codepage = GetOEMCP();
166         TRACE("%u\n", console_output_codepage);
167     }
168     return console_output_codepage;
169 }
170
171
172 /******************************************************************************
173  * SetConsoleOutputCP [KERNEL32.@]  Set the output codepage used by the console
174  *
175  * PARAMS
176  *    cp [I] code page to set
177  *
178  * RETURNS
179  *    Success: TRUE
180  *    Failure: FALSE
181  */
182 BOOL WINAPI SetConsoleOutputCP(UINT cp)
183 {
184     if (!IsValidCodePage( cp )) return FALSE;
185     console_output_codepage = cp;
186     return TRUE;
187 }
188
189
190 /***********************************************************************
191  *           Beep   (KERNEL32.@)
192  */
193 BOOL WINAPI Beep( DWORD dwFreq, DWORD dwDur )
194 {
195     static const char beep = '\a';
196     /* dwFreq and dwDur are ignored by Win95 */
197     if (isatty(2)) write( 2, &beep, 1 );
198     return TRUE;
199 }
200
201
202 /******************************************************************
203  *              OpenConsoleW            (KERNEL32.@)
204  *
205  * Undocumented
206  *      Open a handle to the current process console.
207  *      Returns INVALID_HANDLE_VALUE on failure.
208  */
209 HANDLE WINAPI OpenConsoleW(LPCWSTR name, DWORD access, BOOL inherit, DWORD creation)
210 {
211     static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
212     static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
213     BOOL        output;
214     HANDLE ret;
215
216     if (strcmpiW(coninW, name) == 0) 
217         output = FALSE;
218     else if (strcmpiW(conoutW, name) == 0) 
219         output = TRUE;
220     else
221     {
222         SetLastError(ERROR_INVALID_NAME);
223         return INVALID_HANDLE_VALUE;
224     }
225     if (creation != OPEN_EXISTING)
226     {
227         SetLastError(ERROR_INVALID_PARAMETER);
228         return INVALID_HANDLE_VALUE;
229     }
230
231     SERVER_START_REQ( open_console )
232     {
233         req->from    = output;
234         req->access  = access;
235         req->share   = FILE_SHARE_READ | FILE_SHARE_WRITE;
236         req->inherit = inherit;
237         SetLastError(0);
238         wine_server_call_err( req );
239         ret = reply->handle;
240     }
241     SERVER_END_REQ;
242     return ret ? console_handle_map(ret) : INVALID_HANDLE_VALUE;
243 }
244
245 /******************************************************************
246  *              VerifyConsoleIoHandle            (KERNEL32.@)
247  *
248  * Undocumented
249  */
250 BOOL WINAPI VerifyConsoleIoHandle(HANDLE handle)
251 {
252     BOOL ret;
253
254     if (!is_console_handle(handle)) return FALSE;
255     SERVER_START_REQ(get_console_mode)
256     {
257         req->handle = console_handle_unmap(handle);
258         ret = !wine_server_call_err( req );
259     }
260     SERVER_END_REQ;
261     return ret;
262 }
263
264 /******************************************************************
265  *              DuplicateConsoleHandle            (KERNEL32.@)
266  *
267  * Undocumented
268  */
269 HANDLE WINAPI DuplicateConsoleHandle(HANDLE handle, DWORD access, BOOL inherit,
270                                      DWORD options)
271 {
272     HANDLE      ret;
273
274     if (!is_console_handle(handle) ||
275         !DuplicateHandle(GetCurrentProcess(), console_handle_unmap(handle), 
276                          GetCurrentProcess(), &ret, access, inherit, options))
277         return INVALID_HANDLE_VALUE;
278     return console_handle_map(ret);
279 }
280
281 /******************************************************************
282  *              CloseConsoleHandle            (KERNEL32.@)
283  *
284  * Undocumented
285  */
286 BOOL WINAPI CloseConsoleHandle(HANDLE handle)
287 {
288     if (!is_console_handle(handle)) 
289     {
290         SetLastError(ERROR_INVALID_PARAMETER);
291         return FALSE;
292     }
293     return CloseHandle(console_handle_unmap(handle));
294 }
295
296 /******************************************************************
297  *              GetConsoleInputWaitHandle            (KERNEL32.@)
298  *
299  * Undocumented
300  */
301 HANDLE WINAPI GetConsoleInputWaitHandle(void)
302 {
303     static HANDLE console_wait_event;
304  
305     /* FIXME: this is not thread safe */
306     if (!console_wait_event)
307     {
308         SERVER_START_REQ(get_console_wait_event)
309         {
310             if (!wine_server_call_err( req )) console_wait_event = reply->handle;
311         }
312         SERVER_END_REQ;
313     }
314     return console_wait_event;
315 }
316
317
318 /******************************************************************************
319  * WriteConsoleInputA [KERNEL32.@]
320  */
321 BOOL WINAPI WriteConsoleInputA( HANDLE handle, const INPUT_RECORD *buffer,
322                                 DWORD count, LPDWORD written )
323 {
324     INPUT_RECORD *recW;
325     BOOL ret;
326
327     if (!(recW = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*recW) ))) return FALSE;
328     memcpy( recW, buffer, count*sizeof(*recW) );
329     input_records_AtoW( recW, count );
330     ret = WriteConsoleInputW( handle, recW, count, written );
331     HeapFree( GetProcessHeap(), 0, recW );
332     return ret;
333 }
334
335
336 /******************************************************************************
337  * WriteConsoleInputW [KERNEL32.@]
338  */
339 BOOL WINAPI WriteConsoleInputW( HANDLE handle, const INPUT_RECORD *buffer,
340                                 DWORD count, LPDWORD written )
341 {
342     BOOL ret;
343
344     TRACE("(%p,%p,%ld,%p)\n", handle, buffer, count, written);
345
346     if (written) *written = 0;
347     SERVER_START_REQ( write_console_input )
348     {
349         req->handle = console_handle_unmap(handle);
350         wine_server_add_data( req, buffer, count * sizeof(INPUT_RECORD) );
351         if ((ret = !wine_server_call_err( req )) && written)
352             *written = reply->written;
353     }
354     SERVER_END_REQ;
355
356     return ret;
357 }
358
359
360 /***********************************************************************
361  *            WriteConsoleOutputA   (KERNEL32.@)
362  */
363 BOOL WINAPI WriteConsoleOutputA( HANDLE hConsoleOutput, const CHAR_INFO *lpBuffer,
364                                  COORD size, COORD coord, LPSMALL_RECT region )
365 {
366     int y;
367     BOOL ret;
368     COORD new_size, new_coord;
369     CHAR_INFO *ciw;
370
371     new_size.X = min( region->Right - region->Left + 1, size.X - coord.X );
372     new_size.Y = min( region->Bottom - region->Top + 1, size.Y - coord.Y );
373
374     if (new_size.X <= 0 || new_size.Y <= 0)
375     {
376         region->Bottom = region->Top + new_size.Y - 1;
377         region->Right = region->Left + new_size.X - 1;
378         return TRUE;
379     }
380
381     /* only copy the useful rectangle */
382     if (!(ciw = HeapAlloc( GetProcessHeap(), 0, sizeof(CHAR_INFO) * new_size.X * new_size.Y )))
383         return FALSE;
384     for (y = 0; y < new_size.Y; y++)
385     {
386         memcpy( &ciw[y * new_size.X], &lpBuffer[(y + coord.Y) * size.X + coord.X],
387                 new_size.X * sizeof(CHAR_INFO) );
388         char_info_AtoW( &ciw[ y * new_size.X ], new_size.X );
389     }
390     new_coord.X = new_coord.Y = 0;
391     ret = WriteConsoleOutputW( hConsoleOutput, ciw, new_size, new_coord, region );
392     HeapFree( GetProcessHeap(), 0, ciw );
393     return ret;
394 }
395
396
397 /***********************************************************************
398  *            WriteConsoleOutputW   (KERNEL32.@)
399  */
400 BOOL WINAPI WriteConsoleOutputW( HANDLE hConsoleOutput, const CHAR_INFO *lpBuffer,
401                                  COORD size, COORD coord, LPSMALL_RECT region )
402 {
403     int width, height, y;
404     BOOL ret = TRUE;
405
406     TRACE("(%p,%p,(%d,%d),(%d,%d),(%d,%dx%d,%d)\n",
407           hConsoleOutput, lpBuffer, size.X, size.Y, coord.X, coord.Y,
408           region->Left, region->Top, region->Right, region->Bottom);
409
410     width = min( region->Right - region->Left + 1, size.X - coord.X );
411     height = min( region->Bottom - region->Top + 1, size.Y - coord.Y );
412
413     if (width > 0 && height > 0)
414     {
415         for (y = 0; y < height; y++)
416         {
417             SERVER_START_REQ( write_console_output )
418             {
419                 req->handle = console_handle_unmap(hConsoleOutput);
420                 req->x      = region->Left;
421                 req->y      = region->Top + y;
422                 req->mode   = CHAR_INFO_MODE_TEXTATTR;
423                 req->wrap   = FALSE;
424                 wine_server_add_data( req, &lpBuffer[(y + coord.Y) * size.X + coord.X],
425                                       width * sizeof(CHAR_INFO));
426                 if ((ret = !wine_server_call_err( req )))
427                 {
428                     width  = min( width, reply->width - region->Left );
429                     height = min( height, reply->height - region->Top );
430                 }
431             }
432             SERVER_END_REQ;
433             if (!ret) break;
434         }
435     }
436     region->Bottom = region->Top + height - 1;
437     region->Right = region->Left + width - 1;
438     return ret;
439 }
440
441
442 /******************************************************************************
443  * WriteConsoleOutputCharacterA [KERNEL32.@]  Copies character to consecutive
444  *                                            cells in the console screen buffer
445  *
446  * PARAMS
447  *    hConsoleOutput    [I] Handle to screen buffer
448  *    str               [I] Pointer to buffer with chars to write
449  *    length            [I] Number of cells to write to
450  *    coord             [I] Coords of first cell
451  *    lpNumCharsWritten [O] Pointer to number of cells written
452  */
453 BOOL WINAPI WriteConsoleOutputCharacterA( HANDLE hConsoleOutput, LPCSTR str, DWORD length,
454                                           COORD coord, LPDWORD lpNumCharsWritten )
455 {
456     BOOL ret;
457     LPWSTR strW;
458     DWORD lenW;
459
460     TRACE("(%p,%s,%ld,%dx%d,%p)\n", hConsoleOutput,
461           debugstr_an(str, length), length, coord.X, coord.Y, lpNumCharsWritten);
462
463     lenW = MultiByteToWideChar( GetConsoleOutputCP(), 0, str, length, NULL, 0 );
464
465     if (lpNumCharsWritten) *lpNumCharsWritten = 0;
466
467     if (!(strW = HeapAlloc( GetProcessHeap(), 0, lenW * sizeof(WCHAR) ))) return FALSE;
468     MultiByteToWideChar( GetConsoleOutputCP(), 0, str, length, strW, lenW );
469
470     ret = WriteConsoleOutputCharacterW( hConsoleOutput, strW, lenW, coord, lpNumCharsWritten );
471     HeapFree( GetProcessHeap(), 0, strW );
472     return ret;
473 }
474
475
476 /******************************************************************************
477  * WriteConsoleOutputAttribute [KERNEL32.@]  Sets attributes for some cells in
478  *                                           the console screen buffer
479  *
480  * PARAMS
481  *    hConsoleOutput    [I] Handle to screen buffer
482  *    attr              [I] Pointer to buffer with write attributes
483  *    length            [I] Number of cells to write to
484  *    coord             [I] Coords of first cell
485  *    lpNumAttrsWritten [O] Pointer to number of cells written
486  *
487  * RETURNS
488  *    Success: TRUE
489  *    Failure: FALSE
490  *
491  */
492 BOOL WINAPI WriteConsoleOutputAttribute( HANDLE hConsoleOutput, CONST WORD *attr, DWORD length,
493                                          COORD coord, LPDWORD lpNumAttrsWritten )
494 {
495     BOOL ret;
496
497     TRACE("(%p,%p,%ld,%dx%d,%p)\n", hConsoleOutput,attr,length,coord.X,coord.Y,lpNumAttrsWritten);
498
499     SERVER_START_REQ( write_console_output )
500     {
501         req->handle = console_handle_unmap(hConsoleOutput);
502         req->x      = coord.X;
503         req->y      = coord.Y;
504         req->mode   = CHAR_INFO_MODE_ATTR;
505         req->wrap   = TRUE;
506         wine_server_add_data( req, attr, length * sizeof(WORD) );
507         if ((ret = !wine_server_call_err( req )))
508         {
509             if (lpNumAttrsWritten) *lpNumAttrsWritten = reply->written;
510         }
511     }
512     SERVER_END_REQ;
513     return ret;
514 }
515
516
517 /******************************************************************************
518  * FillConsoleOutputCharacterA [KERNEL32.@]
519  *
520  * PARAMS
521  *    hConsoleOutput    [I] Handle to screen buffer
522  *    ch                [I] Character to write
523  *    length            [I] Number of cells to write to
524  *    coord             [I] Coords of first cell
525  *    lpNumCharsWritten [O] Pointer to number of cells written
526  *
527  * RETURNS
528  *    Success: TRUE
529  *    Failure: FALSE
530  */
531 BOOL WINAPI FillConsoleOutputCharacterA( HANDLE hConsoleOutput, CHAR ch, DWORD length,
532                                          COORD coord, LPDWORD lpNumCharsWritten )
533 {
534     WCHAR wch;
535
536     MultiByteToWideChar( GetConsoleOutputCP(), 0, &ch, 1, &wch, 1 );
537     return FillConsoleOutputCharacterW(hConsoleOutput, wch, length, coord, lpNumCharsWritten);
538 }
539
540
541 /******************************************************************************
542  * FillConsoleOutputCharacterW [KERNEL32.@]  Writes characters to console
543  *
544  * PARAMS
545  *    hConsoleOutput    [I] Handle to screen buffer
546  *    ch                [I] Character to write
547  *    length            [I] Number of cells to write to
548  *    coord             [I] Coords of first cell
549  *    lpNumCharsWritten [O] Pointer to number of cells written
550  *
551  * RETURNS
552  *    Success: TRUE
553  *    Failure: FALSE
554  */
555 BOOL WINAPI FillConsoleOutputCharacterW( HANDLE hConsoleOutput, WCHAR ch, DWORD length,
556                                          COORD coord, LPDWORD lpNumCharsWritten)
557 {
558     BOOL ret;
559
560     TRACE("(%p,%s,%ld,(%dx%d),%p)\n",
561           hConsoleOutput, debugstr_wn(&ch, 1), length, coord.X, coord.Y, lpNumCharsWritten);
562
563     SERVER_START_REQ( fill_console_output )
564     {
565         req->handle  = console_handle_unmap(hConsoleOutput);
566         req->x       = coord.X;
567         req->y       = coord.Y;
568         req->mode    = CHAR_INFO_MODE_TEXT;
569         req->wrap    = TRUE;
570         req->data.ch = ch;
571         req->count   = length;
572         if ((ret = !wine_server_call_err( req )))
573         {
574             if (lpNumCharsWritten) *lpNumCharsWritten = reply->written;
575         }
576     }
577     SERVER_END_REQ;
578     return ret;
579 }
580
581
582 /******************************************************************************
583  * FillConsoleOutputAttribute [KERNEL32.@]  Sets attributes for console
584  *
585  * PARAMS
586  *    hConsoleOutput    [I] Handle to screen buffer
587  *    attr              [I] Color attribute to write
588  *    length            [I] Number of cells to write to
589  *    coord             [I] Coords of first cell
590  *    lpNumAttrsWritten [O] Pointer to number of cells written
591  *
592  * RETURNS
593  *    Success: TRUE
594  *    Failure: FALSE
595  */
596 BOOL WINAPI FillConsoleOutputAttribute( HANDLE hConsoleOutput, WORD attr, DWORD length,
597                                         COORD coord, LPDWORD lpNumAttrsWritten )
598 {
599     BOOL ret;
600
601     TRACE("(%p,%d,%ld,(%dx%d),%p)\n",
602           hConsoleOutput, attr, length, coord.X, coord.Y, lpNumAttrsWritten);
603
604     SERVER_START_REQ( fill_console_output )
605     {
606         req->handle    = console_handle_unmap(hConsoleOutput);
607         req->x         = coord.X;
608         req->y         = coord.Y;
609         req->mode      = CHAR_INFO_MODE_ATTR;
610         req->wrap      = TRUE;
611         req->data.attr = attr;
612         req->count     = length;
613         if ((ret = !wine_server_call_err( req )))
614         {
615             if (lpNumAttrsWritten) *lpNumAttrsWritten = reply->written;
616         }
617     }
618     SERVER_END_REQ;
619     return ret;
620 }
621
622
623 /******************************************************************************
624  * ReadConsoleOutputCharacterA [KERNEL32.@]
625  *
626  */
627 BOOL WINAPI ReadConsoleOutputCharacterA(HANDLE hConsoleOutput, LPSTR lpstr, DWORD count,
628                                         COORD coord, LPDWORD read_count)
629 {
630     DWORD read;
631     BOOL ret;
632     LPWSTR wptr = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
633
634     if (read_count) *read_count = 0;
635     if (!wptr) return FALSE;
636
637     if ((ret = ReadConsoleOutputCharacterW( hConsoleOutput, wptr, count, coord, &read )))
638     {
639         read = WideCharToMultiByte( GetConsoleOutputCP(), 0, wptr, read, lpstr, count, NULL, NULL);
640         if (read_count) *read_count = read;
641     }
642     HeapFree( GetProcessHeap(), 0, wptr );
643     return ret;
644 }
645
646
647 /******************************************************************************
648  * ReadConsoleOutputCharacterW [KERNEL32.@]
649  *
650  */
651 BOOL WINAPI ReadConsoleOutputCharacterW( HANDLE hConsoleOutput, LPWSTR buffer, DWORD count,
652                                          COORD coord, LPDWORD read_count )
653 {
654     BOOL ret;
655
656     TRACE( "(%p,%p,%ld,%dx%d,%p)\n", hConsoleOutput, buffer, count, coord.X, coord.Y, read_count );
657
658     SERVER_START_REQ( read_console_output )
659     {
660         req->handle = console_handle_unmap(hConsoleOutput);
661         req->x      = coord.X;
662         req->y      = coord.Y;
663         req->mode   = CHAR_INFO_MODE_TEXT;
664         req->wrap   = TRUE;
665         wine_server_set_reply( req, buffer, count * sizeof(WCHAR) );
666         if ((ret = !wine_server_call_err( req )))
667         {
668             if (read_count) *read_count = wine_server_reply_size(reply) / sizeof(WCHAR);
669         }
670     }
671     SERVER_END_REQ;
672     return ret;
673 }
674
675
676 /******************************************************************************
677  *  ReadConsoleOutputAttribute [KERNEL32.@]
678  */
679 BOOL WINAPI ReadConsoleOutputAttribute(HANDLE hConsoleOutput, LPWORD lpAttribute, DWORD length,
680                                        COORD coord, LPDWORD read_count)
681 {
682     BOOL ret;
683
684     TRACE("(%p,%p,%ld,%dx%d,%p)\n",
685           hConsoleOutput, lpAttribute, length, coord.X, coord.Y, read_count);
686
687     SERVER_START_REQ( read_console_output )
688     {
689         req->handle = console_handle_unmap(hConsoleOutput);
690         req->x      = coord.X;
691         req->y      = coord.Y;
692         req->mode   = CHAR_INFO_MODE_ATTR;
693         req->wrap   = TRUE;
694         wine_server_set_reply( req, lpAttribute, length * sizeof(WORD) );
695         if ((ret = !wine_server_call_err( req )))
696         {
697             if (read_count) *read_count = wine_server_reply_size(reply) / sizeof(WORD);
698         }
699     }
700     SERVER_END_REQ;
701     return ret;
702 }
703
704
705 /******************************************************************************
706  *  ReadConsoleOutputA [KERNEL32.@]
707  *
708  */
709 BOOL WINAPI ReadConsoleOutputA( HANDLE hConsoleOutput, LPCHAR_INFO lpBuffer, COORD size,
710                                 COORD coord, LPSMALL_RECT region )
711 {
712     BOOL ret;
713     int y;
714
715     ret = ReadConsoleOutputW( hConsoleOutput, lpBuffer, size, coord, region );
716     if (ret && region->Right >= region->Left)
717     {
718         for (y = 0; y <= region->Bottom - region->Top; y++)
719         {
720             char_info_WtoA( &lpBuffer[(coord.Y + y) * size.X + coord.X],
721                             region->Right - region->Left + 1 );
722         }
723     }
724     return ret;
725 }
726
727
728 /******************************************************************************
729  *  ReadConsoleOutputW [KERNEL32.@]
730  *
731  * NOTE: The NT4 (sp5) kernel crashes on me if size is (0,0). I don't
732  * think we need to be *that* compatible.  -- AJ
733  */
734 BOOL WINAPI ReadConsoleOutputW( HANDLE hConsoleOutput, LPCHAR_INFO lpBuffer, COORD size,
735                                 COORD coord, LPSMALL_RECT region )
736 {
737     int width, height, y;
738     BOOL ret = TRUE;
739
740     width = min( region->Right - region->Left + 1, size.X - coord.X );
741     height = min( region->Bottom - region->Top + 1, size.Y - coord.Y );
742
743     if (width > 0 && height > 0)
744     {
745         for (y = 0; y < height; y++)
746         {
747             SERVER_START_REQ( read_console_output )
748             {
749                 req->handle = console_handle_unmap(hConsoleOutput);
750                 req->x      = region->Left;
751                 req->y      = region->Top + y;
752                 req->mode   = CHAR_INFO_MODE_TEXTATTR;
753                 req->wrap   = FALSE;
754                 wine_server_set_reply( req, &lpBuffer[(y+coord.Y) * size.X + coord.X],
755                                        width * sizeof(CHAR_INFO) );
756                 if ((ret = !wine_server_call_err( req )))
757                 {
758                     width  = min( width, reply->width - region->Left );
759                     height = min( height, reply->height - region->Top );
760                 }
761             }
762             SERVER_END_REQ;
763             if (!ret) break;
764         }
765     }
766     region->Bottom = region->Top + height - 1;
767     region->Right = region->Left + width - 1;
768     return ret;
769 }
770
771
772 /******************************************************************************
773  * ReadConsoleInputA [KERNEL32.@]  Reads data from a console
774  *
775  * PARAMS
776  *    handle   [I] Handle to console input buffer
777  *    buffer   [O] Address of buffer for read data
778  *    count    [I] Number of records to read
779  *    pRead    [O] Address of number of records read
780  *
781  * RETURNS
782  *    Success: TRUE
783  *    Failure: FALSE
784  */
785 BOOL WINAPI ReadConsoleInputA( HANDLE handle, PINPUT_RECORD buffer, DWORD count, LPDWORD pRead )
786 {
787     DWORD read;
788
789     if (!ReadConsoleInputW( handle, buffer, count, &read )) return FALSE;
790     input_records_WtoA( buffer, read );
791     if (pRead) *pRead = read;
792     return TRUE;
793 }
794
795
796 /***********************************************************************
797  *            PeekConsoleInputA   (KERNEL32.@)
798  *
799  * Gets 'count' first events (or less) from input queue.
800  */
801 BOOL WINAPI PeekConsoleInputA( HANDLE handle, PINPUT_RECORD buffer, DWORD count, LPDWORD pRead )
802 {
803     DWORD read;
804
805     if (!PeekConsoleInputW( handle, buffer, count, &read )) return FALSE;
806     input_records_WtoA( buffer, read );
807     if (pRead) *pRead = read;
808     return TRUE;
809 }
810
811
812 /***********************************************************************
813  *            PeekConsoleInputW   (KERNEL32.@)
814  */
815 BOOL WINAPI PeekConsoleInputW( HANDLE handle, PINPUT_RECORD buffer, DWORD count, LPDWORD read )
816 {
817     BOOL ret;
818     SERVER_START_REQ( read_console_input )
819     {
820         req->handle = console_handle_unmap(handle);
821         req->flush  = FALSE;
822         wine_server_set_reply( req, buffer, count * sizeof(INPUT_RECORD) );
823         if ((ret = !wine_server_call_err( req )))
824         {
825             if (read) *read = count ? reply->read : 0;
826         }
827     }
828     SERVER_END_REQ;
829     return ret;
830 }
831
832
833 /***********************************************************************
834  *            GetNumberOfConsoleInputEvents   (KERNEL32.@)
835  */
836 BOOL WINAPI GetNumberOfConsoleInputEvents( HANDLE handle, LPDWORD nrofevents )
837 {
838     BOOL ret;
839     SERVER_START_REQ( read_console_input )
840     {
841         req->handle = console_handle_unmap(handle);
842         req->flush  = FALSE;
843         if ((ret = !wine_server_call_err( req )))
844         {
845             if (nrofevents) *nrofevents = reply->read;
846         }
847     }
848     SERVER_END_REQ;
849     return ret;
850 }
851
852
853 /******************************************************************************
854  * read_console_input
855  *
856  * Helper function for ReadConsole, ReadConsoleInput and FlushConsoleInputBuffer
857  *
858  * Returns 
859  *      0 for error, 1 for no INPUT_RECORD ready, 2 with INPUT_RECORD ready
860  */
861 enum read_console_input_return {rci_error = 0, rci_timeout = 1, rci_gotone = 2};
862 static enum read_console_input_return read_console_input(HANDLE handle, PINPUT_RECORD ir, DWORD timeout)
863 {
864     enum read_console_input_return      ret;
865
866     if (WaitForSingleObject(GetConsoleInputWaitHandle(), timeout) != WAIT_OBJECT_0)
867         return rci_timeout;
868     SERVER_START_REQ( read_console_input )
869     {
870         req->handle = console_handle_unmap(handle);
871         req->flush = TRUE;
872         wine_server_set_reply( req, ir, sizeof(INPUT_RECORD) );
873         if (wine_server_call_err( req ) || !reply->read) ret = rci_error;
874         else ret = rci_gotone;
875     }
876     SERVER_END_REQ;
877
878     return ret;
879 }
880
881
882 /***********************************************************************
883  *            FlushConsoleInputBuffer   (KERNEL32.@)
884  */
885 BOOL WINAPI FlushConsoleInputBuffer( HANDLE handle )
886 {
887     enum read_console_input_return      last;
888     INPUT_RECORD                        ir;
889
890     while ((last = read_console_input(handle, &ir, 0)) == rci_gotone);
891
892     return last == rci_timeout;
893 }
894
895
896 /***********************************************************************
897  *            SetConsoleTitleA   (KERNEL32.@)
898  */
899 BOOL WINAPI SetConsoleTitleA( LPCSTR title )
900 {
901     LPWSTR titleW;
902     BOOL ret;
903
904     DWORD len = MultiByteToWideChar( GetConsoleOutputCP(), 0, title, -1, NULL, 0 );
905     if (!(titleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) return FALSE;
906     MultiByteToWideChar( GetConsoleOutputCP(), 0, title, -1, titleW, len );
907     ret = SetConsoleTitleW(titleW);
908     HeapFree(GetProcessHeap(), 0, titleW);
909     return ret;
910 }
911
912
913 /***********************************************************************
914  *            GetConsoleTitleA   (KERNEL32.@)
915  */
916 DWORD WINAPI GetConsoleTitleA(LPSTR title, DWORD size)
917 {
918     WCHAR *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * size);
919     DWORD ret;
920
921     if (!ptr) return 0;
922     ret = GetConsoleTitleW( ptr, size );
923     if (ret)
924     {
925         WideCharToMultiByte( GetConsoleOutputCP(), 0, ptr, ret + 1, title, size, NULL, NULL);
926         ret = strlen(title);
927     }
928     HeapFree(GetProcessHeap(), 0, ptr);
929     return ret;
930 }
931
932
933 /******************************************************************************
934  * GetConsoleTitleW [KERNEL32.@]  Retrieves title string for console
935  *
936  * PARAMS
937  *    title [O] Address of buffer for title
938  *    size  [I] Size of buffer
939  *
940  * RETURNS
941  *    Success: Length of string copied
942  *    Failure: 0
943  */
944 DWORD WINAPI GetConsoleTitleW(LPWSTR title, DWORD size)
945 {
946     DWORD ret = 0;
947
948     SERVER_START_REQ( get_console_input_info )
949     {
950         req->handle = 0;
951         wine_server_set_reply( req, title, (size-1) * sizeof(WCHAR) );
952         if (!wine_server_call_err( req ))
953         {
954             ret = wine_server_reply_size(reply) / sizeof(WCHAR);
955             title[ret] = 0;
956         }
957     }
958     SERVER_END_REQ;
959     return ret;
960 }
961
962
963 /***********************************************************************
964  *            GetLargestConsoleWindowSize   (KERNEL32.@)
965  *
966  * NOTE
967  *      This should return a COORD, but calling convention for returning
968  *      structures is different between Windows and gcc on i386.
969  *
970  * VERSION: [i386]
971  */
972 #ifdef __i386__
973 #undef GetLargestConsoleWindowSize
974 DWORD WINAPI GetLargestConsoleWindowSize(HANDLE hConsoleOutput)
975 {
976     union {
977         COORD c;
978         DWORD w;
979     } x;
980     x.c.X = 80;
981     x.c.Y = 24;
982     TRACE("(%p), returning %dx%d (%lx)\n", hConsoleOutput, x.c.X, x.c.Y, x.w);
983     return x.w;
984 }
985 #endif /* defined(__i386__) */
986
987
988 /***********************************************************************
989  *            GetLargestConsoleWindowSize   (KERNEL32.@)
990  *
991  * NOTE
992  *      This should return a COORD, but calling convention for returning
993  *      structures is different between Windows and gcc on i386.
994  *
995  * VERSION: [!i386]
996  */
997 #ifndef __i386__
998 COORD WINAPI GetLargestConsoleWindowSize(HANDLE hConsoleOutput)
999 {
1000     COORD c;
1001     c.X = 80;
1002     c.Y = 24;
1003     TRACE("(%p), returning %dx%d\n", hConsoleOutput, c.X, c.Y);
1004     return c;
1005 }
1006 #endif /* defined(__i386__) */
1007
1008 static WCHAR*   S_EditString /* = NULL */;
1009 static unsigned S_EditStrPos /* = 0 */;
1010
1011 /***********************************************************************
1012  *            FreeConsole (KERNEL32.@)
1013  */
1014 BOOL WINAPI FreeConsole(VOID)
1015 {
1016     BOOL ret;
1017
1018     SERVER_START_REQ(free_console)
1019     {
1020         ret = !wine_server_call_err( req );
1021     }
1022     SERVER_END_REQ;
1023     return ret;
1024 }
1025
1026 /******************************************************************
1027  *              start_console_renderer
1028  *
1029  * helper for AllocConsole
1030  * starts the renderer process
1031  */
1032 static  BOOL    start_console_renderer_helper(const char* appname, STARTUPINFOA* si,
1033                                               HANDLE hEvent)
1034 {
1035     char                buffer[1024];
1036     int                 ret;
1037     PROCESS_INFORMATION pi;
1038
1039     /* FIXME: use dynamic allocation for most of the buffers below */
1040     ret = snprintf(buffer, sizeof(buffer), "%s --use-event=%d", appname, (INT)hEvent);
1041     if ((ret > -1) && (ret < sizeof(buffer)) &&
1042         CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS,
1043                        NULL, NULL, si, &pi))
1044     {
1045         if (WaitForSingleObject(hEvent, INFINITE) != WAIT_OBJECT_0) return FALSE;
1046
1047         TRACE("Started wineconsole pid=%08lx tid=%08lx\n",
1048               pi.dwProcessId, pi.dwThreadId);
1049
1050         return TRUE;
1051     }
1052     return FALSE;
1053 }
1054
1055 static  BOOL    start_console_renderer(STARTUPINFOA* si)
1056 {
1057     HANDLE              hEvent = 0;
1058     LPSTR               p;
1059     OBJECT_ATTRIBUTES   attr;
1060     BOOL                ret = FALSE;
1061
1062     attr.Length                   = sizeof(attr);
1063     attr.RootDirectory            = 0;
1064     attr.Attributes               = OBJ_INHERIT;
1065     attr.ObjectName               = NULL;
1066     attr.SecurityDescriptor       = NULL;
1067     attr.SecurityQualityOfService = NULL;
1068
1069     NtCreateEvent(&hEvent, EVENT_ALL_ACCESS, &attr, TRUE, FALSE);
1070     if (!hEvent) return FALSE;
1071
1072     /* first try environment variable */
1073     if ((p = getenv("WINECONSOLE")) != NULL)
1074     {
1075         ret = start_console_renderer_helper(p, si, hEvent);
1076         if (!ret)
1077             ERR("Couldn't launch Wine console from WINECONSOLE env var (%s)... "
1078                 "trying default access\n", p);
1079     }
1080
1081     /* then try the regular PATH */
1082     if (!ret)
1083         ret = start_console_renderer_helper("wineconsole", si, hEvent);
1084
1085     CloseHandle(hEvent);
1086     return ret;
1087 }
1088
1089 /***********************************************************************
1090  *            AllocConsole (KERNEL32.@)
1091  *
1092  * creates an xterm with a pty to our program
1093  */
1094 BOOL WINAPI AllocConsole(void)
1095 {
1096     HANDLE              handle_in = INVALID_HANDLE_VALUE;
1097     HANDLE              handle_out = INVALID_HANDLE_VALUE;
1098     HANDLE              handle_err = INVALID_HANDLE_VALUE;
1099     STARTUPINFOA        siCurrent;
1100     STARTUPINFOA        siConsole;
1101     char                buffer[1024];
1102     SECURITY_ATTRIBUTES sa;
1103
1104     TRACE("()\n");
1105
1106     handle_in = CreateFileA( "CONIN$", GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,
1107                              0, NULL, OPEN_EXISTING, 0, 0 );
1108
1109     if (handle_in != INVALID_HANDLE_VALUE)
1110     {
1111         /* we already have a console opened on this process, don't create a new one */
1112         CloseHandle(handle_in);
1113         return FALSE;
1114     }
1115
1116     GetStartupInfoA(&siCurrent);
1117
1118     memset(&siConsole, 0, sizeof(siConsole));
1119     siConsole.cb = sizeof(siConsole);
1120     /* setup a view arguments for wineconsole (it'll use them as default values)  */
1121     if (siCurrent.dwFlags & STARTF_USECOUNTCHARS)
1122     {
1123         siConsole.dwFlags |= STARTF_USECOUNTCHARS;
1124         siConsole.dwXCountChars = siCurrent.dwXCountChars;
1125         siConsole.dwYCountChars = siCurrent.dwYCountChars;
1126     }
1127     if (siCurrent.dwFlags & STARTF_USEFILLATTRIBUTE)
1128     {
1129         siConsole.dwFlags |= STARTF_USEFILLATTRIBUTE;
1130         siConsole.dwFillAttribute = siCurrent.dwFillAttribute;
1131     }
1132     if (siCurrent.dwFlags & STARTF_USESHOWWINDOW)
1133     {
1134         siConsole.dwFlags |= STARTF_USESHOWWINDOW;
1135         siConsole.wShowWindow = siCurrent.wShowWindow;
1136     }
1137     /* FIXME (should pass the unicode form) */
1138     if (siCurrent.lpTitle)
1139         siConsole.lpTitle = siCurrent.lpTitle;
1140     else if (GetModuleFileNameA(0, buffer, sizeof(buffer)))
1141     {
1142         buffer[sizeof(buffer) - 1] = '\0';
1143         siConsole.lpTitle = buffer;
1144     }
1145
1146     if (!start_console_renderer(&siConsole))
1147         goto the_end;
1148
1149     if( !(siCurrent.dwFlags & STARTF_USESTDHANDLES) ) {
1150         /* all std I/O handles are inheritable by default */
1151         sa.nLength = sizeof(sa);
1152         sa.lpSecurityDescriptor = NULL;
1153         sa.bInheritHandle = TRUE;
1154   
1155         handle_in = CreateFileA( "CONIN$", GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,
1156                 0, &sa, OPEN_EXISTING, 0, 0 );
1157         if (handle_in == INVALID_HANDLE_VALUE) goto the_end;
1158   
1159         handle_out = CreateFileA( "CONOUT$", GENERIC_READ|GENERIC_WRITE,
1160                                   0, &sa, OPEN_EXISTING, 0, 0 );
1161         if (handle_out == INVALID_HANDLE_VALUE) goto the_end;
1162   
1163         if (!DuplicateHandle(GetCurrentProcess(), handle_out, GetCurrentProcess(),
1164                     &handle_err, 0, TRUE, DUPLICATE_SAME_ACCESS))
1165             goto the_end;
1166     } else {
1167         /*  STARTF_USESTDHANDLES flag: use handles from StartupInfo */
1168         handle_in  =  siCurrent.hStdInput;
1169         handle_out =  siCurrent.hStdOutput;
1170         handle_err =  siCurrent.hStdError;
1171     }
1172
1173     /* NT resets the STD_*_HANDLEs on console alloc */
1174     SetStdHandle(STD_INPUT_HANDLE,  handle_in);
1175     SetStdHandle(STD_OUTPUT_HANDLE, handle_out);
1176     SetStdHandle(STD_ERROR_HANDLE,  handle_err);
1177
1178     SetLastError(ERROR_SUCCESS);
1179
1180     return TRUE;
1181
1182  the_end:
1183     ERR("Can't allocate console\n");
1184     if (handle_in != INVALID_HANDLE_VALUE)      CloseHandle(handle_in);
1185     if (handle_out != INVALID_HANDLE_VALUE)     CloseHandle(handle_out);
1186     if (handle_err != INVALID_HANDLE_VALUE)     CloseHandle(handle_err);
1187     FreeConsole();
1188     return FALSE;
1189 }
1190
1191
1192 /***********************************************************************
1193  *            ReadConsoleA   (KERNEL32.@)
1194  */
1195 BOOL WINAPI ReadConsoleA(HANDLE hConsoleInput, LPVOID lpBuffer, DWORD nNumberOfCharsToRead,
1196                          LPDWORD lpNumberOfCharsRead, LPVOID lpReserved)
1197 {
1198     LPWSTR      ptr = HeapAlloc(GetProcessHeap(), 0, nNumberOfCharsToRead * sizeof(WCHAR));
1199     DWORD       ncr = 0;
1200     BOOL        ret;
1201
1202     if ((ret = ReadConsoleW(hConsoleInput, ptr, nNumberOfCharsToRead, &ncr, NULL)))
1203         ncr = WideCharToMultiByte(CP_ACP, 0, ptr, ncr, lpBuffer, nNumberOfCharsToRead, NULL, NULL);
1204
1205     if (lpNumberOfCharsRead) *lpNumberOfCharsRead = ncr;
1206     HeapFree(GetProcessHeap(), 0, ptr);
1207
1208     return ret;
1209 }
1210
1211 /***********************************************************************
1212  *            ReadConsoleW   (KERNEL32.@)
1213  */
1214 BOOL WINAPI ReadConsoleW(HANDLE hConsoleInput, LPVOID lpBuffer,
1215                          DWORD nNumberOfCharsToRead, LPDWORD lpNumberOfCharsRead, LPVOID lpReserved)
1216 {
1217     DWORD       charsread;
1218     LPWSTR      xbuf = (LPWSTR)lpBuffer;
1219     DWORD       mode;
1220
1221     TRACE("(%p,%p,%ld,%p,%p)\n",
1222           hConsoleInput, lpBuffer, nNumberOfCharsToRead, lpNumberOfCharsRead, lpReserved);
1223
1224     if (!GetConsoleMode(hConsoleInput, &mode))
1225         return FALSE;
1226
1227     if (mode & ENABLE_LINE_INPUT)
1228     {
1229         if (!S_EditString || S_EditString[S_EditStrPos] == 0)
1230         {
1231             HeapFree(GetProcessHeap(), 0, S_EditString);
1232             if (!(S_EditString = CONSOLE_Readline(hConsoleInput)))
1233                 return FALSE;
1234             S_EditStrPos = 0;
1235         }
1236         charsread = lstrlenW(&S_EditString[S_EditStrPos]);
1237         if (charsread > nNumberOfCharsToRead) charsread = nNumberOfCharsToRead;
1238         memcpy(xbuf, &S_EditString[S_EditStrPos], charsread * sizeof(WCHAR));
1239         S_EditStrPos += charsread;
1240     }
1241     else
1242     {
1243         INPUT_RECORD    ir;
1244         DWORD           timeout = INFINITE;
1245
1246         /* FIXME: should we read at least 1 char? The SDK does not say */
1247         /* wait for at least one available input record (it doesn't mean we'll have
1248          * chars stored in xbuf...)
1249          */
1250         charsread = 0;
1251         do 
1252         {
1253             if (read_console_input(hConsoleInput, &ir, timeout) != rci_gotone) break;
1254             timeout = 0;
1255             if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown &&
1256                 ir.Event.KeyEvent.uChar.UnicodeChar &&
1257                 !(ir.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY))
1258             {
1259                 xbuf[charsread++] = ir.Event.KeyEvent.uChar.UnicodeChar;
1260             }
1261         } while (charsread < nNumberOfCharsToRead);
1262         /* nothing has been read */
1263         if (timeout == INFINITE) return FALSE;
1264     }
1265
1266     if (lpNumberOfCharsRead) *lpNumberOfCharsRead = charsread;
1267
1268     return TRUE;
1269 }
1270
1271
1272 /***********************************************************************
1273  *            ReadConsoleInputW   (KERNEL32.@)
1274  */
1275 BOOL WINAPI ReadConsoleInputW(HANDLE hConsoleInput, PINPUT_RECORD lpBuffer,
1276                               DWORD nLength, LPDWORD lpNumberOfEventsRead)
1277 {
1278     DWORD idx = 0;
1279     DWORD timeout = INFINITE;
1280
1281     if (!nLength)
1282     {
1283         if (lpNumberOfEventsRead) *lpNumberOfEventsRead = 0;
1284         return TRUE;
1285     }
1286
1287     /* loop until we get at least one event */
1288     while (read_console_input(hConsoleInput, &lpBuffer[idx], timeout) == rci_gotone &&
1289            ++idx < nLength)
1290         timeout = 0;
1291
1292     if (lpNumberOfEventsRead) *lpNumberOfEventsRead = idx;
1293     return idx != 0;
1294 }
1295
1296
1297 /******************************************************************************
1298  * WriteConsoleOutputCharacterW [KERNEL32.@]  Copies character to consecutive
1299  *                                            cells in the console screen buffer
1300  *
1301  * PARAMS
1302  *    hConsoleOutput    [I] Handle to screen buffer
1303  *    str               [I] Pointer to buffer with chars to write
1304  *    length            [I] Number of cells to write to
1305  *    coord             [I] Coords of first cell
1306  *    lpNumCharsWritten [O] Pointer to number of cells written
1307  *
1308  * RETURNS
1309  *    Success: TRUE
1310  *    Failure: FALSE
1311  *
1312  */
1313 BOOL WINAPI WriteConsoleOutputCharacterW( HANDLE hConsoleOutput, LPCWSTR str, DWORD length,
1314                                           COORD coord, LPDWORD lpNumCharsWritten )
1315 {
1316     BOOL ret;
1317
1318     TRACE("(%p,%s,%ld,%dx%d,%p)\n", hConsoleOutput,
1319           debugstr_wn(str, length), length, coord.X, coord.Y, lpNumCharsWritten);
1320
1321     SERVER_START_REQ( write_console_output )
1322     {
1323         req->handle = console_handle_unmap(hConsoleOutput);
1324         req->x      = coord.X;
1325         req->y      = coord.Y;
1326         req->mode   = CHAR_INFO_MODE_TEXT;
1327         req->wrap   = TRUE;
1328         wine_server_add_data( req, str, length * sizeof(WCHAR) );
1329         if ((ret = !wine_server_call_err( req )))
1330         {
1331             if (lpNumCharsWritten) *lpNumCharsWritten = reply->written;
1332         }
1333     }
1334     SERVER_END_REQ;
1335     return ret;
1336 }
1337
1338
1339 /******************************************************************************
1340  * SetConsoleTitleW [KERNEL32.@]  Sets title bar string for console
1341  *
1342  * PARAMS
1343  *    title [I] Address of new title
1344  *
1345  * RETURNS
1346  *    Success: TRUE
1347  *    Failure: FALSE
1348  */
1349 BOOL WINAPI SetConsoleTitleW(LPCWSTR title)
1350 {
1351     BOOL ret;
1352
1353     TRACE("(%s)\n", debugstr_w(title));
1354     SERVER_START_REQ( set_console_input_info )
1355     {
1356         req->handle = 0;
1357         req->mask = SET_CONSOLE_INPUT_INFO_TITLE;
1358         wine_server_add_data( req, title, strlenW(title) * sizeof(WCHAR) );
1359         ret = !wine_server_call_err( req );
1360     }
1361     SERVER_END_REQ;
1362     return ret;
1363 }
1364
1365
1366 /***********************************************************************
1367  *            GetNumberOfConsoleMouseButtons   (KERNEL32.@)
1368  */
1369 BOOL WINAPI GetNumberOfConsoleMouseButtons(LPDWORD nrofbuttons)
1370 {
1371     FIXME("(%p): stub\n", nrofbuttons);
1372     *nrofbuttons = 2;
1373     return TRUE;
1374 }
1375
1376 /******************************************************************************
1377  *  SetConsoleInputExeNameW      [KERNEL32.@]
1378  *
1379  * BUGS
1380  *   Unimplemented
1381  */
1382 BOOL WINAPI SetConsoleInputExeNameW(LPCWSTR name)
1383 {
1384     FIXME("(%s): stub!\n", debugstr_w(name));
1385
1386     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1387     return TRUE;
1388 }
1389
1390 /******************************************************************************
1391  *  SetConsoleInputExeNameA      [KERNEL32.@]
1392  *
1393  * BUGS
1394  *   Unimplemented
1395  */
1396 BOOL WINAPI SetConsoleInputExeNameA(LPCSTR name)
1397 {
1398     int         len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
1399     LPWSTR      xptr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1400     BOOL        ret;
1401
1402     if (!xptr) return FALSE;
1403
1404     MultiByteToWideChar(CP_ACP, 0, name, -1, xptr, len);
1405     ret = SetConsoleInputExeNameW(xptr);
1406     HeapFree(GetProcessHeap(), 0, xptr);
1407
1408     return ret;
1409 }
1410
1411 /******************************************************************
1412  *              CONSOLE_DefaultHandler
1413  *
1414  * Final control event handler
1415  */
1416 static BOOL WINAPI CONSOLE_DefaultHandler(DWORD dwCtrlType)
1417 {
1418     FIXME("Terminating process %lx on event %lx\n", GetCurrentProcessId(), dwCtrlType);
1419     ExitProcess(0);
1420     /* should never go here */
1421     return TRUE;
1422 }
1423
1424 /******************************************************************************
1425  * SetConsoleCtrlHandler [KERNEL32.@]  Adds function to calling process list
1426  *
1427  * PARAMS
1428  *    func [I] Address of handler function
1429  *    add  [I] Handler to add or remove
1430  *
1431  * RETURNS
1432  *    Success: TRUE
1433  *    Failure: FALSE
1434  */
1435
1436 struct ConsoleHandler
1437 {
1438     PHANDLER_ROUTINE            handler;
1439     struct ConsoleHandler*      next;
1440 };
1441
1442 static struct ConsoleHandler    CONSOLE_DefaultConsoleHandler = {CONSOLE_DefaultHandler, NULL};
1443 static struct ConsoleHandler*   CONSOLE_Handlers = &CONSOLE_DefaultConsoleHandler;
1444
1445 static CRITICAL_SECTION CONSOLE_CritSect;
1446 static CRITICAL_SECTION_DEBUG critsect_debug =
1447 {
1448     0, 0, &CONSOLE_CritSect,
1449     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
1450       0, 0, { 0, (DWORD)(__FILE__ ": CONSOLE_CritSect") }
1451 };
1452 static CRITICAL_SECTION CONSOLE_CritSect = { &critsect_debug, -1, 0, 0, 0, 0 };
1453
1454 /*****************************************************************************/
1455
1456 /******************************************************************
1457  *              SetConsoleCtrlHandler (KERNEL32.@)
1458  */
1459 BOOL WINAPI SetConsoleCtrlHandler(PHANDLER_ROUTINE func, BOOL add)
1460 {
1461     BOOL        ret = TRUE;
1462
1463     TRACE("(%p,%i)\n", func, add);
1464
1465     if (!func)
1466     {
1467         RtlEnterCriticalSection(&CONSOLE_CritSect);
1468         if (add)
1469             NtCurrentTeb()->Peb->ProcessParameters->ConsoleFlags |= 1;
1470         else
1471             NtCurrentTeb()->Peb->ProcessParameters->ConsoleFlags &= ~1;
1472         RtlLeaveCriticalSection(&CONSOLE_CritSect);
1473     }
1474     else if (add)
1475     {
1476         struct ConsoleHandler*  ch = HeapAlloc(GetProcessHeap(), 0, sizeof(struct ConsoleHandler));
1477
1478         if (!ch) return FALSE;
1479         ch->handler = func;
1480         RtlEnterCriticalSection(&CONSOLE_CritSect);
1481         ch->next = CONSOLE_Handlers;
1482         CONSOLE_Handlers = ch;
1483         RtlLeaveCriticalSection(&CONSOLE_CritSect);
1484     }
1485     else
1486     {
1487         struct ConsoleHandler**  ch;
1488         RtlEnterCriticalSection(&CONSOLE_CritSect);
1489         for (ch = &CONSOLE_Handlers; *ch; ch = &(*ch)->next)
1490         {
1491             if ((*ch)->handler == func) break;
1492         }
1493         if (*ch)
1494         {
1495             struct ConsoleHandler*   rch = *ch;
1496
1497             /* sanity check */
1498             if (rch == &CONSOLE_DefaultConsoleHandler)
1499             {
1500                 ERR("Who's trying to remove default handler???\n");
1501                 SetLastError(ERROR_INVALID_PARAMETER);
1502                 ret = FALSE;
1503             }
1504             else
1505             {
1506                 *ch = rch->next;
1507                 HeapFree(GetProcessHeap(), 0, rch);
1508             }
1509         }
1510         else
1511         {
1512             WARN("Attempt to remove non-installed CtrlHandler %p\n", func);
1513             SetLastError(ERROR_INVALID_PARAMETER);
1514             ret = FALSE;
1515         }
1516         RtlLeaveCriticalSection(&CONSOLE_CritSect);
1517     }
1518     return ret;
1519 }
1520
1521 static WINE_EXCEPTION_FILTER(CONSOLE_CtrlEventHandler)
1522 {
1523     TRACE("(%lx)\n", GetExceptionCode());
1524     return EXCEPTION_EXECUTE_HANDLER;
1525 }
1526
1527 /******************************************************************
1528  *              CONSOLE_SendEventThread
1529  *
1530  * Internal helper to pass an event to the list on installed handlers
1531  */
1532 static DWORD WINAPI CONSOLE_SendEventThread(void* pmt)
1533 {
1534     DWORD                       event = (DWORD)pmt;
1535     struct ConsoleHandler*      ch;
1536
1537     if (event == CTRL_C_EVENT)
1538     {
1539         BOOL    caught_by_dbg = TRUE;
1540         /* First, try to pass the ctrl-C event to the debugger (if any)
1541          * If it continues, there's nothing more to do
1542          * Otherwise, we need to send the ctrl-C event to the handlers
1543          */
1544         __TRY
1545         {
1546             RaiseException( DBG_CONTROL_C, 0, 0, NULL );
1547         }
1548         __EXCEPT(CONSOLE_CtrlEventHandler)
1549         {
1550             caught_by_dbg = FALSE;
1551         }
1552         __ENDTRY;
1553         if (caught_by_dbg) return 0;
1554         /* the debugger didn't continue... so, pass to ctrl handlers */
1555     }
1556     RtlEnterCriticalSection(&CONSOLE_CritSect);
1557     for (ch = CONSOLE_Handlers; ch; ch = ch->next)
1558     {
1559         if (ch->handler(event)) break;
1560     }
1561     RtlLeaveCriticalSection(&CONSOLE_CritSect);
1562     return 1;
1563 }
1564
1565 /******************************************************************
1566  *              CONSOLE_HandleCtrlC
1567  *
1568  * Check whether the shall manipulate CtrlC events
1569  */
1570 int     CONSOLE_HandleCtrlC(unsigned sig)
1571 {
1572     /* FIXME: better test whether a console is attached to this process ??? */
1573     extern    unsigned CONSOLE_GetNumHistoryEntries(void);
1574     if (CONSOLE_GetNumHistoryEntries() == (unsigned)-1) return 0;
1575
1576     /* check if we have to ignore ctrl-C events */
1577     if (!(NtCurrentTeb()->Peb->ProcessParameters->ConsoleFlags & 1))
1578     {
1579         /* Create a separate thread to signal all the events. 
1580          * This is needed because:
1581          *  - this function can be called in an Unix signal handler (hence on an
1582          *    different stack than the thread that's running). This breaks the 
1583          *    Win32 exception mechanisms (where the thread's stack is checked).
1584          *  - since the current thread, while processing the signal, can hold the
1585          *    console critical section, we need another execution environment where
1586          *    we can wait on this critical section 
1587          */
1588         CreateThread(NULL, 0, CONSOLE_SendEventThread, (void*)CTRL_C_EVENT, 0, NULL);
1589     }
1590     return 1;
1591 }
1592
1593 /******************************************************************************
1594  * GenerateConsoleCtrlEvent [KERNEL32.@] Simulate a CTRL-C or CTRL-BREAK
1595  *
1596  * PARAMS
1597  *    dwCtrlEvent        [I] Type of event
1598  *    dwProcessGroupID   [I] Process group ID to send event to
1599  *
1600  * RETURNS
1601  *    Success: True
1602  *    Failure: False (and *should* [but doesn't] set LastError)
1603  */
1604 BOOL WINAPI GenerateConsoleCtrlEvent(DWORD dwCtrlEvent,
1605                                      DWORD dwProcessGroupID)
1606 {
1607     BOOL ret;
1608
1609     TRACE("(%ld, %ld)\n", dwCtrlEvent, dwProcessGroupID);
1610
1611     if (dwCtrlEvent != CTRL_C_EVENT && dwCtrlEvent != CTRL_BREAK_EVENT)
1612     {
1613         ERR("Invalid event %ld for PGID %ld\n", dwCtrlEvent, dwProcessGroupID);
1614         return FALSE;
1615     }
1616
1617     SERVER_START_REQ( send_console_signal )
1618     {
1619         req->signal = dwCtrlEvent;
1620         req->group_id = dwProcessGroupID;
1621         ret = !wine_server_call_err( req );
1622     }
1623     SERVER_END_REQ;
1624
1625     /* FIXME: shall this function be synchronous, ie only return when all events
1626      * have been handled by all processes in the given group ?
1627      * As of today, we don't wait...
1628      */
1629     return ret;
1630 }
1631
1632
1633 /******************************************************************************
1634  * CreateConsoleScreenBuffer [KERNEL32.@]  Creates a console screen buffer
1635  *
1636  * PARAMS
1637  *    dwDesiredAccess    [I] Access flag
1638  *    dwShareMode        [I] Buffer share mode
1639  *    sa                 [I] Security attributes
1640  *    dwFlags            [I] Type of buffer to create
1641  *    lpScreenBufferData [I] Reserved
1642  *
1643  * NOTES
1644  *    Should call SetLastError
1645  *
1646  * RETURNS
1647  *    Success: Handle to new console screen buffer
1648  *    Failure: INVALID_HANDLE_VALUE
1649  */
1650 HANDLE WINAPI CreateConsoleScreenBuffer(DWORD dwDesiredAccess, DWORD dwShareMode,
1651                                         LPSECURITY_ATTRIBUTES sa, DWORD dwFlags,
1652                                         LPVOID lpScreenBufferData)
1653 {
1654     HANDLE      ret = INVALID_HANDLE_VALUE;
1655
1656     TRACE("(%ld,%ld,%p,%ld,%p)\n",
1657           dwDesiredAccess, dwShareMode, sa, dwFlags, lpScreenBufferData);
1658
1659     if (dwFlags != CONSOLE_TEXTMODE_BUFFER || lpScreenBufferData != NULL)
1660     {
1661         SetLastError(ERROR_INVALID_PARAMETER);
1662         return INVALID_HANDLE_VALUE;
1663     }
1664
1665     SERVER_START_REQ(create_console_output)
1666     {
1667         req->handle_in = 0;
1668         req->access    = dwDesiredAccess;
1669         req->share     = dwShareMode;
1670         req->inherit   = (sa && sa->bInheritHandle);
1671         if (!wine_server_call_err( req )) ret = reply->handle_out;
1672     }
1673     SERVER_END_REQ;
1674
1675     return ret;
1676 }
1677
1678
1679 /***********************************************************************
1680  *           GetConsoleScreenBufferInfo   (KERNEL32.@)
1681  */
1682 BOOL WINAPI GetConsoleScreenBufferInfo(HANDLE hConsoleOutput, LPCONSOLE_SCREEN_BUFFER_INFO csbi)
1683 {
1684     BOOL        ret;
1685
1686     SERVER_START_REQ(get_console_output_info)
1687     {
1688         req->handle = console_handle_unmap(hConsoleOutput);
1689         if ((ret = !wine_server_call_err( req )))
1690         {
1691             csbi->dwSize.X              = reply->width;
1692             csbi->dwSize.Y              = reply->height;
1693             csbi->dwCursorPosition.X    = reply->cursor_x;
1694             csbi->dwCursorPosition.Y    = reply->cursor_y;
1695             csbi->wAttributes           = reply->attr;
1696             csbi->srWindow.Left         = reply->win_left;
1697             csbi->srWindow.Right        = reply->win_right;
1698             csbi->srWindow.Top          = reply->win_top;
1699             csbi->srWindow.Bottom       = reply->win_bottom;
1700             csbi->dwMaximumWindowSize.X = reply->max_width;
1701             csbi->dwMaximumWindowSize.Y = reply->max_height;
1702         }
1703     }
1704     SERVER_END_REQ;
1705
1706     TRACE("(%p,(%d,%d) (%d,%d) %d (%d,%d-%d,%d) (%d,%d)\n", 
1707           hConsoleOutput, csbi->dwSize.X, csbi->dwSize.Y,
1708           csbi->dwCursorPosition.X, csbi->dwCursorPosition.Y,
1709           csbi->wAttributes,
1710           csbi->srWindow.Left, csbi->srWindow.Top, csbi->srWindow.Right, csbi->srWindow.Bottom,
1711           csbi->dwMaximumWindowSize.X, csbi->dwMaximumWindowSize.Y);
1712
1713     return ret;
1714 }
1715
1716
1717 /******************************************************************************
1718  * SetConsoleActiveScreenBuffer [KERNEL32.@]  Sets buffer to current console
1719  *
1720  * RETURNS
1721  *    Success: TRUE
1722  *    Failure: FALSE
1723  */
1724 BOOL WINAPI SetConsoleActiveScreenBuffer(HANDLE hConsoleOutput)
1725 {
1726     BOOL ret;
1727
1728     TRACE("(%p)\n", hConsoleOutput);
1729
1730     SERVER_START_REQ( set_console_input_info )
1731     {
1732         req->handle    = 0;
1733         req->mask      = SET_CONSOLE_INPUT_INFO_ACTIVE_SB;
1734         req->active_sb = hConsoleOutput;
1735         ret = !wine_server_call_err( req );
1736     }
1737     SERVER_END_REQ;
1738     return ret;
1739 }
1740
1741
1742 /***********************************************************************
1743  *            GetConsoleMode   (KERNEL32.@)
1744  */
1745 BOOL WINAPI GetConsoleMode(HANDLE hcon, LPDWORD mode)
1746 {
1747     BOOL ret;
1748
1749     SERVER_START_REQ(get_console_mode)
1750     {
1751         req->handle = console_handle_unmap(hcon);
1752         ret = !wine_server_call_err( req );
1753         if (ret && mode) *mode = reply->mode;
1754     }
1755     SERVER_END_REQ;
1756     return ret;
1757 }
1758
1759
1760 /******************************************************************************
1761  * SetConsoleMode [KERNEL32.@]  Sets input mode of console's input buffer
1762  *
1763  * PARAMS
1764  *    hcon [I] Handle to console input or screen buffer
1765  *    mode [I] Input or output mode to set
1766  *
1767  * RETURNS
1768  *    Success: TRUE
1769  *    Failure: FALSE
1770  *
1771  *    mode:
1772  *      ENABLE_PROCESSED_INPUT  0x01
1773  *      ENABLE_LINE_INPUT       0x02
1774  *      ENABLE_ECHO_INPUT       0x04
1775  *      ENABLE_WINDOW_INPUT     0x08
1776  *      ENABLE_MOUSE_INPUT      0x10
1777  */
1778 BOOL WINAPI SetConsoleMode(HANDLE hcon, DWORD mode)
1779 {
1780     BOOL ret;
1781
1782     SERVER_START_REQ(set_console_mode)
1783     {
1784         req->handle = console_handle_unmap(hcon);
1785         req->mode = mode;
1786         ret = !wine_server_call_err( req );
1787     }
1788     SERVER_END_REQ;
1789     /* FIXME: when resetting a console input to editline mode, I think we should
1790      * empty the S_EditString buffer
1791      */
1792
1793     TRACE("(%p,%lx) retval == %d\n", hcon, mode, ret);
1794
1795     return ret;
1796 }
1797
1798
1799 /******************************************************************
1800  *              CONSOLE_WriteChars
1801  *
1802  * WriteConsoleOutput helper: hides server call semantics
1803  * writes a string at a given pos with standard attribute
1804  */
1805 static int CONSOLE_WriteChars(HANDLE hCon, LPCWSTR lpBuffer, int nc, COORD* pos)
1806 {
1807     int written = -1;
1808
1809     if (!nc) return 0;
1810
1811     SERVER_START_REQ( write_console_output )
1812     {
1813         req->handle = console_handle_unmap(hCon);
1814         req->x      = pos->X;
1815         req->y      = pos->Y;
1816         req->mode   = CHAR_INFO_MODE_TEXTSTDATTR;
1817         req->wrap   = FALSE;
1818         wine_server_add_data( req, lpBuffer, nc * sizeof(WCHAR) );
1819         if (!wine_server_call_err( req )) written = reply->written;
1820     }
1821     SERVER_END_REQ;
1822
1823     if (written > 0) pos->X += written;
1824     return written;
1825 }
1826
1827 /******************************************************************
1828  *              next_line
1829  *
1830  * WriteConsoleOutput helper: handles passing to next line (+scrolling if necessary)
1831  *
1832  */
1833 static int      next_line(HANDLE hCon, CONSOLE_SCREEN_BUFFER_INFO* csbi)
1834 {
1835     SMALL_RECT  src;
1836     CHAR_INFO   ci;
1837     COORD       dst;
1838
1839     csbi->dwCursorPosition.X = 0;
1840     csbi->dwCursorPosition.Y++;
1841
1842     if (csbi->dwCursorPosition.Y < csbi->dwSize.Y) return 1;
1843
1844     src.Top    = 1;
1845     src.Bottom = csbi->dwSize.Y - 1;
1846     src.Left   = 0;
1847     src.Right  = csbi->dwSize.X - 1;
1848
1849     dst.X      = 0;
1850     dst.Y      = 0;
1851
1852     ci.Attributes = csbi->wAttributes;
1853     ci.Char.UnicodeChar = ' ';
1854
1855     csbi->dwCursorPosition.Y--;
1856     if (!ScrollConsoleScreenBufferW(hCon, &src, NULL, dst, &ci))
1857         return 0;
1858     return 1;
1859 }
1860
1861 /******************************************************************
1862  *              write_block
1863  *
1864  * WriteConsoleOutput helper: writes a block of non special characters
1865  * Block can spread on several lines, and wrapping, if needed, is
1866  * handled
1867  *
1868  */
1869 static int      write_block(HANDLE hCon, CONSOLE_SCREEN_BUFFER_INFO* csbi,
1870                             DWORD mode, LPCWSTR ptr, int len)
1871 {
1872     int blk;    /* number of chars to write on current line */
1873     int done;   /* number of chars already written */
1874
1875     if (len <= 0) return 1;
1876
1877     if (mode & ENABLE_WRAP_AT_EOL_OUTPUT) /* writes remaining on next line */
1878     {
1879         for (done = 0; done < len; done += blk)
1880         {
1881             blk = min(len - done, csbi->dwSize.X - csbi->dwCursorPosition.X);
1882
1883             if (CONSOLE_WriteChars(hCon, ptr + done, blk, &csbi->dwCursorPosition) != blk)
1884                 return 0;
1885             if (csbi->dwCursorPosition.X == csbi->dwSize.X && !next_line(hCon, csbi))
1886                 return 0;
1887         }
1888     }
1889     else
1890     {
1891         int     pos = csbi->dwCursorPosition.X;
1892         /* FIXME: we could reduce the number of loops
1893          * but, in most cases we wouldn't gain lots of time (it would only
1894          * happen if we're asked to overwrite more than twice the part of the line,
1895          * which is unlikely
1896          */
1897         for (blk = done = 0; done < len; done += blk)
1898         {
1899             blk = min(len - done, csbi->dwSize.X - csbi->dwCursorPosition.X);
1900
1901             csbi->dwCursorPosition.X = pos;
1902             if (CONSOLE_WriteChars(hCon, ptr + done, blk, &csbi->dwCursorPosition) != blk)
1903                 return 0;
1904         }
1905     }
1906
1907     return 1;
1908 }
1909
1910 /***********************************************************************
1911  *            WriteConsoleW   (KERNEL32.@)
1912  */
1913 BOOL WINAPI WriteConsoleW(HANDLE hConsoleOutput, LPCVOID lpBuffer, DWORD nNumberOfCharsToWrite,
1914                           LPDWORD lpNumberOfCharsWritten, LPVOID lpReserved)
1915 {
1916     DWORD                       mode;
1917     DWORD                       nw = 0;
1918     const WCHAR*                psz = lpBuffer;
1919     CONSOLE_SCREEN_BUFFER_INFO  csbi;
1920     int                         k, first = 0;
1921
1922     TRACE("%p %s %ld %p %p\n",
1923           hConsoleOutput, debugstr_wn(lpBuffer, nNumberOfCharsToWrite),
1924           nNumberOfCharsToWrite, lpNumberOfCharsWritten, lpReserved);
1925
1926     if (lpNumberOfCharsWritten) *lpNumberOfCharsWritten = 0;
1927
1928     if (!GetConsoleMode(hConsoleOutput, &mode) ||
1929         !GetConsoleScreenBufferInfo(hConsoleOutput, &csbi))
1930         return FALSE;
1931
1932     if (mode & ENABLE_PROCESSED_OUTPUT)
1933     {
1934         unsigned int    i;
1935
1936         for (i = 0; i < nNumberOfCharsToWrite; i++)
1937         {
1938             switch (psz[i])
1939             {
1940             case '\b': case '\t': case '\n': case '\a': case '\r':
1941                 /* don't handle here the i-th char... done below */
1942                 if ((k = i - first) > 0)
1943                 {
1944                     if (!write_block(hConsoleOutput, &csbi, mode, &psz[first], k))
1945                         goto the_end;
1946                     nw += k;
1947                 }
1948                 first = i + 1;
1949                 nw++;
1950             }
1951             switch (psz[i])
1952             {
1953             case '\b':
1954                 if (csbi.dwCursorPosition.X > 0) csbi.dwCursorPosition.X--;
1955                 break;
1956             case '\t':
1957                 {
1958                     WCHAR tmp[8] = {' ',' ',' ',' ',' ',' ',' ',' '};
1959
1960                     if (!write_block(hConsoleOutput, &csbi, mode, tmp,
1961                                      ((csbi.dwCursorPosition.X + 8) & ~7) - csbi.dwCursorPosition.X))
1962                         goto the_end;
1963                 }
1964                 break;
1965             case '\n':
1966                 next_line(hConsoleOutput, &csbi);
1967                 break;
1968             case '\a':
1969                 Beep(400, 300);
1970                 break;
1971             case '\r':
1972                 csbi.dwCursorPosition.X = 0;
1973                 break;
1974             default:
1975                 break;
1976             }
1977         }
1978     }
1979
1980     /* write the remaining block (if any) if processed output is enabled, or the
1981      * entire buffer otherwise
1982      */
1983     if ((k = nNumberOfCharsToWrite - first) > 0)
1984     {
1985         if (!write_block(hConsoleOutput, &csbi, mode, &psz[first], k))
1986             goto the_end;
1987         nw += k;
1988     }
1989
1990  the_end:
1991     SetConsoleCursorPosition(hConsoleOutput, csbi.dwCursorPosition);
1992     if (lpNumberOfCharsWritten) *lpNumberOfCharsWritten = nw;
1993     return nw != 0;
1994 }
1995
1996
1997 /***********************************************************************
1998  *            WriteConsoleA   (KERNEL32.@)
1999  */
2000 BOOL WINAPI WriteConsoleA(HANDLE hConsoleOutput, LPCVOID lpBuffer, DWORD nNumberOfCharsToWrite,
2001                           LPDWORD lpNumberOfCharsWritten, LPVOID lpReserved)
2002 {
2003     BOOL        ret;
2004     LPWSTR      xstring;
2005     DWORD       n;
2006
2007     n = MultiByteToWideChar(CP_ACP, 0, lpBuffer, nNumberOfCharsToWrite, NULL, 0);
2008
2009     if (lpNumberOfCharsWritten) *lpNumberOfCharsWritten = 0;
2010     xstring = HeapAlloc(GetProcessHeap(), 0, n * sizeof(WCHAR));
2011     if (!xstring) return 0;
2012
2013     MultiByteToWideChar(CP_ACP, 0, lpBuffer, nNumberOfCharsToWrite, xstring, n);
2014
2015     ret = WriteConsoleW(hConsoleOutput, xstring, n, lpNumberOfCharsWritten, 0);
2016
2017     HeapFree(GetProcessHeap(), 0, xstring);
2018
2019     return ret;
2020 }
2021
2022 /******************************************************************************
2023  * SetConsoleCursorPosition [KERNEL32.@]
2024  * Sets the cursor position in console
2025  *
2026  * PARAMS
2027  *    hConsoleOutput   [I] Handle of console screen buffer
2028  *    dwCursorPosition [I] New cursor position coordinates
2029  *
2030  * RETURNS STD
2031  */
2032 BOOL WINAPI SetConsoleCursorPosition(HANDLE hcon, COORD pos)
2033 {
2034     BOOL                        ret;
2035     CONSOLE_SCREEN_BUFFER_INFO  csbi;
2036     int                         do_move = 0;
2037     int                         w, h;
2038
2039     TRACE("%p %d %d\n", hcon, pos.X, pos.Y);
2040
2041     SERVER_START_REQ(set_console_output_info)
2042     {
2043         req->handle         = console_handle_unmap(hcon);
2044         req->cursor_x       = pos.X;
2045         req->cursor_y       = pos.Y;
2046         req->mask           = SET_CONSOLE_OUTPUT_INFO_CURSOR_POS;
2047         ret = !wine_server_call_err( req );
2048     }
2049     SERVER_END_REQ;
2050
2051     if (!ret || !GetConsoleScreenBufferInfo(hcon, &csbi))
2052         return FALSE;
2053
2054     /* if cursor is no longer visible, scroll the visible window... */
2055     w = csbi.srWindow.Right - csbi.srWindow.Left + 1;
2056     h = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
2057     if (pos.X < csbi.srWindow.Left)
2058     {
2059         csbi.srWindow.Left   = min(pos.X, csbi.dwSize.X - w);
2060         do_move++;
2061     }
2062     else if (pos.X > csbi.srWindow.Right)
2063     {
2064         csbi.srWindow.Left   = max(pos.X, w) - w + 1;
2065         do_move++;
2066     }
2067     csbi.srWindow.Right  = csbi.srWindow.Left + w - 1;
2068
2069     if (pos.Y < csbi.srWindow.Top)
2070     {
2071         csbi.srWindow.Top    = min(pos.Y, csbi.dwSize.Y - h);
2072         do_move++;
2073     }
2074     else if (pos.Y > csbi.srWindow.Bottom)
2075     {
2076         csbi.srWindow.Top   = max(pos.Y, h) - h + 1;
2077         do_move++;
2078     }
2079     csbi.srWindow.Bottom = csbi.srWindow.Top + h - 1;
2080
2081     ret = (do_move) ? SetConsoleWindowInfo(hcon, TRUE, &csbi.srWindow) : TRUE;
2082
2083     return ret;
2084 }
2085
2086 /******************************************************************************
2087  * GetConsoleCursorInfo [KERNEL32.@]  Gets size and visibility of console
2088  *
2089  * PARAMS
2090  *    hcon  [I] Handle to console screen buffer
2091  *    cinfo [O] Address of cursor information
2092  *
2093  * RETURNS
2094  *    Success: TRUE
2095  *    Failure: FALSE
2096  */
2097 BOOL WINAPI GetConsoleCursorInfo(HANDLE hCon, LPCONSOLE_CURSOR_INFO cinfo)
2098 {
2099     BOOL ret;
2100
2101     SERVER_START_REQ(get_console_output_info)
2102     {
2103         req->handle = console_handle_unmap(hCon);
2104         ret = !wine_server_call_err( req );
2105         if (ret && cinfo)
2106         {
2107             cinfo->dwSize = reply->cursor_size;
2108             cinfo->bVisible = reply->cursor_visible;
2109         }
2110     }
2111     SERVER_END_REQ;
2112
2113     TRACE("(%p) returning (%ld,%d)\n", hCon, cinfo->dwSize, cinfo->bVisible);
2114     return ret;
2115 }
2116
2117
2118 /******************************************************************************
2119  * SetConsoleCursorInfo [KERNEL32.@]  Sets size and visibility of cursor
2120  *
2121  * PARAMS
2122  *      hcon    [I] Handle to console screen buffer
2123  *      cinfo   [I] Address of cursor information
2124  * RETURNS
2125  *    Success: TRUE
2126  *    Failure: FALSE
2127  */
2128 BOOL WINAPI SetConsoleCursorInfo(HANDLE hCon, LPCONSOLE_CURSOR_INFO cinfo)
2129 {
2130     BOOL ret;
2131
2132     TRACE("(%p,%ld,%d)\n", hCon, cinfo->dwSize, cinfo->bVisible);
2133     SERVER_START_REQ(set_console_output_info)
2134     {
2135         req->handle         = console_handle_unmap(hCon);
2136         req->cursor_size    = cinfo->dwSize;
2137         req->cursor_visible = cinfo->bVisible;
2138         req->mask           = SET_CONSOLE_OUTPUT_INFO_CURSOR_GEOM;
2139         ret = !wine_server_call_err( req );
2140     }
2141     SERVER_END_REQ;
2142     return ret;
2143 }
2144
2145
2146 /******************************************************************************
2147  * SetConsoleWindowInfo [KERNEL32.@]  Sets size and position of console
2148  *
2149  * PARAMS
2150  *      hcon            [I] Handle to console screen buffer
2151  *      bAbsolute       [I] Coordinate type flag
2152  *      window          [I] Address of new window rectangle
2153  * RETURNS
2154  *    Success: TRUE
2155  *    Failure: FALSE
2156  */
2157 BOOL WINAPI SetConsoleWindowInfo(HANDLE hCon, BOOL bAbsolute, LPSMALL_RECT window)
2158 {
2159     SMALL_RECT  p = *window;
2160     BOOL        ret;
2161
2162     TRACE("(%p,%d,(%d,%d-%d,%d))\n", hCon, bAbsolute, p.Left, p.Top, p.Right, p.Bottom);
2163
2164     if (!bAbsolute)
2165     {
2166         CONSOLE_SCREEN_BUFFER_INFO      csbi;
2167
2168         if (!GetConsoleScreenBufferInfo(hCon, &csbi))
2169             return FALSE;
2170         p.Left   += csbi.srWindow.Left;
2171         p.Top    += csbi.srWindow.Top;
2172         p.Right  += csbi.srWindow.Right;
2173         p.Bottom += csbi.srWindow.Bottom;
2174     }
2175     SERVER_START_REQ(set_console_output_info)
2176     {
2177         req->handle         = console_handle_unmap(hCon);
2178         req->win_left       = p.Left;
2179         req->win_top        = p.Top;
2180         req->win_right      = p.Right;
2181         req->win_bottom     = p.Bottom;
2182         req->mask           = SET_CONSOLE_OUTPUT_INFO_DISPLAY_WINDOW;
2183         ret = !wine_server_call_err( req );
2184     }
2185     SERVER_END_REQ;
2186
2187     return ret;
2188 }
2189
2190
2191 /******************************************************************************
2192  * SetConsoleTextAttribute [KERNEL32.@]  Sets colors for text
2193  *
2194  * Sets the foreground and background color attributes of characters
2195  * written to the screen buffer.
2196  *
2197  * RETURNS
2198  *    Success: TRUE
2199  *    Failure: FALSE
2200  */
2201 BOOL WINAPI SetConsoleTextAttribute(HANDLE hConsoleOutput, WORD wAttr)
2202 {
2203     BOOL ret;
2204
2205     TRACE("(%p,%d)\n", hConsoleOutput, wAttr);
2206     SERVER_START_REQ(set_console_output_info)
2207     {
2208         req->handle = console_handle_unmap(hConsoleOutput);
2209         req->attr   = wAttr;
2210         req->mask   = SET_CONSOLE_OUTPUT_INFO_ATTR;
2211         ret = !wine_server_call_err( req );
2212     }
2213     SERVER_END_REQ;
2214     return ret;
2215 }
2216
2217
2218 /******************************************************************************
2219  * SetConsoleScreenBufferSize [KERNEL32.@]  Changes size of console
2220  *
2221  * PARAMS
2222  *    hConsoleOutput [I] Handle to console screen buffer
2223  *    dwSize         [I] New size in character rows and cols
2224  *
2225  * RETURNS
2226  *    Success: TRUE
2227  *    Failure: FALSE
2228  */
2229 BOOL WINAPI SetConsoleScreenBufferSize(HANDLE hConsoleOutput, COORD dwSize)
2230 {
2231     BOOL ret;
2232
2233     TRACE("(%p,(%d,%d))\n", hConsoleOutput, dwSize.X, dwSize.Y);
2234     SERVER_START_REQ(set_console_output_info)
2235     {
2236         req->handle = console_handle_unmap(hConsoleOutput);
2237         req->width  = dwSize.X;
2238         req->height = dwSize.Y;
2239         req->mask   = SET_CONSOLE_OUTPUT_INFO_SIZE;
2240         ret = !wine_server_call_err( req );
2241     }
2242     SERVER_END_REQ;
2243     return ret;
2244 }
2245
2246
2247 /******************************************************************************
2248  * ScrollConsoleScreenBufferA [KERNEL32.@]
2249  *
2250  */
2251 BOOL WINAPI ScrollConsoleScreenBufferA(HANDLE hConsoleOutput, LPSMALL_RECT lpScrollRect,
2252                                        LPSMALL_RECT lpClipRect, COORD dwDestOrigin,
2253                                        LPCHAR_INFO lpFill)
2254 {
2255     CHAR_INFO   ciw;
2256
2257     ciw.Attributes = lpFill->Attributes;
2258     MultiByteToWideChar(CP_ACP, 0, &lpFill->Char.AsciiChar, 1, &ciw.Char.UnicodeChar, 1);
2259
2260     return ScrollConsoleScreenBufferW(hConsoleOutput, lpScrollRect, lpClipRect,
2261                                       dwDestOrigin, &ciw);
2262 }
2263
2264 /******************************************************************
2265  *              CONSOLE_FillLineUniform
2266  *
2267  * Helper function for ScrollConsoleScreenBufferW
2268  * Fills a part of a line with a constant character info
2269  */
2270 void CONSOLE_FillLineUniform(HANDLE hConsoleOutput, int i, int j, int len, LPCHAR_INFO lpFill)
2271 {
2272     SERVER_START_REQ( fill_console_output )
2273     {
2274         req->handle    = console_handle_unmap(hConsoleOutput);
2275         req->mode      = CHAR_INFO_MODE_TEXTATTR;
2276         req->x         = i;
2277         req->y         = j;
2278         req->count     = len;
2279         req->wrap      = FALSE;
2280         req->data.ch   = lpFill->Char.UnicodeChar;
2281         req->data.attr = lpFill->Attributes;
2282         wine_server_call_err( req );
2283     }
2284     SERVER_END_REQ;
2285 }
2286
2287 /******************************************************************************
2288  * ScrollConsoleScreenBufferW [KERNEL32.@]
2289  *
2290  */
2291
2292 BOOL WINAPI ScrollConsoleScreenBufferW(HANDLE hConsoleOutput, LPSMALL_RECT lpScrollRect,
2293                                        LPSMALL_RECT lpClipRect, COORD dwDestOrigin,
2294                                        LPCHAR_INFO lpFill)
2295 {
2296     SMALL_RECT                  dst;
2297     DWORD                       ret;
2298     int                         i, j;
2299     int                         start = -1;
2300     SMALL_RECT                  clip;
2301     CONSOLE_SCREEN_BUFFER_INFO  csbi;
2302     BOOL                        inside;
2303     COORD                       src;
2304
2305     if (lpClipRect)
2306         TRACE("(%p,(%d,%d-%d,%d),(%d,%d-%d,%d),%d-%d,%p)\n", hConsoleOutput,
2307               lpScrollRect->Left, lpScrollRect->Top,
2308               lpScrollRect->Right, lpScrollRect->Bottom,
2309               lpClipRect->Left, lpClipRect->Top,
2310               lpClipRect->Right, lpClipRect->Bottom,
2311               dwDestOrigin.X, dwDestOrigin.Y, lpFill);
2312     else
2313         TRACE("(%p,(%d,%d-%d,%d),(nil),%d-%d,%p)\n", hConsoleOutput,
2314               lpScrollRect->Left, lpScrollRect->Top,
2315               lpScrollRect->Right, lpScrollRect->Bottom,
2316               dwDestOrigin.X, dwDestOrigin.Y, lpFill);
2317
2318     if (!GetConsoleScreenBufferInfo(hConsoleOutput, &csbi))
2319         return FALSE;
2320
2321     src.X = lpScrollRect->Left;
2322     src.Y = lpScrollRect->Top;
2323
2324     /* step 1: get dst rect */
2325     dst.Left = dwDestOrigin.X;
2326     dst.Top = dwDestOrigin.Y;
2327     dst.Right = dst.Left + (lpScrollRect->Right - lpScrollRect->Left);
2328     dst.Bottom = dst.Top + (lpScrollRect->Bottom - lpScrollRect->Top);
2329
2330     /* step 2a: compute the final clip rect (optional passed clip and screen buffer limits */
2331     if (lpClipRect)
2332     {
2333         clip.Left   = max(0, lpClipRect->Left);
2334         clip.Right  = min(csbi.dwSize.X - 1, lpClipRect->Right);
2335         clip.Top    = max(0, lpClipRect->Top);
2336         clip.Bottom = min(csbi.dwSize.Y - 1, lpClipRect->Bottom);
2337     }
2338     else
2339     {
2340         clip.Left   = 0;
2341         clip.Right  = csbi.dwSize.X - 1;
2342         clip.Top    = 0;
2343         clip.Bottom = csbi.dwSize.Y - 1;
2344     }
2345     if (clip.Left > clip.Right || clip.Top > clip.Bottom) return FALSE;
2346
2347     /* step 2b: clip dst rect */
2348     if (dst.Left   < clip.Left  ) {src.X += clip.Left - dst.Left; dst.Left   = clip.Left;}
2349     if (dst.Top    < clip.Top   ) {src.Y += clip.Top  - dst.Top;  dst.Top    = clip.Top;}
2350     if (dst.Right  > clip.Right ) dst.Right  = clip.Right;
2351     if (dst.Bottom > clip.Bottom) dst.Bottom = clip.Bottom;
2352
2353     /* step 3: transfer the bits */
2354     SERVER_START_REQ(move_console_output)
2355     {
2356         req->handle = console_handle_unmap(hConsoleOutput);
2357         req->x_src = src.X;
2358         req->y_src = src.Y;
2359         req->x_dst = dst.Left;
2360         req->y_dst = dst.Top;
2361         req->w = dst.Right - dst.Left + 1;
2362         req->h = dst.Bottom - dst.Top + 1;
2363         ret = !wine_server_call_err( req );
2364     }
2365     SERVER_END_REQ;
2366
2367     if (!ret) return FALSE;
2368
2369     /* step 4: clean out the exposed part */
2370
2371     /* have to write cell [i,j] if it is not in dst rect (because it has already
2372      * been written to by the scroll) and is in clip (we shall not write
2373      * outside of clip)
2374      */
2375     for (j = max(lpScrollRect->Top, clip.Top); j <= min(lpScrollRect->Bottom, clip.Bottom); j++)
2376     {
2377         inside = dst.Top <= j && j <= dst.Bottom;
2378         start = -1;
2379         for (i = max(lpScrollRect->Left, clip.Left); i <= min(lpScrollRect->Right, clip.Right); i++)
2380         {
2381             if (inside && dst.Left <= i && i <= dst.Right)
2382             {
2383                 if (start != -1)
2384                 {
2385                     CONSOLE_FillLineUniform(hConsoleOutput, start, j, i - start, lpFill);
2386                     start = -1;
2387                 }
2388             }
2389             else
2390             {
2391                 if (start == -1) start = i;
2392             }
2393         }
2394         if (start != -1)
2395             CONSOLE_FillLineUniform(hConsoleOutput, start, j, i - start, lpFill);
2396     }
2397
2398     return TRUE;
2399 }
2400
2401
2402 /* ====================================================================
2403  *
2404  * Console manipulation functions
2405  *
2406  * ====================================================================*/
2407
2408 /* some missing functions...
2409  * FIXME: those are likely to be defined as undocumented function in kernel32 (or part of them)
2410  * should get the right API and implement them
2411  *      GetConsoleCommandHistory[AW] (dword dword dword)
2412  *      GetConsoleCommandHistoryLength[AW]
2413  *      SetConsoleCommandHistoryMode
2414  *      SetConsoleNumberOfCommands[AW]
2415  */
2416 int CONSOLE_GetHistory(int idx, WCHAR* buf, int buf_len)
2417 {
2418     int len = 0;
2419
2420     SERVER_START_REQ( get_console_input_history )
2421     {
2422         req->handle = 0;
2423         req->index = idx;
2424         if (buf && buf_len > 1)
2425         {
2426             wine_server_set_reply( req, buf, (buf_len - 1) * sizeof(WCHAR) );
2427         }
2428         if (!wine_server_call_err( req ))
2429         {
2430             if (buf) buf[wine_server_reply_size(reply) / sizeof(WCHAR)] = 0;
2431             len = reply->total / sizeof(WCHAR) + 1;
2432         }
2433     }
2434     SERVER_END_REQ;
2435     return len;
2436 }
2437
2438 /******************************************************************
2439  *              CONSOLE_AppendHistory
2440  *
2441  *
2442  */
2443 BOOL    CONSOLE_AppendHistory(const WCHAR* ptr)
2444 {
2445     size_t      len = strlenW(ptr);
2446     BOOL        ret;
2447
2448     while (len && (ptr[len - 1] == '\n' || ptr[len - 1] == '\r')) len--;
2449
2450     SERVER_START_REQ( append_console_input_history )
2451     {
2452         req->handle = 0;
2453         wine_server_add_data( req, ptr, len * sizeof(WCHAR) );
2454         ret = !wine_server_call_err( req );
2455     }
2456     SERVER_END_REQ;
2457     return ret;
2458 }
2459
2460 /******************************************************************
2461  *              CONSOLE_GetNumHistoryEntries
2462  *
2463  *
2464  */
2465 unsigned CONSOLE_GetNumHistoryEntries(void)
2466 {
2467     unsigned ret = -1;
2468     SERVER_START_REQ(get_console_input_info)
2469     {
2470         req->handle = 0;
2471         if (!wine_server_call_err( req )) ret = reply->history_index;
2472     }
2473     SERVER_END_REQ;
2474     return ret;
2475 }
2476
2477 /******************************************************************
2478  *              CONSOLE_GetEditionMode
2479  *
2480  *
2481  */
2482 BOOL CONSOLE_GetEditionMode(HANDLE hConIn, int* mode)
2483 {
2484     unsigned ret = FALSE;
2485     SERVER_START_REQ(get_console_input_info)
2486     {
2487         req->handle = console_handle_unmap(hConIn);
2488         if ((ret = !wine_server_call_err( req )))
2489             *mode = reply->edition_mode;
2490     }
2491     SERVER_END_REQ;
2492     return ret;
2493 }