po: Update Lithuanian translation.
[wine.git] / dlls / kernelbase / console.c
blob91e8129fbe2fa6afcd9a807be93d9cf4de3b2264
1 /*
2 * Win32 console functions
4 * Copyright 1995 Martin von Loewis and Cameron Heide
5 * Copyright 1997 Karl Garrison
6 * Copyright 1998 John Richardson
7 * Copyright 1998 Marcus Meissner
8 * Copyright 2001,2002,2004,2005,2010 Eric Pouech
9 * Copyright 2001 Alexandre Julliard
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.
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.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <limits.h>
31 #define NONAMELESSUNION
32 #include "ntstatus.h"
33 #define WIN32_NO_STATUS
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winnls.h"
37 #include "winerror.h"
38 #include "wincon.h"
39 #include "wine/server.h"
40 #include "wine/exception.h"
41 #include "wine/debug.h"
42 #include "kernelbase.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(console);
47 static CRITICAL_SECTION console_section;
48 static CRITICAL_SECTION_DEBUG critsect_debug =
50 0, 0, &console_section,
51 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
52 0, 0, { (DWORD_PTR)(__FILE__ ": console_section") }
54 static CRITICAL_SECTION console_section = { &critsect_debug, -1, 0, 0, 0, 0 };
56 static WCHAR input_exe[MAX_PATH + 1];
59 /* map a kernel32 console handle onto a real wineserver handle */
60 static inline obj_handle_t console_handle_unmap( HANDLE h )
62 return wine_server_obj_handle( console_handle_map( h ) );
65 /* map input records to ASCII */
66 static void input_records_WtoA( INPUT_RECORD *buffer, int count )
68 UINT cp = GetConsoleCP();
69 int i;
70 char ch;
72 for (i = 0; i < count; i++)
74 if (buffer[i].EventType != KEY_EVENT) continue;
75 WideCharToMultiByte( cp, 0, &buffer[i].Event.KeyEvent.uChar.UnicodeChar, 1, &ch, 1, NULL, NULL );
76 buffer[i].Event.KeyEvent.uChar.AsciiChar = ch;
80 /* map input records to Unicode */
81 static void input_records_AtoW( INPUT_RECORD *buffer, int count )
83 UINT cp = GetConsoleCP();
84 int i;
85 WCHAR ch;
87 for (i = 0; i < count; i++)
89 if (buffer[i].EventType != KEY_EVENT) continue;
90 MultiByteToWideChar( cp, 0, &buffer[i].Event.KeyEvent.uChar.AsciiChar, 1, &ch, 1 );
91 buffer[i].Event.KeyEvent.uChar.UnicodeChar = ch;
95 /* map char infos to ASCII */
96 static void char_info_WtoA( CHAR_INFO *buffer, int count )
98 UINT cp = GetConsoleOutputCP();
99 char ch;
101 while (count-- > 0)
103 WideCharToMultiByte( cp, 0, &buffer->Char.UnicodeChar, 1, &ch, 1, NULL, NULL );
104 buffer->Char.AsciiChar = ch;
105 buffer++;
109 /* map char infos to Unicode */
110 static void char_info_AtoW( CHAR_INFO *buffer, int count )
112 UINT cp = GetConsoleOutputCP();
113 WCHAR ch;
115 while (count-- > 0)
117 MultiByteToWideChar( cp, 0, &buffer->Char.AsciiChar, 1, &ch, 1 );
118 buffer->Char.UnicodeChar = ch;
119 buffer++;
123 /* helper function for ScrollConsoleScreenBufferW */
124 static void fill_console_output( HANDLE handle, int i, int j, int len, CHAR_INFO *fill )
126 SERVER_START_REQ( fill_console_output )
128 req->handle = console_handle_unmap( handle );
129 req->mode = CHAR_INFO_MODE_TEXTATTR;
130 req->x = i;
131 req->y = j;
132 req->count = len;
133 req->wrap = FALSE;
134 req->data.ch = fill->Char.UnicodeChar;
135 req->data.attr = fill->Attributes;
136 wine_server_call_err( req );
138 SERVER_END_REQ;
141 /* helper function for GetLargestConsoleWindowSize */
142 static COORD get_largest_console_window_size( HANDLE handle )
144 COORD c = { 0, 0 };
146 SERVER_START_REQ( get_console_output_info )
148 req->handle = console_handle_unmap( handle );
149 if (!wine_server_call_err( req ))
151 c.X = reply->max_width;
152 c.Y = reply->max_height;
155 SERVER_END_REQ;
156 TRACE( "(%p), returning %dx%d\n", handle, c.X, c.Y );
157 return c;
160 /* helper function to replace OpenConsoleW */
161 HANDLE open_console( BOOL output, DWORD access, SECURITY_ATTRIBUTES *sa, DWORD creation )
163 HANDLE ret;
165 if (creation != OPEN_EXISTING)
167 SetLastError( ERROR_INVALID_PARAMETER );
168 return INVALID_HANDLE_VALUE;
171 SERVER_START_REQ( open_console )
173 req->from = wine_server_obj_handle( ULongToHandle( output ));
174 req->access = access;
175 req->attributes = sa && sa->bInheritHandle ? OBJ_INHERIT : 0;
176 req->share = FILE_SHARE_READ | FILE_SHARE_WRITE;
177 wine_server_call_err( req );
178 ret = wine_server_ptr_handle( reply->handle );
180 SERVER_END_REQ;
181 if (ret) ret = console_handle_map( ret );
182 return ret;
186 /******************************************************************
187 * AttachConsole (kernelbase.@)
189 BOOL WINAPI DECLSPEC_HOTPATCH AttachConsole( DWORD pid )
191 BOOL ret;
193 TRACE( "(%x)\n", pid );
195 SERVER_START_REQ( attach_console )
197 req->pid = pid;
198 if ((ret = !wine_server_call_err( req )))
200 SetStdHandle( STD_INPUT_HANDLE, wine_server_ptr_handle( reply->std_in ));
201 SetStdHandle( STD_OUTPUT_HANDLE, wine_server_ptr_handle( reply->std_out ));
202 SetStdHandle( STD_ERROR_HANDLE, wine_server_ptr_handle( reply->std_err ));
205 SERVER_END_REQ;
206 return ret;
210 /******************************************************************************
211 * CreateConsoleScreenBuffer (kernelbase.@)
213 HANDLE WINAPI DECLSPEC_HOTPATCH CreateConsoleScreenBuffer( DWORD access, DWORD share,
214 SECURITY_ATTRIBUTES *sa, DWORD flags,
215 void *data )
217 HANDLE ret = INVALID_HANDLE_VALUE;
219 TRACE( "(%x,%x,%p,%x,%p)\n", access, share, sa, flags, data );
221 if (flags != CONSOLE_TEXTMODE_BUFFER || data)
223 SetLastError( ERROR_INVALID_PARAMETER );
224 return INVALID_HANDLE_VALUE;
227 SERVER_START_REQ( create_console_output )
229 req->handle_in = 0;
230 req->access = access;
231 req->attributes = (sa && sa->bInheritHandle) ? OBJ_INHERIT : 0;
232 req->share = share;
233 req->fd = -1;
234 if (!wine_server_call_err( req ))
235 ret = console_handle_map( wine_server_ptr_handle( reply->handle_out ));
237 SERVER_END_REQ;
238 return ret;
242 /******************************************************************************
243 * FillConsoleOutputAttribute (kernelbase.@)
245 BOOL WINAPI DECLSPEC_HOTPATCH FillConsoleOutputAttribute( HANDLE handle, WORD attr, DWORD length,
246 COORD coord, DWORD *written )
248 BOOL ret;
250 TRACE( "(%p,%d,%d,(%dx%d),%p)\n", handle, attr, length, coord.X, coord.Y, written );
252 if (!written)
254 SetLastError( ERROR_INVALID_ACCESS );
255 return FALSE;
258 *written = 0;
259 SERVER_START_REQ( fill_console_output )
261 req->handle = console_handle_unmap( handle );
262 req->x = coord.X;
263 req->y = coord.Y;
264 req->mode = CHAR_INFO_MODE_ATTR;
265 req->wrap = TRUE;
266 req->data.attr = attr;
267 req->count = length;
268 if ((ret = !wine_server_call_err( req ))) *written = reply->written;
270 SERVER_END_REQ;
271 return ret;
275 /******************************************************************************
276 * FillConsoleOutputCharacterA (kernelbase.@)
278 BOOL WINAPI DECLSPEC_HOTPATCH FillConsoleOutputCharacterA( HANDLE handle, CHAR ch, DWORD length,
279 COORD coord, DWORD *written )
281 WCHAR wch;
283 MultiByteToWideChar( GetConsoleOutputCP(), 0, &ch, 1, &wch, 1 );
284 return FillConsoleOutputCharacterW( handle, wch, length, coord, written );
288 /******************************************************************************
289 * FillConsoleOutputCharacterW (kernelbase.@)
291 BOOL WINAPI DECLSPEC_HOTPATCH FillConsoleOutputCharacterW( HANDLE handle, WCHAR ch, DWORD length,
292 COORD coord, DWORD *written )
294 BOOL ret;
296 TRACE( "(%p,%s,%d,(%dx%d),%p)\n", handle, debugstr_wn(&ch, 1), length, coord.X, coord.Y, written );
298 if (!written)
300 SetLastError( ERROR_INVALID_ACCESS );
301 return FALSE;
304 *written = 0;
305 SERVER_START_REQ( fill_console_output )
307 req->handle = console_handle_unmap( handle );
308 req->x = coord.X;
309 req->y = coord.Y;
310 req->mode = CHAR_INFO_MODE_TEXT;
311 req->wrap = TRUE;
312 req->data.ch = ch;
313 req->count = length;
314 if ((ret = !wine_server_call_err( req ))) *written = reply->written;
316 SERVER_END_REQ;
317 return ret;
321 /***********************************************************************
322 * FreeConsole (kernelbase.@)
324 BOOL WINAPI DECLSPEC_HOTPATCH FreeConsole(void)
326 BOOL ret;
328 SERVER_START_REQ( free_console )
330 ret = !wine_server_call_err( req );
332 SERVER_END_REQ;
333 return ret;
337 /******************************************************************************
338 * GenerateConsoleCtrlEvent (kernelbase.@)
340 BOOL WINAPI DECLSPEC_HOTPATCH GenerateConsoleCtrlEvent( DWORD event, DWORD group )
342 BOOL ret;
344 TRACE( "(%d, %x)\n", event, group );
346 if (event != CTRL_C_EVENT && event != CTRL_BREAK_EVENT)
348 ERR( "Invalid event %d for PGID %x\n", event, group );
349 return FALSE;
352 SERVER_START_REQ( send_console_signal )
354 req->signal = event;
355 req->group_id = group;
356 ret = !wine_server_call_err( req );
358 SERVER_END_REQ;
359 return ret;
363 /******************************************************************************
364 * GetConsoleCP (kernelbase.@)
366 UINT WINAPI DECLSPEC_HOTPATCH GetConsoleCP(void)
368 UINT codepage = GetOEMCP(); /* default value */
370 SERVER_START_REQ( get_console_input_info )
372 req->handle = 0;
373 if (!wine_server_call_err( req ))
375 if (reply->input_cp) codepage = reply->input_cp;
378 SERVER_END_REQ;
379 return codepage;
383 /******************************************************************************
384 * GetConsoleCursorInfo (kernelbase.@)
386 BOOL WINAPI DECLSPEC_HOTPATCH GetConsoleCursorInfo( HANDLE handle, CONSOLE_CURSOR_INFO *info )
388 BOOL ret;
390 SERVER_START_REQ( get_console_output_info )
392 req->handle = console_handle_unmap( handle );
393 ret = !wine_server_call_err( req );
394 if (ret && info)
396 info->dwSize = reply->cursor_size;
397 info->bVisible = reply->cursor_visible;
400 SERVER_END_REQ;
402 if (!ret) return FALSE;
403 if (!info)
405 SetLastError( ERROR_INVALID_ACCESS );
406 return FALSE;
408 TRACE("(%p) returning (%d,%d)\n", handle, info->dwSize, info->bVisible);
409 return TRUE;
413 /***********************************************************************
414 * GetConsoleInputExeNameA (kernelbase.@)
416 BOOL WINAPI DECLSPEC_HOTPATCH GetConsoleInputExeNameA( DWORD len, LPSTR buffer )
418 RtlEnterCriticalSection( &console_section );
419 if (WideCharToMultiByte( CP_ACP, 0, input_exe, -1, NULL, 0, NULL, NULL ) <= len)
420 WideCharToMultiByte( CP_ACP, 0, input_exe, -1, buffer, len, NULL, NULL );
421 else SetLastError(ERROR_BUFFER_OVERFLOW);
422 RtlLeaveCriticalSection( &console_section );
423 return TRUE;
427 /***********************************************************************
428 * GetConsoleInputExeNameW (kernelbase.@)
430 BOOL WINAPI DECLSPEC_HOTPATCH GetConsoleInputExeNameW( DWORD len, LPWSTR buffer )
432 RtlEnterCriticalSection( &console_section );
433 if (len > lstrlenW(input_exe)) lstrcpyW( buffer, input_exe );
434 else SetLastError( ERROR_BUFFER_OVERFLOW );
435 RtlLeaveCriticalSection( &console_section );
436 return TRUE;
440 /***********************************************************************
441 * GetConsoleMode (kernelbase.@)
443 BOOL WINAPI DECLSPEC_HOTPATCH GetConsoleMode( HANDLE handle, DWORD *mode )
445 BOOL ret;
447 SERVER_START_REQ( get_console_mode )
449 req->handle = console_handle_unmap( handle );
450 if ((ret = !wine_server_call_err( req )))
452 if (mode) *mode = reply->mode;
455 SERVER_END_REQ;
456 return ret;
460 /***********************************************************************
461 * GetConsoleOutputCP (kernelbase.@)
463 UINT WINAPI DECLSPEC_HOTPATCH GetConsoleOutputCP(void)
465 UINT codepage = GetOEMCP(); /* default value */
467 SERVER_START_REQ( get_console_input_info )
469 req->handle = 0;
470 if (!wine_server_call_err( req ))
472 if (reply->output_cp) codepage = reply->output_cp;
475 SERVER_END_REQ;
476 return codepage;
480 /***********************************************************************
481 * GetConsoleScreenBufferInfo (kernelbase.@)
483 BOOL WINAPI DECLSPEC_HOTPATCH GetConsoleScreenBufferInfo( HANDLE handle, CONSOLE_SCREEN_BUFFER_INFO *info )
485 BOOL ret;
487 SERVER_START_REQ( get_console_output_info )
489 req->handle = console_handle_unmap( handle );
490 if ((ret = !wine_server_call_err( req )))
492 info->dwSize.X = reply->width;
493 info->dwSize.Y = reply->height;
494 info->dwCursorPosition.X = reply->cursor_x;
495 info->dwCursorPosition.Y = reply->cursor_y;
496 info->wAttributes = reply->attr;
497 info->srWindow.Left = reply->win_left;
498 info->srWindow.Right = reply->win_right;
499 info->srWindow.Top = reply->win_top;
500 info->srWindow.Bottom = reply->win_bottom;
501 info->dwMaximumWindowSize.X = min(reply->width, reply->max_width);
502 info->dwMaximumWindowSize.Y = min(reply->height, reply->max_height);
505 SERVER_END_REQ;
507 TRACE( "(%p,(%d,%d) (%d,%d) %d (%d,%d-%d,%d) (%d,%d)\n", handle,
508 info->dwSize.X, info->dwSize.Y, info->dwCursorPosition.X, info->dwCursorPosition.Y,
509 info->wAttributes, info->srWindow.Left, info->srWindow.Top, info->srWindow.Right,
510 info->srWindow.Bottom, info->dwMaximumWindowSize.X, info->dwMaximumWindowSize.Y );
511 return ret;
515 /***********************************************************************
516 * GetConsoleScreenBufferInfoEx (kernelbase.@)
518 BOOL WINAPI DECLSPEC_HOTPATCH GetConsoleScreenBufferInfoEx( HANDLE handle,
519 CONSOLE_SCREEN_BUFFER_INFOEX *info )
521 BOOL ret;
523 if (info->cbSize != sizeof(CONSOLE_SCREEN_BUFFER_INFOEX))
525 SetLastError( ERROR_INVALID_PARAMETER );
526 return FALSE;
529 SERVER_START_REQ( get_console_output_info )
531 req->handle = console_handle_unmap( handle );
532 wine_server_set_reply( req, info->ColorTable, sizeof(info->ColorTable) );
533 if ((ret = !wine_server_call_err( req )))
535 info->dwSize.X = reply->width;
536 info->dwSize.Y = reply->height;
537 info->dwCursorPosition.X = reply->cursor_x;
538 info->dwCursorPosition.Y = reply->cursor_y;
539 info->wAttributes = reply->attr;
540 info->srWindow.Left = reply->win_left;
541 info->srWindow.Top = reply->win_top;
542 info->srWindow.Right = reply->win_right;
543 info->srWindow.Bottom = reply->win_bottom;
544 info->dwMaximumWindowSize.X = min( reply->width, reply->max_width );
545 info->dwMaximumWindowSize.Y = min( reply->height, reply->max_height );
546 info->wPopupAttributes = reply->popup_attr;
547 info->bFullscreenSupported = FALSE;
550 SERVER_END_REQ;
551 return ret;
555 /******************************************************************************
556 * GetConsoleTitleW (kernelbase.@)
558 DWORD WINAPI DECLSPEC_HOTPATCH GetConsoleTitleW( LPWSTR title, DWORD size )
560 DWORD ret = 0;
562 SERVER_START_REQ( get_console_input_info )
564 req->handle = 0;
565 wine_server_set_reply( req, title, (size - 1) * sizeof(WCHAR) );
566 if (!wine_server_call_err( req ))
568 ret = wine_server_reply_size(reply) / sizeof(WCHAR);
569 title[ret] = 0;
572 SERVER_END_REQ;
573 return ret;
577 /***********************************************************************
578 * GetLargestConsoleWindowSize (kernelbase.@)
580 #if defined(__i386__) && !defined(__MINGW32__)
581 #undef GetLargestConsoleWindowSize
582 DWORD WINAPI DECLSPEC_HOTPATCH GetLargestConsoleWindowSize( HANDLE handle )
584 union {
585 COORD c;
586 DWORD w;
587 } x;
588 x.c = get_largest_console_window_size( handle );
589 return x.w;
592 #else
594 COORD WINAPI DECLSPEC_HOTPATCH GetLargestConsoleWindowSize( HANDLE handle )
596 return get_largest_console_window_size( handle );
599 #endif /* !defined(__i386__) */
602 /***********************************************************************
603 * GetNumberOfConsoleInputEvents (kernelbase.@)
605 BOOL WINAPI DECLSPEC_HOTPATCH GetNumberOfConsoleInputEvents( HANDLE handle, DWORD *count )
607 BOOL ret;
609 SERVER_START_REQ( read_console_input )
611 req->handle = console_handle_unmap( handle );
612 req->flush = FALSE;
613 if ((ret = !wine_server_call_err( req )))
615 if (count) *count = reply->read;
616 else
618 SetLastError( ERROR_INVALID_ACCESS );
619 ret = FALSE;
623 SERVER_END_REQ;
624 return ret;
628 /***********************************************************************
629 * PeekConsoleInputA (kernelbase.@)
631 BOOL WINAPI DECLSPEC_HOTPATCH PeekConsoleInputA( HANDLE handle, INPUT_RECORD *buffer,
632 DWORD length, DWORD *count )
634 DWORD read;
636 if (!PeekConsoleInputW( handle, buffer, length, &read )) return FALSE;
637 input_records_WtoA( buffer, read );
638 if (count) *count = read;
639 return TRUE;
643 /***********************************************************************
644 * PeekConsoleInputW (kernelbase.@)
646 BOOL WINAPI DECLSPEC_HOTPATCH PeekConsoleInputW( HANDLE handle, INPUT_RECORD *buffer,
647 DWORD length, DWORD *count )
649 BOOL ret;
651 SERVER_START_REQ( read_console_input )
653 req->handle = console_handle_unmap( handle );
654 req->flush = FALSE;
655 wine_server_set_reply( req, buffer, length * sizeof(INPUT_RECORD) );
656 if ((ret = !wine_server_call_err( req )))
658 if (count) *count = length ? reply->read : 0;
661 SERVER_END_REQ;
662 return ret;
666 /******************************************************************************
667 * ReadConsoleOutputAttribute (kernelbase.@)
669 BOOL WINAPI DECLSPEC_HOTPATCH ReadConsoleOutputAttribute( HANDLE handle, WORD *attr, DWORD length,
670 COORD coord, DWORD *count )
672 BOOL ret;
674 TRACE( "(%p,%p,%d,%dx%d,%p)\n", handle, attr, length, coord.X, coord.Y, count );
676 if (!count)
678 SetLastError( ERROR_INVALID_ACCESS );
679 return FALSE;
682 *count = 0;
683 SERVER_START_REQ( read_console_output )
685 req->handle = console_handle_unmap( handle );
686 req->x = coord.X;
687 req->y = coord.Y;
688 req->mode = CHAR_INFO_MODE_ATTR;
689 req->wrap = TRUE;
690 wine_server_set_reply( req, attr, length * sizeof(WORD) );
691 if ((ret = !wine_server_call_err( req ))) *count = wine_server_reply_size(reply) / sizeof(WORD);
693 SERVER_END_REQ;
694 return ret;
698 /******************************************************************************
699 * ReadConsoleOutputCharacterA (kernelbase.@)
701 BOOL WINAPI DECLSPEC_HOTPATCH ReadConsoleOutputCharacterA( HANDLE handle, LPSTR buffer, DWORD length,
702 COORD coord, DWORD *count )
704 DWORD read;
705 BOOL ret;
706 LPWSTR wptr;
708 if (!count)
710 SetLastError( ERROR_INVALID_ACCESS );
711 return FALSE;
714 *count = 0;
715 if (!(wptr = HeapAlloc( GetProcessHeap(), 0, length * sizeof(WCHAR) )))
717 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
718 return FALSE;
720 if ((ret = ReadConsoleOutputCharacterW( handle, wptr, length, coord, &read )))
722 read = WideCharToMultiByte( GetConsoleOutputCP(), 0, wptr, read, buffer, length, NULL, NULL);
723 *count = read;
725 HeapFree( GetProcessHeap(), 0, wptr );
726 return ret;
730 /******************************************************************************
731 * ReadConsoleOutputCharacterW (kernelbase.@)
733 BOOL WINAPI DECLSPEC_HOTPATCH ReadConsoleOutputCharacterW( HANDLE handle, LPWSTR buffer, DWORD length,
734 COORD coord, DWORD *count )
736 BOOL ret;
738 TRACE( "(%p,%p,%d,%dx%d,%p)\n", handle, buffer, length, coord.X, coord.Y, count );
740 if (!count)
742 SetLastError( ERROR_INVALID_ACCESS );
743 return FALSE;
746 *count = 0;
747 SERVER_START_REQ( read_console_output )
749 req->handle = console_handle_unmap( handle );
750 req->x = coord.X;
751 req->y = coord.Y;
752 req->mode = CHAR_INFO_MODE_TEXT;
753 req->wrap = TRUE;
754 wine_server_set_reply( req, buffer, length * sizeof(WCHAR) );
755 if ((ret = !wine_server_call_err( req ))) *count = wine_server_reply_size(reply) / sizeof(WCHAR);
757 SERVER_END_REQ;
758 return ret;
762 /******************************************************************************
763 * ReadConsoleOutputA (kernelbase.@)
765 BOOL WINAPI DECLSPEC_HOTPATCH ReadConsoleOutputA( HANDLE handle, CHAR_INFO *buffer, COORD size,
766 COORD coord, SMALL_RECT *region )
768 BOOL ret;
769 int y;
771 ret = ReadConsoleOutputW( handle, buffer, size, coord, region );
772 if (ret && region->Right >= region->Left)
774 for (y = 0; y <= region->Bottom - region->Top; y++)
775 char_info_WtoA( &buffer[(coord.Y + y) * size.X + coord.X], region->Right - region->Left + 1 );
777 return ret;
781 /******************************************************************************
782 * ReadConsoleOutputW (kernelbase.@)
784 BOOL WINAPI DECLSPEC_HOTPATCH ReadConsoleOutputW( HANDLE handle, CHAR_INFO *buffer, COORD size,
785 COORD coord, SMALL_RECT *region )
787 int width, height, y;
788 BOOL ret = TRUE;
790 width = min( region->Right - region->Left + 1, size.X - coord.X );
791 height = min( region->Bottom - region->Top + 1, size.Y - coord.Y );
793 if (width > 0 && height > 0)
795 for (y = 0; y < height; y++)
797 SERVER_START_REQ( read_console_output )
799 req->handle = console_handle_unmap( handle );
800 req->x = region->Left;
801 req->y = region->Top + y;
802 req->mode = CHAR_INFO_MODE_TEXTATTR;
803 req->wrap = FALSE;
804 wine_server_set_reply( req, &buffer[(y+coord.Y) * size.X + coord.X],
805 width * sizeof(CHAR_INFO) );
806 if ((ret = !wine_server_call_err( req )))
808 width = min( width, reply->width - region->Left );
809 height = min( height, reply->height - region->Top );
812 SERVER_END_REQ;
813 if (!ret) break;
816 region->Bottom = region->Top + height - 1;
817 region->Right = region->Left + width - 1;
818 return ret;
822 /******************************************************************************
823 * ScrollConsoleScreenBufferA (kernelbase.@)
825 BOOL WINAPI DECLSPEC_HOTPATCH ScrollConsoleScreenBufferA( HANDLE handle, SMALL_RECT *scroll,
826 SMALL_RECT *clip, COORD origin, CHAR_INFO *fill )
828 CHAR_INFO ciW;
830 ciW.Attributes = fill->Attributes;
831 MultiByteToWideChar( GetConsoleOutputCP(), 0, &fill->Char.AsciiChar, 1, &ciW.Char.UnicodeChar, 1 );
833 return ScrollConsoleScreenBufferW( handle, scroll, clip, origin, &ciW );
837 /******************************************************************************
838 * ScrollConsoleScreenBufferW (kernelbase.@)
840 BOOL WINAPI DECLSPEC_HOTPATCH ScrollConsoleScreenBufferW( HANDLE handle, SMALL_RECT *scroll,
841 SMALL_RECT *clip_rect, COORD origin,
842 CHAR_INFO *fill )
844 CONSOLE_SCREEN_BUFFER_INFO info;
845 SMALL_RECT dst, clip;
846 int i, j, start = -1;
847 DWORD ret;
848 BOOL inside;
849 COORD src;
851 if (clip_rect)
852 TRACE( "(%p,(%d,%d-%d,%d),(%d,%d-%d,%d),%d-%d,%p)\n", handle,
853 scroll->Left, scroll->Top, scroll->Right, scroll->Bottom,
854 clip_rect->Left, clip_rect->Top, clip_rect->Right, clip_rect->Bottom,
855 origin.X, origin.Y, fill );
856 else
857 TRACE("(%p,(%d,%d-%d,%d),(nil),%d-%d,%p)\n", handle,
858 scroll->Left, scroll->Top, scroll->Right, scroll->Bottom,
859 origin.X, origin.Y, fill );
861 if (!GetConsoleScreenBufferInfo( handle, &info )) return FALSE;
863 src.X = scroll->Left;
864 src.Y = scroll->Top;
866 /* step 1: get dst rect */
867 dst.Left = origin.X;
868 dst.Top = origin.Y;
869 dst.Right = dst.Left + (scroll->Right - scroll->Left);
870 dst.Bottom = dst.Top + (scroll->Bottom - scroll->Top);
872 /* step 2a: compute the final clip rect (optional passed clip and screen buffer limits */
873 if (clip_rect)
875 clip.Left = max(0, clip_rect->Left);
876 clip.Right = min(info.dwSize.X - 1, clip_rect->Right);
877 clip.Top = max(0, clip_rect->Top);
878 clip.Bottom = min(info.dwSize.Y - 1, clip_rect->Bottom);
880 else
882 clip.Left = 0;
883 clip.Right = info.dwSize.X - 1;
884 clip.Top = 0;
885 clip.Bottom = info.dwSize.Y - 1;
887 if (clip.Left > clip.Right || clip.Top > clip.Bottom) return FALSE;
889 /* step 2b: clip dst rect */
890 if (dst.Left < clip.Left ) {src.X += clip.Left - dst.Left; dst.Left = clip.Left;}
891 if (dst.Top < clip.Top ) {src.Y += clip.Top - dst.Top; dst.Top = clip.Top;}
892 if (dst.Right > clip.Right ) dst.Right = clip.Right;
893 if (dst.Bottom > clip.Bottom) dst.Bottom = clip.Bottom;
895 /* step 3: transfer the bits */
896 SERVER_START_REQ( move_console_output )
898 req->handle = console_handle_unmap( handle );
899 req->x_src = src.X;
900 req->y_src = src.Y;
901 req->x_dst = dst.Left;
902 req->y_dst = dst.Top;
903 req->w = dst.Right - dst.Left + 1;
904 req->h = dst.Bottom - dst.Top + 1;
905 ret = !wine_server_call_err( req );
907 SERVER_END_REQ;
909 if (!ret) return FALSE;
911 /* step 4: clean out the exposed part */
913 /* have to write cell [i,j] if it is not in dst rect (because it has already
914 * been written to by the scroll) and is in clip (we shall not write
915 * outside of clip)
917 for (j = max(scroll->Top, clip.Top); j <= min(scroll->Bottom, clip.Bottom); j++)
919 inside = dst.Top <= j && j <= dst.Bottom;
920 start = -1;
921 for (i = max(scroll->Left, clip.Left); i <= min(scroll->Right, clip.Right); i++)
923 if (inside && dst.Left <= i && i <= dst.Right)
925 if (start != -1)
927 fill_console_output( handle, start, j, i - start, fill );
928 start = -1;
931 else
933 if (start == -1) start = i;
936 if (start != -1) fill_console_output( handle, start, j, i - start, fill );
939 return TRUE;
943 /******************************************************************************
944 * SetConsoleActiveScreenBuffer (kernelbase.@)
946 BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleActiveScreenBuffer( HANDLE handle )
948 BOOL ret;
950 TRACE( "(%p)\n", handle );
952 SERVER_START_REQ( set_console_input_info )
954 req->handle = 0;
955 req->mask = SET_CONSOLE_INPUT_INFO_ACTIVE_SB;
956 req->active_sb = wine_server_obj_handle( handle );
957 ret = !wine_server_call_err( req );
959 SERVER_END_REQ;
960 return ret;
964 /******************************************************************************
965 * SetConsoleCP (kernelbase.@)
967 BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleCP( UINT cp )
969 BOOL ret;
971 if (!IsValidCodePage( cp ))
973 SetLastError( ERROR_INVALID_PARAMETER );
974 return FALSE;
976 SERVER_START_REQ( set_console_input_info )
978 req->handle = 0;
979 req->mask = SET_CONSOLE_INPUT_INFO_INPUT_CODEPAGE;
980 req->input_cp = cp;
981 ret = !wine_server_call_err( req );
983 SERVER_END_REQ;
984 return ret;
988 /******************************************************************************
989 * SetConsoleCursorInfo (kernelbase.@)
991 BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleCursorInfo( HANDLE handle, CONSOLE_CURSOR_INFO *info )
993 BOOL ret;
995 TRACE( "(%p,%d,%d)\n", handle, info->dwSize, info->bVisible);
997 SERVER_START_REQ( set_console_output_info )
999 req->handle = console_handle_unmap( handle );
1000 req->cursor_size = info->dwSize;
1001 req->cursor_visible = info->bVisible;
1002 req->mask = SET_CONSOLE_OUTPUT_INFO_CURSOR_GEOM;
1003 ret = !wine_server_call_err( req );
1005 SERVER_END_REQ;
1006 return ret;
1010 /******************************************************************************
1011 * SetConsoleCursorPosition (kernelbase.@)
1013 BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleCursorPosition( HANDLE handle, COORD pos )
1015 CONSOLE_SCREEN_BUFFER_INFO info;
1016 int w, h, do_move = 0;
1017 BOOL ret;
1019 TRACE( "%p %d %d\n", handle, pos.X, pos.Y );
1021 SERVER_START_REQ( set_console_output_info )
1023 req->handle = console_handle_unmap( handle );
1024 req->cursor_x = pos.X;
1025 req->cursor_y = pos.Y;
1026 req->mask = SET_CONSOLE_OUTPUT_INFO_CURSOR_POS;
1027 ret = !wine_server_call_err( req );
1029 SERVER_END_REQ;
1031 if (!ret || !GetConsoleScreenBufferInfo( handle, &info )) return FALSE;
1033 /* if cursor is no longer visible, scroll the visible window... */
1034 w = info.srWindow.Right - info.srWindow.Left + 1;
1035 h = info.srWindow.Bottom - info.srWindow.Top + 1;
1036 if (pos.X < info.srWindow.Left)
1038 info.srWindow.Left = min(pos.X, info.dwSize.X - w);
1039 do_move = 1;
1041 else if (pos.X > info.srWindow.Right)
1043 info.srWindow.Left = max(pos.X, w) - w + 1;
1044 do_move = 1;
1046 info.srWindow.Right = info.srWindow.Left + w - 1;
1048 if (pos.Y < info.srWindow.Top)
1050 info.srWindow.Top = min(pos.Y, info.dwSize.Y - h);
1051 do_move = 1;
1053 else if (pos.Y > info.srWindow.Bottom)
1055 info.srWindow.Top = max(pos.Y, h) - h + 1;
1056 do_move = 1;
1058 info.srWindow.Bottom = info.srWindow.Top + h - 1;
1060 if (do_move) ret = SetConsoleWindowInfo( handle, TRUE, &info.srWindow );
1061 return ret;
1065 /******************************************************************************
1066 * SetConsoleInputExeNameA (kernelbase.@)
1068 BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleInputExeNameA( LPCSTR name )
1070 if (!name || !name[0])
1072 SetLastError( ERROR_INVALID_PARAMETER );
1073 return FALSE;
1075 RtlEnterCriticalSection( &console_section );
1076 MultiByteToWideChar( CP_ACP, 0, name, -1, input_exe, ARRAY_SIZE(input_exe) );
1077 RtlLeaveCriticalSection( &console_section );
1078 return TRUE;
1082 /******************************************************************************
1083 * SetConsoleInputExeNameW (kernelbase.@)
1085 BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleInputExeNameW( LPCWSTR name )
1087 if (!name || !name[0])
1089 SetLastError( ERROR_INVALID_PARAMETER );
1090 return FALSE;
1092 RtlEnterCriticalSection( &console_section );
1093 lstrcpynW( input_exe, name, ARRAY_SIZE(input_exe) );
1094 RtlLeaveCriticalSection( &console_section );
1095 return TRUE;
1099 /******************************************************************************
1100 * SetConsoleMode (kernelbase.@)
1102 BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleMode( HANDLE handle, DWORD mode )
1104 BOOL ret;
1106 SERVER_START_REQ(set_console_mode)
1108 req->handle = console_handle_unmap( handle );
1109 req->mode = mode;
1110 ret = !wine_server_call_err( req );
1112 SERVER_END_REQ;
1114 TRACE( "(%p,%x) retval == %d\n", handle, mode, ret );
1115 return ret;
1119 /******************************************************************************
1120 * SetConsoleOutputCP (kernelbase.@)
1122 BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleOutputCP( UINT cp )
1124 BOOL ret;
1126 if (!IsValidCodePage( cp ))
1128 SetLastError( ERROR_INVALID_PARAMETER );
1129 return FALSE;
1131 SERVER_START_REQ( set_console_input_info )
1133 req->handle = 0;
1134 req->mask = SET_CONSOLE_INPUT_INFO_OUTPUT_CODEPAGE;
1135 req->output_cp = cp;
1136 ret = !wine_server_call_err( req );
1138 SERVER_END_REQ;
1139 return ret;
1143 /******************************************************************************
1144 * SetConsoleScreenBufferInfoEx (kernelbase.@)
1146 BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleScreenBufferInfoEx( HANDLE handle,
1147 CONSOLE_SCREEN_BUFFER_INFOEX *info )
1149 FIXME( "(%p %p): stub!\n", handle, info );
1150 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1151 return FALSE;
1155 /******************************************************************************
1156 * SetConsoleScreenBufferSize (kernelbase.@)
1158 BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleScreenBufferSize( HANDLE handle, COORD size )
1160 BOOL ret;
1162 TRACE( "(%p,(%d,%d))\n", handle, size.X, size.Y );
1163 SERVER_START_REQ( set_console_output_info )
1165 req->handle = console_handle_unmap( handle );
1166 req->width = size.X;
1167 req->height = size.Y;
1168 req->mask = SET_CONSOLE_OUTPUT_INFO_SIZE;
1169 ret = !wine_server_call_err( req );
1171 SERVER_END_REQ;
1172 return ret;
1176 /******************************************************************************
1177 * SetConsoleTextAttribute (kernelbase.@)
1179 BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleTextAttribute( HANDLE handle, WORD attr )
1181 BOOL ret;
1183 TRACE( "(%p,%d)\n", handle, attr );
1184 SERVER_START_REQ( set_console_output_info )
1186 req->handle = console_handle_unmap( handle );
1187 req->attr = attr;
1188 req->mask = SET_CONSOLE_OUTPUT_INFO_ATTR;
1189 ret = !wine_server_call_err( req );
1191 SERVER_END_REQ;
1192 return ret;
1196 /******************************************************************************
1197 * SetConsoleTitleW (kernelbase.@)
1199 BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleTitleW( LPCWSTR title )
1201 BOOL ret;
1203 TRACE( "%s\n", debugstr_w( title ));
1204 SERVER_START_REQ( set_console_input_info )
1206 req->handle = 0;
1207 req->mask = SET_CONSOLE_INPUT_INFO_TITLE;
1208 wine_server_add_data( req, title, lstrlenW(title) * sizeof(WCHAR) );
1209 ret = !wine_server_call_err( req );
1211 SERVER_END_REQ;
1212 return ret;
1216 /******************************************************************************
1217 * SetConsoleWindowInfo (kernelbase.@)
1219 BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleWindowInfo( HANDLE handle, BOOL absolute, SMALL_RECT *window )
1221 SMALL_RECT rect = *window;
1222 BOOL ret;
1224 TRACE( "(%p,%d,(%d,%d-%d,%d))\n", handle, absolute, rect.Left, rect.Top, rect.Right, rect.Bottom );
1226 if (!absolute)
1228 CONSOLE_SCREEN_BUFFER_INFO info;
1230 if (!GetConsoleScreenBufferInfo( handle, &info )) return FALSE;
1231 rect.Left += info.srWindow.Left;
1232 rect.Top += info.srWindow.Top;
1233 rect.Right += info.srWindow.Right;
1234 rect.Bottom += info.srWindow.Bottom;
1236 SERVER_START_REQ( set_console_output_info )
1238 req->handle = console_handle_unmap( handle );
1239 req->win_left = rect.Left;
1240 req->win_top = rect.Top;
1241 req->win_right = rect.Right;
1242 req->win_bottom = rect.Bottom;
1243 req->mask = SET_CONSOLE_OUTPUT_INFO_DISPLAY_WINDOW;
1244 ret = !wine_server_call_err( req );
1246 SERVER_END_REQ;
1248 return ret;
1252 /******************************************************************************
1253 * WriteConsoleInputA (kernelbase.@)
1255 BOOL WINAPI DECLSPEC_HOTPATCH WriteConsoleInputA( HANDLE handle, const INPUT_RECORD *buffer,
1256 DWORD count, DWORD *written )
1258 INPUT_RECORD *recW = NULL;
1259 BOOL ret;
1261 if (count > 0)
1263 if (!buffer)
1265 SetLastError( ERROR_INVALID_ACCESS );
1266 return FALSE;
1268 if (!(recW = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*recW) )))
1270 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1271 return FALSE;
1273 memcpy( recW, buffer, count * sizeof(*recW) );
1274 input_records_AtoW( recW, count );
1276 ret = WriteConsoleInputW( handle, recW, count, written );
1277 HeapFree( GetProcessHeap(), 0, recW );
1278 return ret;
1282 /******************************************************************************
1283 * WriteConsoleInputW (kernelbase.@)
1285 BOOL WINAPI DECLSPEC_HOTPATCH WriteConsoleInputW( HANDLE handle, const INPUT_RECORD *buffer,
1286 DWORD count, DWORD *written )
1288 DWORD events_written = 0;
1289 BOOL ret;
1291 TRACE( "(%p,%p,%d,%p)\n", handle, buffer, count, written );
1293 if (count > 0 && !buffer)
1295 SetLastError( ERROR_INVALID_ACCESS );
1296 return FALSE;
1298 SERVER_START_REQ( write_console_input )
1300 req->handle = console_handle_unmap( handle );
1301 wine_server_add_data( req, buffer, count * sizeof(INPUT_RECORD) );
1302 if ((ret = !wine_server_call_err( req ))) events_written = reply->written;
1304 SERVER_END_REQ;
1306 if (written) *written = events_written;
1307 else
1309 SetLastError( ERROR_INVALID_ACCESS );
1310 ret = FALSE;
1312 return ret;
1316 /***********************************************************************
1317 * WriteConsoleOutputA (kernelbase.@)
1319 BOOL WINAPI DECLSPEC_HOTPATCH WriteConsoleOutputA( HANDLE handle, const CHAR_INFO *buffer,
1320 COORD size, COORD coord, SMALL_RECT *region )
1322 int y;
1323 BOOL ret;
1324 COORD new_size, new_coord;
1325 CHAR_INFO *ciW;
1327 new_size.X = min( region->Right - region->Left + 1, size.X - coord.X );
1328 new_size.Y = min( region->Bottom - region->Top + 1, size.Y - coord.Y );
1330 if (new_size.X <= 0 || new_size.Y <= 0)
1332 region->Bottom = region->Top + new_size.Y - 1;
1333 region->Right = region->Left + new_size.X - 1;
1334 return TRUE;
1337 /* only copy the useful rectangle */
1338 if (!(ciW = HeapAlloc( GetProcessHeap(), 0, sizeof(CHAR_INFO) * new_size.X * new_size.Y )))
1339 return FALSE;
1340 for (y = 0; y < new_size.Y; y++)
1341 memcpy( &ciW[y * new_size.X], &buffer[(y + coord.Y) * size.X + coord.X],
1342 new_size.X * sizeof(CHAR_INFO) );
1343 char_info_AtoW( ciW, new_size.X * new_size.Y );
1344 new_coord.X = new_coord.Y = 0;
1345 ret = WriteConsoleOutputW( handle, ciW, new_size, new_coord, region );
1346 HeapFree( GetProcessHeap(), 0, ciW );
1347 return ret;
1351 /***********************************************************************
1352 * WriteConsoleOutputW (kernelbase.@)
1354 BOOL WINAPI DECLSPEC_HOTPATCH WriteConsoleOutputW( HANDLE handle, const CHAR_INFO *buffer,
1355 COORD size, COORD coord, SMALL_RECT *region )
1357 int width, height, y;
1358 BOOL ret = TRUE;
1360 TRACE( "(%p,%p,(%d,%d),(%d,%d),(%d,%dx%d,%d)\n",
1361 handle, buffer, size.X, size.Y, coord.X, coord.Y,
1362 region->Left, region->Top, region->Right, region->Bottom );
1364 width = min( region->Right - region->Left + 1, size.X - coord.X );
1365 height = min( region->Bottom - region->Top + 1, size.Y - coord.Y );
1367 if (width > 0 && height > 0)
1369 for (y = 0; y < height; y++)
1371 SERVER_START_REQ( write_console_output )
1373 req->handle = console_handle_unmap( handle );
1374 req->x = region->Left;
1375 req->y = region->Top + y;
1376 req->mode = CHAR_INFO_MODE_TEXTATTR;
1377 req->wrap = FALSE;
1378 wine_server_add_data( req, &buffer[(y + coord.Y) * size.X + coord.X],
1379 width * sizeof(CHAR_INFO));
1380 if ((ret = !wine_server_call_err( req )))
1382 width = min( width, reply->width - region->Left );
1383 height = min( height, reply->height - region->Top );
1386 SERVER_END_REQ;
1387 if (!ret) break;
1390 region->Bottom = region->Top + height - 1;
1391 region->Right = region->Left + width - 1;
1392 return ret;
1396 /******************************************************************************
1397 * WriteConsoleOutputAttribute (kernelbase.@)
1399 BOOL WINAPI DECLSPEC_HOTPATCH WriteConsoleOutputAttribute( HANDLE handle, const WORD *attr, DWORD length,
1400 COORD coord, DWORD *written )
1402 BOOL ret;
1404 TRACE( "(%p,%p,%d,%dx%d,%p)\n", handle, attr, length, coord.X, coord.Y, written );
1406 if ((length > 0 && !attr) || !written)
1408 SetLastError( ERROR_INVALID_ACCESS );
1409 return FALSE;
1412 *written = 0;
1413 SERVER_START_REQ( write_console_output )
1415 req->handle = console_handle_unmap( handle );
1416 req->x = coord.X;
1417 req->y = coord.Y;
1418 req->mode = CHAR_INFO_MODE_ATTR;
1419 req->wrap = TRUE;
1420 wine_server_add_data( req, attr, length * sizeof(WORD) );
1421 if ((ret = !wine_server_call_err( req ))) *written = reply->written;
1423 SERVER_END_REQ;
1424 return ret;
1428 /******************************************************************************
1429 * WriteConsoleOutputCharacterA (kernelbase.@)
1431 BOOL WINAPI DECLSPEC_HOTPATCH WriteConsoleOutputCharacterA( HANDLE handle, LPCSTR str, DWORD length,
1432 COORD coord, DWORD *written )
1434 BOOL ret;
1435 LPWSTR strW = NULL;
1436 DWORD lenW = 0;
1438 TRACE( "(%p,%s,%d,%dx%d,%p)\n", handle, debugstr_an(str, length), length, coord.X, coord.Y, written );
1440 if (length > 0)
1442 if (!str)
1444 SetLastError( ERROR_INVALID_ACCESS );
1445 return FALSE;
1447 lenW = MultiByteToWideChar( GetConsoleOutputCP(), 0, str, length, NULL, 0 );
1449 if (!(strW = HeapAlloc( GetProcessHeap(), 0, lenW * sizeof(WCHAR) )))
1451 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1452 return FALSE;
1454 MultiByteToWideChar( GetConsoleOutputCP(), 0, str, length, strW, lenW );
1456 ret = WriteConsoleOutputCharacterW( handle, strW, lenW, coord, written );
1457 HeapFree( GetProcessHeap(), 0, strW );
1458 return ret;
1462 /******************************************************************************
1463 * WriteConsoleOutputCharacterW (kernelbase.@)
1465 BOOL WINAPI DECLSPEC_HOTPATCH WriteConsoleOutputCharacterW( HANDLE handle, LPCWSTR str, DWORD length,
1466 COORD coord, DWORD *written )
1468 BOOL ret;
1470 TRACE( "(%p,%s,%d,%dx%d,%p)\n", handle, debugstr_wn(str, length), length, coord.X, coord.Y, written );
1472 if ((length > 0 && !str) || !written)
1474 SetLastError( ERROR_INVALID_ACCESS );
1475 return FALSE;
1478 *written = 0;
1479 SERVER_START_REQ( write_console_output )
1481 req->handle = console_handle_unmap( handle );
1482 req->x = coord.X;
1483 req->y = coord.Y;
1484 req->mode = CHAR_INFO_MODE_TEXT;
1485 req->wrap = TRUE;
1486 wine_server_add_data( req, str, length * sizeof(WCHAR) );
1487 if ((ret = !wine_server_call_err( req ))) *written = reply->written;
1489 SERVER_END_REQ;
1490 return ret;