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