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