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