Added WNetRemoveCachedPassword() stub.
[wine] / win32 / 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  */
9
10 /* FIXME:
11  * - Completely lacks SCREENBUFFER interface.
12  * - No abstraction for something other than xterm.
13  * - Key input translation shouldn't use VkKeyScan and MapVirtualKey, since
14  *   they are window (USER) driver dependend.
15  * - Output sometimes is buffered (We switched off buffering by ~ICANON ?)
16  */
17 /* Reference applications:
18  * -  IDA (interactive disassembler) full version 3.75. Works.
19  * -  LYNX/W32. Works mostly, some keys crash it.
20  */
21
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <termios.h>
25 #include <string.h>
26 #include <sys/ioctl.h>
27 #include <sys/types.h>
28 #include <sys/time.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <sys/errno.h>
33 #include <signal.h>
34 #include <assert.h>
35
36 #include "winbase.h"
37 #include "wine/winuser16.h"
38 #include "wine/keyboard16.h"
39 #include "thread.h"
40 #include "async.h"
41 #include "file.h"
42 #include "process.h"
43 #include "winerror.h"
44 #include "wincon.h"
45 #include "heap.h"
46 #include "server.h"
47 #include "debugtools.h"
48
49 DEFAULT_DEBUG_CHANNEL(console)
50
51
52 /* FIXME:  Should be in an internal header file.  OK, so which one?
53    Used by CONSOLE_makecomplex. */
54 FILE *wine_openpty(int *master, int *slave, char *name,
55                    struct termios *term, struct winsize *winsize);
56
57 /****************************************************************************
58  *              CONSOLE_GetPid
59  */
60 static int CONSOLE_GetPid( HANDLE handle )
61 {
62     struct get_console_info_request *req = get_req_buffer();
63     req->handle = handle;
64     if (server_call( REQ_GET_CONSOLE_INFO )) return 0;
65     return req->pid;
66 }
67
68 /****************************************************************************
69  *              XTERM_string_to_IR                      [internal]
70  *
71  * Transfers a string read from XTERM to INPUT_RECORDs and adds them to the
72  * queue. Does translation of vt100 style function keys and xterm-mouse clicks.
73  */
74 static void
75 CONSOLE_string_to_IR( HANDLE hConsoleInput,unsigned char *buf,int len) {
76     int                 j,k;
77     INPUT_RECORD        ir;
78     DWORD               junk;
79
80     for (j=0;j<len;j++) {
81         unsigned char inchar = buf[j];
82
83         if (inchar!=27) { /* no escape -> 'normal' keyboard event */
84             ir.EventType = 1; /* Key_event */
85
86             ir.Event.KeyEvent.bKeyDown          = 1;
87             ir.Event.KeyEvent.wRepeatCount      = 0;
88
89             ir.Event.KeyEvent.dwControlKeyState = 0;
90             if (inchar & 0x80) {
91                 ir.Event.KeyEvent.dwControlKeyState|=LEFT_ALT_PRESSED;
92                 inchar &= ~0x80;
93             }
94             ir.Event.KeyEvent.wVirtualKeyCode = VkKeyScan16(inchar);
95             if (ir.Event.KeyEvent.wVirtualKeyCode & 0x0100)
96                 ir.Event.KeyEvent.dwControlKeyState|=SHIFT_PRESSED;
97             if (ir.Event.KeyEvent.wVirtualKeyCode & 0x0200)
98                 ir.Event.KeyEvent.dwControlKeyState|=LEFT_CTRL_PRESSED;
99             if (ir.Event.KeyEvent.wVirtualKeyCode & 0x0400)
100                 ir.Event.KeyEvent.dwControlKeyState|=LEFT_ALT_PRESSED;
101             ir.Event.KeyEvent.wVirtualScanCode = MapVirtualKey16(
102                 ir.Event.KeyEvent.wVirtualKeyCode & 0x00ff,
103                 0 /* VirtualKeyCodes to ScanCode */
104             );
105             ir.Event.KeyEvent.uChar.AsciiChar = inchar;
106
107             if (inchar==127) { /* backspace */
108                 ir.Event.KeyEvent.uChar.AsciiChar = '\b'; /* FIXME: hmm */
109                 ir.Event.KeyEvent.wVirtualScanCode = 0x0e;
110                 ir.Event.KeyEvent.wVirtualKeyCode = VK_BACK;
111             } else {
112                 if ((inchar=='\n')||(inchar=='\r')) {
113                     ir.Event.KeyEvent.uChar.AsciiChar   = '\r';
114                     ir.Event.KeyEvent.wVirtualKeyCode   = VK_RETURN;
115                     ir.Event.KeyEvent.wVirtualScanCode  = 0x1c;
116                     ir.Event.KeyEvent.dwControlKeyState = 0;
117                 } else {
118                     if (inchar<' ') {
119                         /* FIXME: find good values for ^X */
120                         ir.Event.KeyEvent.wVirtualKeyCode = 0xdead;
121                         ir.Event.KeyEvent.wVirtualScanCode = 0xbeef;
122                     } 
123                 }
124             }
125
126             assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
127             ir.Event.KeyEvent.bKeyDown = 0;
128             assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
129             continue;
130         }
131         /* inchar is ESC */
132         if ((j==len-1) || (buf[j+1]!='[')) {/* add ESCape on its own */
133             ir.EventType = 1; /* Key_event */
134             ir.Event.KeyEvent.bKeyDown          = 1;
135             ir.Event.KeyEvent.wRepeatCount      = 0;
136
137             ir.Event.KeyEvent.wVirtualKeyCode   = VkKeyScan16(27);
138             ir.Event.KeyEvent.wVirtualScanCode  = MapVirtualKey16(
139                 ir.Event.KeyEvent.wVirtualKeyCode,0
140             );
141             ir.Event.KeyEvent.dwControlKeyState = 0;
142             ir.Event.KeyEvent.uChar.AsciiChar   = 27;
143             assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
144             ir.Event.KeyEvent.bKeyDown = 0;
145             assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
146             continue;
147         }
148         for (k=j;k<len;k++) {
149             if (((buf[k]>='A') && (buf[k]<='Z')) ||
150                 ((buf[k]>='a') && (buf[k]<='z')) ||
151                  (buf[k]=='~')
152             )
153                 break;
154         }
155         if (k<len) {
156             int subid,scancode=0;
157
158             ir.EventType                        = 1; /* Key_event */
159             ir.Event.KeyEvent.bKeyDown          = 1;
160             ir.Event.KeyEvent.wRepeatCount      = 0;
161             ir.Event.KeyEvent.dwControlKeyState = 0;
162
163             ir.Event.KeyEvent.wVirtualKeyCode   = 0xad; /* FIXME */
164             ir.Event.KeyEvent.wVirtualScanCode  = 0xad; /* FIXME */
165             ir.Event.KeyEvent.uChar.AsciiChar   = 0;
166
167             switch (buf[k]) {
168             case '~':
169                 sscanf(&buf[j+2],"%d",&subid);
170                 switch (subid) {
171                 case  2:/*INS */scancode = 0xe052;break;
172                 case  3:/*DEL */scancode = 0xe053;break;
173                 case  6:/*PGDW*/scancode = 0xe051;break;
174                 case  5:/*PGUP*/scancode = 0xe049;break;
175                 case 11:/*F1  */scancode = 0x003b;break;
176                 case 12:/*F2  */scancode = 0x003c;break;
177                 case 13:/*F3  */scancode = 0x003d;break;
178                 case 14:/*F4  */scancode = 0x003e;break;
179                 case 15:/*F5  */scancode = 0x003f;break;
180                 case 17:/*F6  */scancode = 0x0040;break;
181                 case 18:/*F7  */scancode = 0x0041;break;
182                 case 19:/*F8  */scancode = 0x0042;break;
183                 case 20:/*F9  */scancode = 0x0043;break;
184                 case 21:/*F10 */scancode = 0x0044;break;
185                 case 23:/*F11 */scancode = 0x00d9;break;
186                 case 24:/*F12 */scancode = 0x00da;break;
187                 /* FIXME: Shift-Fx */
188                 default:
189                         FIXME("parse ESC[%d~\n",subid);
190                         break;
191                 }
192                 break;
193             case 'A': /* Cursor Up    */scancode = 0xe048;break;
194             case 'B': /* Cursor Down  */scancode = 0xe050;break;
195             case 'D': /* Cursor Left  */scancode = 0xe04b;break;
196             case 'C': /* Cursor Right */scancode = 0xe04d;break;
197             case 'F': /* End          */scancode = 0xe04f;break;
198             case 'H': /* Home         */scancode = 0xe047;break;
199             case 'M':
200                 /* Mouse Button Press  (ESCM<button+'!'><x+'!'><y+'!'>) or
201                  *              Release (ESCM#<x+'!'><y+'!'>
202                  */
203                 if (k<len-3) {
204                     ir.EventType                        = MOUSE_EVENT;
205                     ir.Event.MouseEvent.dwMousePosition.x = buf[k+2]-'!';
206                     ir.Event.MouseEvent.dwMousePosition.y = buf[k+3]-'!';
207                     if (buf[k+1]=='#')
208                         ir.Event.MouseEvent.dwButtonState = 0;
209                     else
210                         ir.Event.MouseEvent.dwButtonState = 1<<(buf[k+1]-' ');
211                     ir.Event.MouseEvent.dwEventFlags      = 0; /* FIXME */
212                     assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk));
213                     j=k+3;
214                 }
215                 break;
216             case 'c':
217                 j=k;
218                 break;
219             }
220             if (scancode) {
221                 ir.Event.KeyEvent.wVirtualScanCode = scancode;
222                 ir.Event.KeyEvent.wVirtualKeyCode = MapVirtualKey16(scancode,1);
223                 assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
224                 ir.Event.KeyEvent.bKeyDown              = 0;
225                 assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
226                 j=k;
227                 continue;
228             }
229         }
230     }
231 }
232
233 /****************************************************************************
234  *              CONSOLE_get_input               (internal)
235  *
236  * Reads (nonblocking) as much input events as possible and stores them
237  * in an internal queue.
238  */
239 static void
240 CONSOLE_get_input( HANDLE handle, BOOL blockwait )
241 {
242     char        *buf = HeapAlloc(GetProcessHeap(),0,1);
243     int         len = 0;
244
245     while (1)
246     {
247         DWORD res;
248         char inchar;
249         if (WaitForSingleObject( handle, 0 )) break;
250         if (!ReadFile( handle, &inchar, 1, &res, NULL )) break;
251         if (!res) /* res 0 but readable means EOF? Hmm. */
252                 break;
253         buf = HeapReAlloc(GetProcessHeap(),0,buf,len+1);
254         buf[len++]=inchar;
255     }
256     CONSOLE_string_to_IR(handle,buf,len);
257     HeapFree(GetProcessHeap(),0,buf);
258 }
259
260 /******************************************************************************
261  * SetConsoleCtrlHandler [KERNEL32.459]  Adds function to calling process list
262  *
263  * PARAMS
264  *    func [I] Address of handler function
265  *    add  [I] Handler to add or remove
266  *
267  * RETURNS
268  *    Success: TRUE
269  *    Failure: FALSE
270  *
271  * CHANGED
272  * James Sutherland (JamesSutherland@gmx.de)
273  * Added global variables console_ignore_ctrl_c and handlers[]
274  * Does not yet do any error checking, or set LastError if failed.
275  * This doesn't yet matter, since these handlers are not yet called...!
276  */
277 static unsigned int console_ignore_ctrl_c = 0;
278 static HANDLER_ROUTINE *handlers[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
279 BOOL WINAPI SetConsoleCtrlHandler( HANDLER_ROUTINE *func, BOOL add )
280 {
281   unsigned int alloc_loop = sizeof(handlers)/sizeof(HANDLER_ROUTINE *);
282   unsigned int done = 0;
283   FIXME("(%p,%i) - no error checking or testing yet\n", func, add);
284   if (!func)
285     {
286       console_ignore_ctrl_c = add;
287       return TRUE;
288     }
289   if (add)
290       {
291         for (;alloc_loop--;)
292           if (!handlers[alloc_loop] && !done)
293             {
294               handlers[alloc_loop] = func;
295               done++;
296             }
297         if (!done)
298            FIXME("Out of space on CtrlHandler table\n");
299         return(done);
300       }
301     else
302       {
303         for (;alloc_loop--;)
304           if (handlers[alloc_loop] == func && !done)
305             {
306               handlers[alloc_loop] = 0;
307               done++;
308             }
309         if (!done)
310            WARN("Attempt to remove non-installed CtrlHandler %p\n",
311                 func);
312         return (done);
313       }
314     return (done);
315 }
316
317
318 /******************************************************************************
319  * GenerateConsoleCtrlEvent [KERNEL32.275] Simulate a CTRL-C or CTRL-BREAK
320  *
321  * PARAMS
322  *    dwCtrlEvent        [I] Type of event
323  *    dwProcessGroupID   [I] Process group ID to send event to
324  *
325  * NOTES
326  *    Doesn't yet work...!
327  *
328  * RETURNS
329  *    Success: True
330  *    Failure: False (and *should* [but doesn't] set LastError)
331  */
332 BOOL WINAPI GenerateConsoleCtrlEvent( DWORD dwCtrlEvent,
333                                         DWORD dwProcessGroupID )
334 {
335   if (dwCtrlEvent != CTRL_C_EVENT && dwCtrlEvent != CTRL_BREAK_EVENT)
336     {
337       ERR("invalid event %d for PGID %ld\n", 
338            (unsigned short)dwCtrlEvent, dwProcessGroupID );
339       return FALSE;
340     }
341   if (dwProcessGroupID == GetCurrentProcessId() )
342     {
343       FIXME("Attempt to send event %d to self - stub\n",
344              (unsigned short)dwCtrlEvent );
345       return FALSE;
346     }
347   FIXME("event %d to external PGID %ld - not implemented yet\n",
348          (unsigned short)dwCtrlEvent, dwProcessGroupID );
349   return FALSE;
350 }
351
352
353 /******************************************************************************
354  * CreateConsoleScreenBuffer [KERNEL32.151]  Creates a console screen buffer
355  *
356  * PARAMS
357  *    dwDesiredAccess    [I] Access flag
358  *    dwShareMode        [I] Buffer share mode
359  *    sa                 [I] Security attributes
360  *    dwFlags            [I] Type of buffer to create
361  *    lpScreenBufferData [I] Reserved
362  *
363  * NOTES
364  *    Should call SetLastError
365  *
366  * RETURNS
367  *    Success: Handle to new console screen buffer
368  *    Failure: INVALID_HANDLE_VALUE
369  */
370 HANDLE WINAPI CreateConsoleScreenBuffer( DWORD dwDesiredAccess,
371                 DWORD dwShareMode, LPSECURITY_ATTRIBUTES sa,
372                 DWORD dwFlags, LPVOID lpScreenBufferData )
373 {
374     FIXME("(%ld,%ld,%p,%ld,%p): stub\n",dwDesiredAccess,
375           dwShareMode, sa, dwFlags, lpScreenBufferData);
376     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
377     return INVALID_HANDLE_VALUE;
378 }
379
380
381 /***********************************************************************
382  *           GetConsoleScreenBufferInfo   (KERNEL32.190)
383  */
384 BOOL WINAPI GetConsoleScreenBufferInfo( HANDLE hConsoleOutput,
385                                           LPCONSOLE_SCREEN_BUFFER_INFO csbi )
386 {
387     csbi->dwSize.x = 80;
388     csbi->dwSize.y = 24;
389     csbi->dwCursorPosition.x = 0;
390     csbi->dwCursorPosition.y = 0;
391     csbi->wAttributes = 0;
392     csbi->srWindow.Left = 0;
393     csbi->srWindow.Right        = 79;
394     csbi->srWindow.Top  = 0;
395     csbi->srWindow.Bottom       = 23;
396     csbi->dwMaximumWindowSize.x = 80;
397     csbi->dwMaximumWindowSize.y = 24;
398     return TRUE;
399 }
400
401
402 /******************************************************************************
403  * SetConsoleActiveScreenBuffer [KERNEL32.623]  Sets buffer to current console
404  *
405  * RETURNS
406  *    Success: TRUE
407  *    Failure: FALSE
408  */
409 BOOL WINAPI SetConsoleActiveScreenBuffer(
410     HANDLE hConsoleOutput) /* [in] Handle to console screen buffer */
411 {
412     FIXME("(%x): stub\n", hConsoleOutput);
413     return FALSE;
414 }
415
416
417 /***********************************************************************
418  *            GetLargestConsoleWindowSize   (KERNEL32.226)
419  */
420 DWORD WINAPI GetLargestConsoleWindowSize( HANDLE hConsoleOutput )
421 {
422     return (DWORD)MAKELONG(80,24);
423 }
424
425 /***********************************************************************
426  *            FreeConsole (KERNEL32.267)
427  */
428 BOOL WINAPI FreeConsole(VOID)
429 {
430     return !server_call( REQ_FREE_CONSOLE );
431 }
432
433
434 /*************************************************************************
435  *              CONSOLE_OpenHandle
436  *
437  * Open a handle to the current process console.
438  */
439 HANDLE CONSOLE_OpenHandle( BOOL output, DWORD access, LPSECURITY_ATTRIBUTES sa )
440 {
441     int ret = -1;
442     struct open_console_request *req = get_req_buffer();
443
444     req->output  = output;
445     req->access  = access;
446     req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
447     SetLastError(0);
448     if (!server_call( REQ_OPEN_CONSOLE )) ret = req->handle;
449     return ret;
450 }
451
452
453 /*************************************************************************
454  *              CONSOLE_make_complex                    [internal]
455  *
456  * Turns a CONSOLE kernel object into a complex one.
457  * (switches from output/input using the terminal where WINE was started to 
458  * its own xterm).
459  * 
460  * This makes simple commandline tools pipeable, while complex commandline 
461  * tools work without getting messed up by debugoutput.
462  * 
463  * All other functions should work indedependend from this call.
464  *
465  * To test for complex console: pid == 0 -> simple, otherwise complex.
466  */
467 static BOOL CONSOLE_make_complex(HANDLE handle)
468 {
469         struct set_console_fd_request *req = get_req_buffer();
470         struct termios term;
471         char buf[256];
472         char c = '\0';
473         int i,xpid,master,slave,pty_handle;
474
475         if (CONSOLE_GetPid( handle )) return TRUE; /* already complex */
476
477         MESSAGE("Console: Making console complex (creating an xterm)...\n");
478
479         if (tcgetattr(0, &term) < 0) {
480                 /* ignore failure, or we can't run from a script */
481         }
482         term.c_lflag = ~(ECHO|ICANON);
483
484         if (wine_openpty(&master, &slave, NULL, &term, NULL) < 0)
485             return FALSE;
486
487         if ((xpid=fork()) == 0) {
488                 tcsetattr(slave, TCSADRAIN, &term);
489                 close( slave );
490                 sprintf(buf, "-Sxx%d", master);
491                 /* "-fn vga" for VGA font. Harmless if vga is not present:
492                  *  xterm: unable to open font "vga", trying "fixed".... 
493                  */
494                 execlp("xterm", "xterm", buf, "-fn","vga",NULL);
495                 ERR("error creating AllocConsole xterm\n");
496                 exit(1);
497         }
498         pty_handle = FILE_DupUnixHandle( slave, GENERIC_READ | GENERIC_WRITE );
499         close( master );
500         close( slave );
501         if (pty_handle == -1) return FALSE;
502
503         /* most xterms like to print their window ID when used with -S;
504          * read it and continue before the user has a chance...
505          */
506         for (i = 0; i < 10000; i++)
507         {
508             BOOL ok = ReadFile( pty_handle, &c, 1, NULL, NULL );
509             if (!ok && !c) usleep(100); /* wait for xterm to be created */
510             else if (c == '\n') break;
511         }
512         if (i == 10000)
513         {
514             ERR("can't read xterm WID\n");
515             CloseHandle( pty_handle );
516             return FALSE;
517         }
518         req->handle = handle;
519         req->file_handle = pty_handle;
520         req->pid = xpid;
521         server_call( REQ_SET_CONSOLE_FD );
522         CloseHandle( pty_handle );
523
524         /* enable mouseclicks */
525         strcpy( buf, "\033[?1001s\033[?1000h" );
526         WriteFile(handle,buf,strlen(buf),NULL,NULL);
527
528         strcpy( buf, "\033]2;" );
529         if (GetConsoleTitleA( buf + 4, sizeof(buf) - 5 ))
530         {
531             strcat( buf, "\a" );
532             WriteFile(handle,buf,strlen(buf),NULL,NULL);
533         }
534         return TRUE;
535
536 }
537
538
539 /***********************************************************************
540  *            AllocConsole (KERNEL32.103)
541  *
542  * creates an xterm with a pty to our program
543  */
544 BOOL WINAPI AllocConsole(VOID)
545 {
546     struct alloc_console_request *req = get_req_buffer();
547     HANDLE hStderr;
548     int handle_in, handle_out;
549
550     TRACE("()\n");
551     req->access  = GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE;
552     req->inherit = FALSE;
553     if (server_call( REQ_ALLOC_CONSOLE )) return FALSE;
554     handle_in = req->handle_in;
555     handle_out = req->handle_out;
556
557     if (!DuplicateHandle( GetCurrentProcess(), req->handle_out, GetCurrentProcess(), &hStderr,
558                           0, TRUE, DUPLICATE_SAME_ACCESS ))
559     {
560         CloseHandle( handle_in );
561         CloseHandle( handle_out );
562         FreeConsole();
563         return FALSE;
564     }
565
566     /* NT resets the STD_*_HANDLEs on console alloc */
567     SetStdHandle( STD_INPUT_HANDLE, handle_in );
568     SetStdHandle( STD_OUTPUT_HANDLE, handle_out );
569     SetStdHandle( STD_ERROR_HANDLE, hStderr );
570
571     SetLastError(ERROR_SUCCESS);
572     SetConsoleTitleA("Wine Console");
573     return TRUE;
574 }
575
576
577 /******************************************************************************
578  * GetConsoleCP [KERNEL32.295]  Returns the OEM code page for the console
579  *
580  * RETURNS
581  *    Code page code
582  */
583 UINT WINAPI GetConsoleCP(VOID)
584 {
585     return GetACP();
586 }
587
588
589 /***********************************************************************
590  *            GetConsoleOutputCP   (KERNEL32.189)
591  */
592 UINT WINAPI GetConsoleOutputCP(VOID)
593 {
594     return GetConsoleCP();
595 }
596
597 /***********************************************************************
598  *            GetConsoleMode   (KERNEL32.188)
599  */
600 BOOL WINAPI GetConsoleMode(HANDLE hcon,LPDWORD mode)
601 {
602     BOOL ret = FALSE;
603     struct get_console_mode_request *req = get_req_buffer();
604     req->handle = hcon;
605     if (!server_call( REQ_GET_CONSOLE_MODE ))
606     {
607         if (mode) *mode = req->mode;
608         ret = TRUE;
609     }
610     return ret;
611 }
612
613
614 /******************************************************************************
615  * SetConsoleMode [KERNEL32.628]  Sets input mode of console's input buffer
616  *
617  * PARAMS
618  *    hcon [I] Handle to console input or screen buffer
619  *    mode [I] Input or output mode to set
620  *
621  * RETURNS
622  *    Success: TRUE
623  *    Failure: FALSE
624  */
625 BOOL WINAPI SetConsoleMode( HANDLE hcon, DWORD mode )
626 {
627     struct set_console_mode_request *req = get_req_buffer();
628     req->handle = hcon;
629     req->mode = mode;
630     return !server_call( REQ_SET_CONSOLE_MODE );
631 }
632
633
634 /***********************************************************************
635  *            GetConsoleTitleA   (KERNEL32.191)
636  */
637 DWORD WINAPI GetConsoleTitleA(LPSTR title,DWORD size)
638 {
639     struct get_console_info_request *req = get_req_buffer();
640     DWORD ret = 0;
641     HANDLE hcon;
642
643     if ((hcon = CreateFileA( "CONOUT$", GENERIC_READ, 0, NULL,
644                                OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE)
645         return 0;
646     req->handle = hcon;
647     if (!server_call( REQ_GET_CONSOLE_INFO ))
648     {
649         lstrcpynA( title, req->title, size );
650         ret = strlen(req->title);
651     }
652     CloseHandle( hcon );
653     return ret;
654 }
655
656
657 /******************************************************************************
658  * GetConsoleTitle32W [KERNEL32.192]  Retrieves title string for console
659  *
660  * PARAMS
661  *    title [O] Address of buffer for title
662  *    size  [I] Size of buffer
663  *
664  * RETURNS
665  *    Success: Length of string copied
666  *    Failure: 0
667  */
668 DWORD WINAPI GetConsoleTitleW( LPWSTR title, DWORD size )
669 {
670     char *tmp;
671     DWORD ret;
672
673     if (!(tmp = HeapAlloc( GetProcessHeap(), 0, size ))) return 0;
674     ret = GetConsoleTitleA( tmp, size );
675     lstrcpyAtoW( title, tmp );
676     HeapFree( GetProcessHeap(), 0, tmp );
677     return ret;
678 }
679
680
681 /***********************************************************************
682  *            WriteConsoleA   (KERNEL32.729)
683  */
684 BOOL WINAPI WriteConsoleA( HANDLE hConsoleOutput,
685                                LPCVOID lpBuffer,
686                                DWORD nNumberOfCharsToWrite,
687                                LPDWORD lpNumberOfCharsWritten,
688                                LPVOID lpReserved )
689 {
690         /* FIXME: should I check if this is a console handle? */
691         return WriteFile(hConsoleOutput, lpBuffer, nNumberOfCharsToWrite,
692                          lpNumberOfCharsWritten, NULL);
693 }
694
695
696 #define CADD(c)                                                         \
697         if (bufused==curbufsize-1)                                      \
698             buffer = HeapReAlloc(GetProcessHeap(),0,buffer,(curbufsize+=100));\
699         buffer[bufused++]=c;
700 #define SADD(s) { char *x=s;while (*x) {CADD(*x);x++;}}
701
702 /***********************************************************************
703  *            WriteConsoleOutputA   (KERNEL32.732)
704  */
705 BOOL WINAPI WriteConsoleOutputA( HANDLE hConsoleOutput,
706                                      LPCHAR_INFO lpBuffer,
707                                      COORD dwBufferSize,
708                                      COORD dwBufferCoord,
709                                      LPSMALL_RECT lpWriteRegion)
710 {
711     int i,j,off=0,lastattr=-1;
712     char        sbuf[20],*buffer=NULL;
713     int         bufused=0,curbufsize = 100;
714     DWORD       res;
715     const int colormap[8] = {
716         0,4,2,6,
717         1,5,3,7,
718     };
719     CONSOLE_make_complex(hConsoleOutput);
720     buffer = HeapAlloc(GetProcessHeap(),0,100);
721     curbufsize = 100;
722
723     TRACE("wr: top = %d, bottom=%d, left=%d,right=%d\n",
724         lpWriteRegion->Top,
725         lpWriteRegion->Bottom,
726         lpWriteRegion->Left,
727         lpWriteRegion->Right
728     );
729
730     for (i=lpWriteRegion->Top;i<=lpWriteRegion->Bottom;i++) {
731         sprintf(sbuf,"%c[%d;%dH",27,i+1,lpWriteRegion->Left+1);
732         SADD(sbuf);
733         for (j=lpWriteRegion->Left;j<=lpWriteRegion->Right;j++) {
734             if (lastattr!=lpBuffer[off].Attributes) {
735                 lastattr = lpBuffer[off].Attributes;
736                 sprintf(sbuf,"%c[0;%s3%d;4%dm",
737                         27,
738                         (lastattr & FOREGROUND_INTENSITY)?"1;":"",
739                         colormap[lastattr&7],
740                         colormap[(lastattr&0x70)>>4]
741                 );
742                 /* FIXME: BACKGROUND_INTENSITY */
743                 SADD(sbuf);
744             }
745             CADD(lpBuffer[off].Char.AsciiChar);
746             off++;
747         }
748     }
749     sprintf(sbuf,"%c[0m",27);SADD(sbuf);
750     WriteFile(hConsoleOutput,buffer,bufused,&res,NULL);
751     HeapFree(GetProcessHeap(),0,buffer);
752     return TRUE;
753 }
754
755 /***********************************************************************
756  *            WriteConsoleW   (KERNEL32.577)
757  */
758 BOOL WINAPI WriteConsoleW( HANDLE hConsoleOutput,
759                                LPCVOID lpBuffer,
760                                DWORD nNumberOfCharsToWrite,
761                                LPDWORD lpNumberOfCharsWritten,
762                                LPVOID lpReserved )
763 {
764         BOOL ret;
765         LPSTR xstring=HeapAlloc( GetProcessHeap(), 0, nNumberOfCharsToWrite );
766
767         lstrcpynWtoA( xstring,  lpBuffer,nNumberOfCharsToWrite);
768
769         /* FIXME: should I check if this is a console handle? */
770         ret= WriteFile(hConsoleOutput, xstring, nNumberOfCharsToWrite,
771                          lpNumberOfCharsWritten, NULL);
772         HeapFree( GetProcessHeap(), 0, xstring );
773         return ret;
774 }
775
776
777 /***********************************************************************
778  *            ReadConsoleA   (KERNEL32.419)
779  */
780 BOOL WINAPI ReadConsoleA( HANDLE hConsoleInput,
781                               LPVOID lpBuffer,
782                               DWORD nNumberOfCharsToRead,
783                               LPDWORD lpNumberOfCharsRead,
784                               LPVOID lpReserved )
785 {
786     int         charsread = 0;
787     LPSTR       xbuf = (LPSTR)lpBuffer;
788     INPUT_RECORD        ir;
789
790     TRACE("(%d,%p,%ld,%p,%p)\n",
791             hConsoleInput,lpBuffer,nNumberOfCharsToRead,
792             lpNumberOfCharsRead,lpReserved
793     );
794
795     CONSOLE_get_input(hConsoleInput,FALSE);
796
797     /* FIXME: should we read at least 1 char? The SDK does not say */
798     while (charsread<nNumberOfCharsToRead)
799     {
800         struct read_console_input_request *req = get_req_buffer();
801         req->handle = hConsoleInput;
802         req->count = 1;
803         req->flush = 1;
804         if (server_call( REQ_READ_CONSOLE_INPUT )) return FALSE;
805         if (!req->read) break;
806         if (!ir.Event.KeyEvent.bKeyDown)
807                 continue;
808         if (ir.EventType != KEY_EVENT)
809                 continue;
810         *xbuf++ = ir.Event.KeyEvent.uChar.AsciiChar; 
811         charsread++;
812     }
813     if (lpNumberOfCharsRead)
814         *lpNumberOfCharsRead = charsread;
815     return TRUE;
816 }
817
818 /***********************************************************************
819  *            ReadConsoleW   (KERNEL32.427)
820  */
821 BOOL WINAPI ReadConsoleW( HANDLE hConsoleInput,
822                               LPVOID lpBuffer,
823                               DWORD nNumberOfCharsToRead,
824                               LPDWORD lpNumberOfCharsRead,
825                               LPVOID lpReserved )
826 {
827     BOOL ret;
828     LPSTR buf = (LPSTR)HeapAlloc(GetProcessHeap(), 0, nNumberOfCharsToRead);
829
830     ret = ReadConsoleA(
831         hConsoleInput,
832         buf,
833         nNumberOfCharsToRead,
834         lpNumberOfCharsRead,
835         lpReserved
836     );
837     if (ret)
838         lstrcpynAtoW(lpBuffer,buf,nNumberOfCharsToRead);
839     HeapFree( GetProcessHeap(), 0, buf );
840     return ret;
841 }
842
843
844 /******************************************************************************
845  * ReadConsoleInput32A [KERNEL32.569]  Reads data from a console
846  *
847  * PARAMS
848  *    hConsoleInput        [I] Handle to console input buffer
849  *    lpBuffer             [O] Address of buffer for read data
850  *    nLength              [I] Number of records to read
851  *    lpNumberOfEventsRead [O] Address of number of records read
852  *
853  * RETURNS
854  *    Success: TRUE
855  *    Failure: FALSE
856  */
857 BOOL WINAPI ReadConsoleInputA(HANDLE hConsoleInput, LPINPUT_RECORD lpBuffer,
858                               DWORD nLength, LPDWORD lpNumberOfEventsRead)
859 {
860     struct read_console_input_request *req = get_req_buffer();
861
862     /* loop until we get at least one event */
863     for (;;)
864     {
865         req->handle = hConsoleInput;
866         req->count = nLength;
867         req->flush = 1;
868         if (server_call( REQ_READ_CONSOLE_INPUT )) return FALSE;
869         if (req->read)
870         {
871             memcpy( lpBuffer, req + 1, req->read * sizeof(*lpBuffer) );
872             if (lpNumberOfEventsRead) *lpNumberOfEventsRead = req->read;
873             return TRUE;
874         }
875         CONSOLE_get_input(hConsoleInput,TRUE);
876         /*WaitForSingleObject( hConsoleInput, INFINITE32 );*/
877     }
878 }
879
880
881 /***********************************************************************
882  *            ReadConsoleInput32W   (KERNEL32.570)
883  */
884 BOOL WINAPI ReadConsoleInputW( HANDLE handle, LPINPUT_RECORD buffer,
885                                    DWORD count, LPDWORD read )
886 {
887     /* FIXME: Fix this if we get UNICODE input. */
888     return ReadConsoleInputA( handle, buffer, count, read );
889 }
890
891
892 /***********************************************************************
893  *            FlushConsoleInputBuffer   (KERNEL32.132)
894  */
895 BOOL WINAPI FlushConsoleInputBuffer( HANDLE handle )
896 {
897     struct read_console_input_request *req = get_req_buffer();
898     req->handle = handle;
899     req->count = -1;  /* get all records */
900     req->flush = 1;
901     return !server_call( REQ_READ_CONSOLE_INPUT );
902 }
903
904
905 /***********************************************************************
906  *            PeekConsoleInputA   (KERNEL32.550)
907  *
908  * Gets 'count' first events (or less) from input queue.
909  *
910  * Does not need a complex console.
911  */
912 BOOL WINAPI PeekConsoleInputA( HANDLE handle, LPINPUT_RECORD buffer,
913                                    DWORD count, LPDWORD read )
914 {
915     struct read_console_input_request *req = get_req_buffer();
916
917     CONSOLE_get_input(handle,FALSE);
918
919     req->handle = handle;
920     req->count = count;
921     req->flush = 0;
922     if (server_call( REQ_READ_CONSOLE_INPUT )) return FALSE;
923     if (req->read) memcpy( buffer, req + 1, req->read * sizeof(*buffer) );
924     if (read) *read = req->read;
925     return TRUE;
926 }
927
928
929 /***********************************************************************
930  *            PeekConsoleInputW   (KERNEL32.551)
931  */
932 BOOL WINAPI PeekConsoleInputW(HANDLE hConsoleInput,
933                                   LPINPUT_RECORD pirBuffer,
934                                   DWORD cInRecords,
935                                   LPDWORD lpcRead)
936 {
937     /* FIXME: Hmm. Fix this if we get UNICODE input. */
938     return PeekConsoleInputA(hConsoleInput,pirBuffer,cInRecords,lpcRead);
939 }
940
941
942 /******************************************************************************
943  * WriteConsoleInput32A [KERNEL32.730]  Write data to a console input buffer
944  *
945  */
946 BOOL WINAPI WriteConsoleInputA( HANDLE handle, INPUT_RECORD *buffer,
947                                 DWORD count, LPDWORD written )
948 {
949     struct write_console_input_request *req = get_req_buffer();
950     const DWORD max = server_remaining( req + 1 ) / sizeof(INPUT_RECORD);
951
952     if (written) *written = 0;
953     while (count)
954     {
955         DWORD len = count < max ? count : max;
956         req->count = len;
957         req->handle = handle;
958         memcpy( req + 1, buffer, len * sizeof(*buffer) );
959         if (server_call( REQ_WRITE_CONSOLE_INPUT )) return FALSE;
960         if (written) *written += req->written;
961         count -= len;
962         buffer += len;
963     }
964     return TRUE;
965 }
966
967
968 /***********************************************************************
969  *            SetConsoleTitle32A   (KERNEL32.476)
970  *
971  * Sets the console title.
972  *
973  * We do not necessarily need to create a complex console for that,
974  * but should remember the title and set it on creation of the latter.
975  * (not fixed at this time).
976  */
977 BOOL WINAPI SetConsoleTitleA(LPCSTR title)
978 {
979     struct set_console_info_request *req = get_req_buffer();
980     HANDLE hcon;
981     DWORD written;
982
983     if ((hcon = CreateFileA( "CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL,
984                                OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE)
985         return FALSE;
986     req->handle = hcon;
987     req->mask = SET_CONSOLE_INFO_TITLE;
988     lstrcpynA( req->title, title, server_remaining(req->title) );
989     if (server_call( REQ_SET_CONSOLE_INFO )) goto error;
990     if (CONSOLE_GetPid( hcon ))
991     {
992         /* only set title for complex console (own xterm) */
993         WriteFile( hcon, "\033]2;", 4, &written, NULL );
994         WriteFile( hcon, title, strlen(title), &written, NULL );
995         WriteFile( hcon, "\a", 1, &written, NULL );
996     }
997     CloseHandle( hcon );
998     return TRUE;
999  error:
1000     CloseHandle( hcon );
1001     return FALSE;
1002 }
1003
1004
1005 /******************************************************************************
1006  * SetConsoleTitle32W [KERNEL32.477]  Sets title bar string for console
1007  *
1008  * PARAMS
1009  *    title [I] Address of new title
1010  *
1011  * NOTES
1012  *    This should not be calling the A version
1013  *
1014  * RETURNS
1015  *    Success: TRUE
1016  *    Failure: FALSE
1017  */
1018 BOOL WINAPI SetConsoleTitleW( LPCWSTR title )
1019 {
1020     BOOL ret;
1021
1022     LPSTR titleA = HEAP_strdupWtoA( GetProcessHeap(), 0, title );
1023     ret = SetConsoleTitleA(titleA);
1024     HeapFree( GetProcessHeap(), 0, titleA );
1025     return ret;
1026 }
1027
1028 /******************************************************************************
1029  * SetConsoleCursorPosition [KERNEL32.627]
1030  * Sets the cursor position in console
1031  *
1032  * PARAMS
1033  *    hConsoleOutput   [I] Handle of console screen buffer
1034  *    dwCursorPosition [I] New cursor position coordinates
1035  *
1036  * RETURNS STD
1037  */
1038 BOOL WINAPI SetConsoleCursorPosition( HANDLE hcon, COORD pos )
1039 {
1040     char        xbuf[20];
1041     DWORD       xlen;
1042
1043     /* make console complex only if we change lines, not just in the line */
1044     if (pos.y)
1045         CONSOLE_make_complex(hcon);
1046
1047     TRACE("%d (%dx%d)\n", hcon, pos.x , pos.y );
1048     /* x are columns, y rows */
1049     if (pos.y) 
1050         /* full screen cursor absolute positioning */
1051         sprintf(xbuf,"%c[%d;%dH", 0x1B, pos.y+1, pos.x+1);
1052     else
1053         /* relative cursor positioning in line (\r to go to 0) */
1054         sprintf(xbuf,"\r%c[%dC", 0x1B, pos.x);
1055     /* FIXME: store internal if we start using own console buffers */
1056     WriteFile(hcon,xbuf,strlen(xbuf),&xlen,NULL);
1057     return TRUE;
1058 }
1059
1060 /***********************************************************************
1061  *            GetNumberOfConsoleInputEvents   (KERNEL32.246)
1062  */
1063 BOOL WINAPI GetNumberOfConsoleInputEvents(HANDLE hcon,LPDWORD nrofevents)
1064 {
1065     CONSOLE_get_input(hcon,FALSE);
1066     *nrofevents = 1; /* UMM */
1067     return TRUE;
1068 }
1069
1070 /***********************************************************************
1071  *            GetNumberOfConsoleMouseButtons   (KERNEL32.358)
1072  */
1073 BOOL WINAPI GetNumberOfConsoleMouseButtons(LPDWORD nrofbuttons)
1074 {
1075     FIXME("(%p): stub\n", nrofbuttons);
1076     *nrofbuttons = 2;
1077     return TRUE;
1078 }
1079
1080 /******************************************************************************
1081  * GetConsoleCursorInfo32 [KERNEL32.296]  Gets size and visibility of console
1082  *
1083  * PARAMS
1084  *    hcon  [I] Handle to console screen buffer
1085  *    cinfo [O] Address of cursor information
1086  *
1087  * RETURNS
1088  *    Success: TRUE
1089  *    Failure: FALSE
1090  */
1091 BOOL WINAPI GetConsoleCursorInfo( HANDLE hcon, LPCONSOLE_CURSOR_INFO cinfo )
1092 {
1093     struct get_console_info_request *req = get_req_buffer();
1094     req->handle = hcon;
1095     if (server_call( REQ_GET_CONSOLE_INFO )) return FALSE;
1096     if (cinfo)
1097     {
1098         cinfo->dwSize = req->cursor_size;
1099         cinfo->bVisible = req->cursor_visible;
1100     }
1101     return TRUE;
1102 }
1103
1104
1105 /******************************************************************************
1106  * SetConsoleCursorInfo32 [KERNEL32.626]  Sets size and visibility of cursor
1107  *
1108  * RETURNS
1109  *    Success: TRUE
1110  *    Failure: FALSE
1111  */
1112 BOOL WINAPI SetConsoleCursorInfo( 
1113     HANDLE hcon,                /* [in] Handle to console screen buffer */
1114     LPCONSOLE_CURSOR_INFO cinfo)  /* [in] Address of cursor information */
1115 {
1116     struct set_console_info_request *req = get_req_buffer();
1117     char        buf[8];
1118     DWORD       xlen;
1119
1120     CONSOLE_make_complex(hcon);
1121     sprintf(buf,"\033[?25%c",cinfo->bVisible?'h':'l');
1122     WriteFile(hcon,buf,strlen(buf),&xlen,NULL);
1123
1124     req->handle         = hcon;
1125     req->cursor_size    = cinfo->dwSize;
1126     req->cursor_visible = cinfo->bVisible;
1127     req->mask           = SET_CONSOLE_INFO_CURSOR;
1128     return !server_call( REQ_SET_CONSOLE_INFO );
1129 }
1130
1131
1132 /******************************************************************************
1133  * SetConsoleWindowInfo [KERNEL32.634]  Sets size and position of console
1134  *
1135  * RETURNS
1136  *    Success: TRUE
1137  *    Failure: FALSE
1138  */
1139 BOOL WINAPI SetConsoleWindowInfo(
1140     HANDLE hcon,       /* [in] Handle to console screen buffer */
1141     BOOL bAbsolute,    /* [in] Coordinate type flag */
1142     LPSMALL_RECT window) /* [in] Address of new window rectangle */
1143 {
1144     FIXME("(%x,%d,%p): stub\n", hcon, bAbsolute, window);
1145     return TRUE;
1146 }
1147
1148
1149 /******************************************************************************
1150  * SetConsoleTextAttribute32 [KERNEL32.631]  Sets colors for text
1151  *
1152  * Sets the foreground and background color attributes of characters
1153  * written to the screen buffer.
1154  *
1155  * RETURNS
1156  *    Success: TRUE
1157  *    Failure: FALSE
1158  */
1159 BOOL WINAPI SetConsoleTextAttribute(HANDLE hConsoleOutput,WORD wAttr)
1160 {
1161     const int colormap[8] = {
1162         0,4,2,6,
1163         1,5,3,7,
1164     };
1165     DWORD xlen;
1166     char buffer[20];
1167
1168     TRACE("(%d,%d)\n",hConsoleOutput,wAttr);
1169     sprintf(buffer,"%c[0;%s3%d;4%dm",
1170         27,
1171         (wAttr & FOREGROUND_INTENSITY)?"1;":"",
1172         colormap[wAttr&7],
1173         colormap[(wAttr&0x70)>>4]
1174     );
1175     WriteFile(hConsoleOutput,buffer,strlen(buffer),&xlen,NULL);
1176     return TRUE;
1177 }
1178
1179
1180 /******************************************************************************
1181  * SetConsoleScreenBufferSize [KERNEL32.630]  Changes size of console 
1182  *
1183  * PARAMS
1184  *    hConsoleOutput [I] Handle to console screen buffer
1185  *    dwSize         [I] New size in character rows and cols
1186  *
1187  * RETURNS
1188  *    Success: TRUE
1189  *    Failure: FALSE
1190  */
1191 BOOL WINAPI SetConsoleScreenBufferSize( HANDLE hConsoleOutput, 
1192                                           COORD dwSize )
1193 {
1194     FIXME("(%d,%dx%d): stub\n",hConsoleOutput,dwSize.x,dwSize.y);
1195     return TRUE;
1196 }
1197
1198
1199 /******************************************************************************
1200  * FillConsoleOutputCharacterA [KERNEL32.242]
1201  *
1202  * PARAMS
1203  *    hConsoleOutput    [I] Handle to screen buffer
1204  *    cCharacter        [I] Character to write
1205  *    nLength           [I] Number of cells to write to
1206  *    dwCoord           [I] Coords of first cell
1207  *    lpNumCharsWritten [O] Pointer to number of cells written
1208  *
1209  * RETURNS
1210  *    Success: TRUE
1211  *    Failure: FALSE
1212  */
1213 BOOL WINAPI FillConsoleOutputCharacterA(
1214     HANDLE hConsoleOutput,
1215     BYTE cCharacter,
1216     DWORD nLength,
1217     COORD dwCoord,
1218     LPDWORD lpNumCharsWritten)
1219 {
1220     long        count;
1221     DWORD       xlen;
1222
1223     SetConsoleCursorPosition(hConsoleOutput,dwCoord);
1224     for(count=0;count<nLength;count++)
1225         WriteFile(hConsoleOutput,&cCharacter,1,&xlen,NULL);
1226     *lpNumCharsWritten = nLength;
1227     return TRUE;
1228 }
1229
1230
1231 /******************************************************************************
1232  * FillConsoleOutputCharacterW [KERNEL32.243]  Writes characters to console
1233  *
1234  * PARAMS
1235  *    hConsoleOutput    [I] Handle to screen buffer
1236  *    cCharacter        [I] Character to write
1237  *    nLength           [I] Number of cells to write to
1238  *    dwCoord           [I] Coords of first cell
1239  *    lpNumCharsWritten [O] Pointer to number of cells written
1240  *
1241  * RETURNS
1242  *    Success: TRUE
1243  *    Failure: FALSE
1244  */
1245 BOOL WINAPI FillConsoleOutputCharacterW(HANDLE hConsoleOutput,
1246                                             WCHAR cCharacter,
1247                                             DWORD nLength,
1248                                            COORD dwCoord, 
1249                                             LPDWORD lpNumCharsWritten)
1250 {
1251     long        count;
1252     DWORD       xlen;
1253
1254     SetConsoleCursorPosition(hConsoleOutput,dwCoord);
1255     /* FIXME: not quite correct ... but the lower part of UNICODE char comes
1256      * first 
1257      */
1258     for(count=0;count<nLength;count++)
1259         WriteFile(hConsoleOutput,&cCharacter,1,&xlen,NULL);
1260     *lpNumCharsWritten = nLength;
1261     return TRUE;
1262 }
1263
1264
1265 /******************************************************************************
1266  * FillConsoleOutputAttribute [KERNEL32.241]  Sets attributes for console
1267  *
1268  * PARAMS
1269  *    hConsoleOutput    [I] Handle to screen buffer
1270  *    wAttribute        [I] Color attribute to write
1271  *    nLength           [I] Number of cells to write to
1272  *    dwCoord           [I] Coords of first cell
1273  *    lpNumAttrsWritten [O] Pointer to number of cells written
1274  *
1275  * RETURNS
1276  *    Success: TRUE
1277  *    Failure: FALSE
1278  */
1279 BOOL WINAPI FillConsoleOutputAttribute( HANDLE hConsoleOutput, 
1280               WORD wAttribute, DWORD nLength, COORD dwCoord, 
1281               LPDWORD lpNumAttrsWritten)
1282 {
1283     FIXME("(%d,%d,%ld,%dx%d,%p): stub\n", hConsoleOutput,
1284           wAttribute,nLength,dwCoord.x,dwCoord.y,lpNumAttrsWritten);
1285     *lpNumAttrsWritten = nLength;
1286     return TRUE;
1287 }
1288
1289 /******************************************************************************
1290  * ReadConsoleOutputCharacter32A [KERNEL32.573]
1291  * 
1292  * BUGS
1293  *   Unimplemented
1294  */
1295 BOOL WINAPI ReadConsoleOutputCharacterA(HANDLE hConsoleOutput, 
1296               LPSTR lpstr, DWORD dword, COORD coord, LPDWORD lpdword)
1297 {
1298     FIXME("(%d,%p,%ld,%dx%d,%p): stub\n", hConsoleOutput,lpstr,
1299           dword,coord.x,coord.y,lpdword);
1300     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1301     return FALSE;
1302 }
1303
1304
1305 /******************************************************************************
1306  * ScrollConsoleScreenBuffer [KERNEL32.612]
1307  * 
1308  * BUGS
1309  *   Unimplemented
1310  */
1311 BOOL WINAPI ScrollConsoleScreenBuffer( HANDLE hConsoleOutput, 
1312               LPSMALL_RECT lpScrollRect, LPSMALL_RECT lpClipRect,
1313               COORD dwDestOrigin, LPCHAR_INFO lpFill)
1314 {
1315     FIXME("(%d,%p,%p,%dx%d,%p): stub\n", hConsoleOutput,lpScrollRect,
1316           lpClipRect,dwDestOrigin.x,dwDestOrigin.y,lpFill);
1317     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1318     return FALSE;
1319 }