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