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