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