2 * Win32 kernel 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 Eric Pouech
11 /* Reference applications:
12 * - IDA (interactive disassembler) full version 3.75. Works.
13 * - LYNX/W32. Works mostly, some keys crash it.
28 #include "wine/server.h"
29 #include "wine/exception.h"
30 #include "debugtools.h"
32 #include "msvcrt/excpt.h"
34 DEFAULT_DEBUG_CHANNEL(console
);
37 extern WCHAR
* CONSOLE_Readline(HANDLE
, int);
39 static WCHAR
* S_EditString
/* = NULL */;
40 static unsigned S_EditStrPos
/* = 0 */;
42 /***********************************************************************
43 * FreeConsole (KERNEL32.@)
45 BOOL WINAPI
FreeConsole(VOID
)
49 SERVER_START_REQ(free_console
)
51 ret
= !wine_server_call_err( req
);
57 /******************************************************************
58 * start_console_renderer
60 * helper for AllocConsole
61 * starts the renderer process
63 static BOOL
start_console_renderer(void)
68 PROCESS_INFORMATION pi
;
71 OBJECT_ATTRIBUTES attr
;
73 attr
.Length
= sizeof(attr
);
74 attr
.RootDirectory
= 0;
75 attr
.Attributes
= OBJ_INHERIT
;
76 attr
.ObjectName
= NULL
;
77 attr
.SecurityDescriptor
= NULL
;
78 attr
.SecurityQualityOfService
= NULL
;
80 NtCreateEvent(&hEvent
, EVENT_ALL_ACCESS
, &attr
, TRUE
, FALSE
);
81 if (!hEvent
) return FALSE
;
83 memset(&si
, 0, sizeof(si
));
86 /* FIXME: use dynamic allocation for most of the buffers below */
87 /* first try environment variable */
88 if ((p
= getenv("WINECONSOLE")) != NULL
)
90 ret
= snprintf(buffer
, sizeof(buffer
), "%s -- --use-event=%d", p
, hEvent
);
91 if ((ret
> -1) && (ret
< sizeof(buffer
)) &&
92 CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &si
, &pi
))
94 ERR("Couldn't launch Wine console from WINECONSOLE env var... trying default access\n");
97 /* then the regular installation dir */
98 ret
= snprintf(buffer
, sizeof(buffer
), "%s -- --use-event=%d", BINDIR
"/wineconsole", hEvent
);
99 if ((ret
> -1) && (ret
< sizeof(buffer
)) &&
100 CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &si
, &pi
))
103 /* then try the dir where we were started from */
104 if ((path
= HeapAlloc(GetProcessHeap(), 0, strlen(full_argv0
) + sizeof(buffer
))))
108 if ((p
= strrchr(strcpy( path
, full_argv0
), '/')))
111 sprintf(p
, "wineconsole -- --use-event=%d", hEvent
);
112 if (CreateProcessA(NULL
, path
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &si
, &pi
))
114 sprintf(p
, "programs/wineconsole/wineconsole -- --use-event=%d", hEvent
);
115 if (CreateProcessA(NULL
, path
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &si
, &pi
))
119 n
= readlink(full_argv0
, buffer
, sizeof(buffer
));
120 if (n
!= -1 && n
< sizeof(buffer
))
123 if (buffer
[0] == '/') /* absolute path ? */
124 strcpy(path
, buffer
);
125 else if ((p
= strrchr(strcpy( path
, full_argv0
), '/')))
127 strcpy(p
+ 1, buffer
);
131 if ((p
= strrchr(path
, '/')))
134 sprintf(p
, "wineconsole -- --use-event=%d", hEvent
);
135 if (CreateProcessA(NULL
, path
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &si
, &pi
))
137 sprintf(p
, "programs/wineconsole/wineconsole -- --use-event=%d", hEvent
);
138 if (CreateProcessA(NULL
, path
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &si
, &pi
))
141 } else perror("readlink");
143 HeapFree(GetProcessHeap(), 0, path
); path
= NULL
;
146 /* then try the regular PATH */
147 sprintf(buffer
, "wineconsole -- --use-event=%d\n", hEvent
);
148 if (CreateProcessA(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
, NULL
, NULL
, &si
, &pi
))
154 if (path
) HeapFree(GetProcessHeap(), 0, path
);
155 if (WaitForSingleObject(hEvent
, INFINITE
) != WAIT_OBJECT_0
) goto the_end
;
158 TRACE("Started wineconsole pid=%08lx tid=%08lx\n", pi
.dwProcessId
, pi
.dwThreadId
);
163 ERR("Can't allocate console\n");
164 if (path
) HeapFree(GetProcessHeap(), 0, path
);
169 /***********************************************************************
170 * AllocConsole (KERNEL32.@)
172 * creates an xterm with a pty to our program
174 BOOL WINAPI
AllocConsole(void)
176 HANDLE handle_in
= INVALID_HANDLE_VALUE
;
177 HANDLE handle_out
= INVALID_HANDLE_VALUE
;
178 HANDLE handle_err
= INVALID_HANDLE_VALUE
;
183 handle_in
= CreateFileA( "CONIN$", GENERIC_READ
|GENERIC_WRITE
|SYNCHRONIZE
,
184 0, NULL
, OPEN_EXISTING
, 0, 0 );
186 if (handle_in
!= INVALID_HANDLE_VALUE
)
188 /* we already have a console opened on this process, don't create a new one */
189 CloseHandle(handle_in
);
193 if (!start_console_renderer())
196 handle_in
= CreateFileA( "CONIN$", GENERIC_READ
|GENERIC_WRITE
|SYNCHRONIZE
,
197 0, NULL
, OPEN_EXISTING
, 0, 0 );
198 if (handle_in
== INVALID_HANDLE_VALUE
) goto the_end
;
200 handle_out
= CreateFileA( "CONOUT$", GENERIC_READ
|GENERIC_WRITE
,
201 0, NULL
, OPEN_EXISTING
, 0, 0 );
202 if (handle_out
== INVALID_HANDLE_VALUE
) goto the_end
;
204 if (!DuplicateHandle(GetCurrentProcess(), handle_out
, GetCurrentProcess(), &handle_err
,
205 0, TRUE
, DUPLICATE_SAME_ACCESS
))
208 /* NT resets the STD_*_HANDLEs on console alloc */
209 SetStdHandle(STD_INPUT_HANDLE
, handle_in
);
210 SetStdHandle(STD_OUTPUT_HANDLE
, handle_out
);
211 SetStdHandle(STD_ERROR_HANDLE
, handle_err
);
213 GetStartupInfoW(&si
);
214 if (si
.dwFlags
& STARTF_USESIZE
)
217 c
.X
= si
.dwXCountChars
;
218 c
.Y
= si
.dwYCountChars
;
219 SetConsoleScreenBufferSize(handle_out
, c
);
221 if (si
.dwFlags
& STARTF_USEFILLATTRIBUTE
)
222 SetConsoleTextAttribute(handle_out
, si
.dwFillAttribute
);
224 SetConsoleTitleW(si
.lpTitle
);
226 SetLastError(ERROR_SUCCESS
);
231 ERR("Can't allocate console\n");
232 if (handle_in
!= INVALID_HANDLE_VALUE
) CloseHandle(handle_in
);
233 if (handle_out
!= INVALID_HANDLE_VALUE
) CloseHandle(handle_out
);
234 if (handle_err
!= INVALID_HANDLE_VALUE
) CloseHandle(handle_err
);
240 /******************************************************************************
243 * Helper function for ReadConsole, ReadConsoleInput and PeekConsoleInput
245 static BOOL
read_console_input(HANDLE handle
, LPINPUT_RECORD buffer
, DWORD count
,
246 LPDWORD pRead
, BOOL flush
)
252 SERVER_START_REQ( read_console_input
)
254 req
->handle
= handle
;
256 wine_server_set_reply( req
, buffer
, count
* sizeof(INPUT_RECORD
) );
257 if ((ret
= !wine_server_call_err( req
))) read
= reply
->read
;
260 if (count
&& flush
&& GetConsoleMode(handle
, &mode
) && (mode
& ENABLE_PROCESSED_INPUT
))
264 for (i
= 0; i
< read
; i
++)
266 if (buffer
[i
].EventType
== KEY_EVENT
&& buffer
[i
].Event
.KeyEvent
.bKeyDown
&&
267 buffer
[i
].Event
.KeyEvent
.uChar
.UnicodeChar
== 'C' - 64 &&
268 !(buffer
[i
].Event
.KeyEvent
.dwControlKeyState
& ENHANCED_KEY
))
270 GenerateConsoleCtrlEvent(CTRL_C_EVENT
, GetCurrentProcessId());
271 /* FIXME: this is hackish, but it easily disables IR handling afterwards */
272 buffer
[i
].Event
.KeyEvent
.uChar
.UnicodeChar
= 0;
276 if (pRead
) *pRead
= read
;
281 /***********************************************************************
282 * ReadConsoleA (KERNEL32.@)
284 BOOL WINAPI
ReadConsoleA(HANDLE hConsoleInput
, LPVOID lpBuffer
, DWORD nNumberOfCharsToRead
,
285 LPDWORD lpNumberOfCharsRead
, LPVOID lpReserved
)
287 LPWSTR ptr
= HeapAlloc(GetProcessHeap(), 0, nNumberOfCharsToRead
* sizeof(WCHAR
));
291 if ((ret
= ReadConsoleW(hConsoleInput
, ptr
, nNumberOfCharsToRead
, &ncr
, 0)))
292 ncr
= WideCharToMultiByte(CP_ACP
, 0, ptr
, ncr
, lpBuffer
, nNumberOfCharsToRead
, NULL
, NULL
);
294 if (lpNumberOfCharsRead
) *lpNumberOfCharsRead
= ncr
;
295 HeapFree(GetProcessHeap(), 0, ptr
);
300 /***********************************************************************
301 * ReadConsoleW (KERNEL32.@)
303 BOOL WINAPI
ReadConsoleW(HANDLE hConsoleInput
, LPVOID lpBuffer
,
304 DWORD nNumberOfCharsToRead
, LPDWORD lpNumberOfCharsRead
, LPVOID lpReserved
)
307 LPWSTR xbuf
= (LPWSTR
)lpBuffer
;
310 TRACE("(%d,%p,%ld,%p,%p)\n",
311 hConsoleInput
, lpBuffer
, nNumberOfCharsToRead
, lpNumberOfCharsRead
, lpReserved
);
313 if (!GetConsoleMode(hConsoleInput
, &mode
))
316 if (mode
& ENABLE_LINE_INPUT
)
318 if (!S_EditString
|| S_EditString
[S_EditStrPos
] == 0)
320 if (S_EditString
) HeapFree(GetProcessHeap(), 0, S_EditString
);
321 if (!(S_EditString
= CONSOLE_Readline(hConsoleInput
, mode
& WINE_ENABLE_LINE_INPUT_EMACS
)))
325 charsread
= lstrlenW(&S_EditString
[S_EditStrPos
]);
326 if (charsread
> nNumberOfCharsToRead
) charsread
= nNumberOfCharsToRead
;
327 memcpy(xbuf
, &S_EditString
[S_EditStrPos
], charsread
* sizeof(WCHAR
));
328 S_EditStrPos
+= charsread
;
335 /* FIXME: should we read at least 1 char? The SDK does not say */
336 /* wait for at least one available input record (it doesn't mean we'll have
337 * chars stored in xbuf...
339 WaitForSingleObject(hConsoleInput
, INFINITE
);
340 for (charsread
= 0; charsread
< nNumberOfCharsToRead
;)
342 if (!read_console_input(hConsoleInput
, &ir
, 1, &count
, TRUE
)) return FALSE
;
343 if (count
&& ir
.EventType
== KEY_EVENT
&& ir
.Event
.KeyEvent
.bKeyDown
&&
344 ir
.Event
.KeyEvent
.uChar
.UnicodeChar
&&
345 !(ir
.Event
.KeyEvent
.dwControlKeyState
& ENHANCED_KEY
))
347 xbuf
[charsread
++] = ir
.Event
.KeyEvent
.uChar
.UnicodeChar
;
352 if (lpNumberOfCharsRead
) *lpNumberOfCharsRead
= charsread
;
358 /***********************************************************************
359 * ReadConsoleInputW (KERNEL32.@)
361 BOOL WINAPI
ReadConsoleInputW(HANDLE hConsoleInput
, LPINPUT_RECORD lpBuffer
,
362 DWORD nLength
, LPDWORD lpNumberOfEventsRead
)
368 if (lpNumberOfEventsRead
) *lpNumberOfEventsRead
= 0;
372 /* loop until we get at least one event */
375 WaitForSingleObject(hConsoleInput
, INFINITE
);
376 if (!read_console_input(hConsoleInput
, lpBuffer
, nLength
, &count
, TRUE
))
380 if (lpNumberOfEventsRead
) *lpNumberOfEventsRead
= count
;
387 /******************************************************************************
388 * WriteConsoleOutputCharacterW [KERNEL32.@] Copies character to consecutive
389 * cells in the console screen buffer
392 * hConsoleOutput [I] Handle to screen buffer
393 * str [I] Pointer to buffer with chars to write
394 * length [I] Number of cells to write to
395 * coord [I] Coords of first cell
396 * lpNumCharsWritten [O] Pointer to number of cells written
403 BOOL WINAPI
WriteConsoleOutputCharacterW( HANDLE hConsoleOutput
, LPCWSTR str
, DWORD length
,
404 COORD coord
, LPDWORD lpNumCharsWritten
)
408 TRACE("(%d,%s,%ld,%dx%d,%p)\n", hConsoleOutput
,
409 debugstr_wn(str
, length
), length
, coord
.X
, coord
.Y
, lpNumCharsWritten
);
411 SERVER_START_REQ( write_console_output
)
413 req
->handle
= hConsoleOutput
;
416 req
->mode
= CHAR_INFO_MODE_TEXT
;
418 wine_server_add_data( req
, str
, length
* sizeof(WCHAR
) );
419 if ((ret
= !wine_server_call_err( req
)))
421 if (lpNumCharsWritten
) *lpNumCharsWritten
= reply
->written
;
429 /******************************************************************************
430 * SetConsoleTitleW [KERNEL32.@] Sets title bar string for console
433 * title [I] Address of new title
439 BOOL WINAPI
SetConsoleTitleW(LPCWSTR title
)
443 SERVER_START_REQ( set_console_input_info
)
446 req
->mask
= SET_CONSOLE_INPUT_INFO_TITLE
;
447 wine_server_add_data( req
, title
, strlenW(title
) * sizeof(WCHAR
) );
448 ret
= !wine_server_call_err( req
);
455 /***********************************************************************
456 * GetNumberOfConsoleMouseButtons (KERNEL32.@)
458 BOOL WINAPI
GetNumberOfConsoleMouseButtons(LPDWORD nrofbuttons
)
460 FIXME("(%p): stub\n", nrofbuttons
);
465 /******************************************************************************
466 * SetConsoleInputExeNameW [KERNEL32.@]
471 BOOL WINAPI
SetConsoleInputExeNameW(LPCWSTR name
)
473 FIXME("(%s): stub!\n", debugstr_w(name
));
475 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
479 /******************************************************************************
480 * SetConsoleInputExeNameA [KERNEL32.@]
485 BOOL WINAPI
SetConsoleInputExeNameA(LPCSTR name
)
487 int len
= MultiByteToWideChar(CP_ACP
, 0, name
, -1, NULL
, 0);
488 LPWSTR xptr
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
491 if (!xptr
) return FALSE
;
493 MultiByteToWideChar(CP_ACP
, 0, name
, -1, xptr
, len
);
494 ret
= SetConsoleInputExeNameW(xptr
);
495 HeapFree(GetProcessHeap(), 0, xptr
);
500 static BOOL WINAPI
CONSOLE_DefaultHandler(DWORD dwCtrlType
)
502 FIXME("Terminating process %lx on event %lx\n", GetCurrentProcessId(), dwCtrlType
);
504 /* should never go here */
508 /******************************************************************************
509 * SetConsoleCtrlHandler [KERNEL32.@] Adds function to calling process list
512 * func [I] Address of handler function
513 * add [I] Handler to add or remove
520 * James Sutherland (JamesSutherland@gmx.de)
521 * Added global variables console_ignore_ctrl_c and handlers[]
522 * Does not yet do any error checking, or set LastError if failed.
523 * This doesn't yet matter, since these handlers are not yet called...!
526 static unsigned int console_ignore_ctrl_c
= 0; /* FIXME: this should be inherited somehow */
527 static PHANDLER_ROUTINE handlers
[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,CONSOLE_DefaultHandler
};
529 /*****************************************************************************/
531 BOOL WINAPI
SetConsoleCtrlHandler(PHANDLER_ROUTINE func
, BOOL add
)
533 int alloc_loop
= sizeof(handlers
)/sizeof(handlers
[0]) - 1;
535 FIXME("(%p,%i) - no error checking or testing yet\n", func
, add
);
539 console_ignore_ctrl_c
= add
;
544 for (; alloc_loop
>= 0 && handlers
[alloc_loop
]; alloc_loop
--);
547 FIXME("Out of space on CtrlHandler table\n");
550 handlers
[alloc_loop
] = func
;
554 for (; alloc_loop
>= 0 && handlers
[alloc_loop
] != func
; alloc_loop
--);
557 WARN("Attempt to remove non-installed CtrlHandler %p\n", func
);
561 if (alloc_loop
== sizeof(handlers
)/sizeof(handlers
[0]) - 1)
563 ERR("Who's trying to remove default handler???\n");
567 memmove(&handlers
[1], &handlers
[0], alloc_loop
* sizeof(handlers
[0]));
573 static WINE_EXCEPTION_FILTER(CONSOLE_CtrlEventHandler
)
575 TRACE("(%lx)\n", GetExceptionCode());
576 return EXCEPTION_EXECUTE_HANDLER
;
579 /******************************************************************************
580 * GenerateConsoleCtrlEvent [KERNEL32.@] Simulate a CTRL-C or CTRL-BREAK
583 * dwCtrlEvent [I] Type of event
584 * dwProcessGroupID [I] Process group ID to send event to
587 * Doesn't yet work...!
591 * Failure: False (and *should* [but doesn't] set LastError)
593 BOOL WINAPI
GenerateConsoleCtrlEvent(DWORD dwCtrlEvent
,
594 DWORD dwProcessGroupID
)
596 if (dwCtrlEvent
!= CTRL_C_EVENT
&& dwCtrlEvent
!= CTRL_BREAK_EVENT
)
598 ERR("invalid event %ld for PGID %ld\n", dwCtrlEvent
, dwProcessGroupID
);
602 if (dwProcessGroupID
== GetCurrentProcessId() || dwProcessGroupID
== 0)
606 FIXME("Attempt to send event %ld to self groupID, doing locally only\n", dwCtrlEvent
);
608 /* this is only meaningfull when done locally, otherwise it will have to be done on
609 * the 'receive' side of the event generation
611 if (dwCtrlEvent
== CTRL_C_EVENT
&& console_ignore_ctrl_c
)
614 /* try to pass the exception to the debugger
615 * if it continues, there's nothing more to do
616 * otherwise, we need to send the ctrl-event to the handlers
620 RaiseException( (dwCtrlEvent
== CTRL_C_EVENT
) ? DBG_CONTROL_C
: DBG_CONTROL_BREAK
,
623 __EXCEPT(CONSOLE_CtrlEventHandler
)
625 /* the debugger didn't continue... so, pass to ctrl handlers */
626 for (i
= 0; i
< sizeof(handlers
)/sizeof(handlers
[0]); i
++)
628 if (handlers
[i
] && (handlers
[i
])(dwCtrlEvent
)) break;
634 FIXME("event %ld to external PGID %ld - not implemented yet\n", dwCtrlEvent
, dwProcessGroupID
);
639 /******************************************************************************
640 * CreateConsoleScreenBuffer [KERNEL32.@] Creates a console screen buffer
643 * dwDesiredAccess [I] Access flag
644 * dwShareMode [I] Buffer share mode
645 * sa [I] Security attributes
646 * dwFlags [I] Type of buffer to create
647 * lpScreenBufferData [I] Reserved
650 * Should call SetLastError
653 * Success: Handle to new console screen buffer
654 * Failure: INVALID_HANDLE_VALUE
656 HANDLE WINAPI
CreateConsoleScreenBuffer(DWORD dwDesiredAccess
, DWORD dwShareMode
,
657 LPSECURITY_ATTRIBUTES sa
, DWORD dwFlags
,
658 LPVOID lpScreenBufferData
)
660 HANDLE ret
= INVALID_HANDLE_VALUE
;
662 TRACE("(%ld,%ld,%p,%ld,%p)\n",
663 dwDesiredAccess
, dwShareMode
, sa
, dwFlags
, lpScreenBufferData
);
665 if (dwFlags
!= CONSOLE_TEXTMODE_BUFFER
|| lpScreenBufferData
!= NULL
)
667 SetLastError(ERROR_INVALID_PARAMETER
);
668 return INVALID_HANDLE_VALUE
;
671 SERVER_START_REQ(create_console_output
)
674 req
->access
= dwDesiredAccess
;
675 req
->share
= dwShareMode
;
676 req
->inherit
= (sa
&& sa
->bInheritHandle
);
677 if (!wine_server_call_err( req
)) ret
= reply
->handle_out
;
685 /***********************************************************************
686 * GetConsoleScreenBufferInfo (KERNEL32.@)
688 BOOL WINAPI
GetConsoleScreenBufferInfo(HANDLE hConsoleOutput
, LPCONSOLE_SCREEN_BUFFER_INFO csbi
)
692 SERVER_START_REQ(get_console_output_info
)
694 req
->handle
= hConsoleOutput
;
695 if ((ret
= !wine_server_call_err( req
)))
697 csbi
->dwSize
.X
= reply
->width
;
698 csbi
->dwSize
.Y
= reply
->height
;
699 csbi
->dwCursorPosition
.X
= reply
->cursor_x
;
700 csbi
->dwCursorPosition
.Y
= reply
->cursor_y
;
701 csbi
->wAttributes
= reply
->attr
;
702 csbi
->srWindow
.Left
= reply
->win_left
;
703 csbi
->srWindow
.Right
= reply
->win_right
;
704 csbi
->srWindow
.Top
= reply
->win_top
;
705 csbi
->srWindow
.Bottom
= reply
->win_bottom
;
706 csbi
->dwMaximumWindowSize
.X
= reply
->max_width
;
707 csbi
->dwMaximumWindowSize
.Y
= reply
->max_height
;
716 /******************************************************************************
717 * SetConsoleActiveScreenBuffer [KERNEL32.@] Sets buffer to current console
723 BOOL WINAPI
SetConsoleActiveScreenBuffer(HANDLE hConsoleOutput
)
727 TRACE("(%x)\n", hConsoleOutput
);
729 SERVER_START_REQ( set_console_input_info
)
732 req
->mask
= SET_CONSOLE_INPUT_INFO_ACTIVE_SB
;
733 req
->active_sb
= hConsoleOutput
;
734 ret
= !wine_server_call_err( req
);
741 /***********************************************************************
742 * GetConsoleMode (KERNEL32.@)
744 BOOL WINAPI
GetConsoleMode(HANDLE hcon
, LPDWORD mode
)
748 SERVER_START_REQ(get_console_mode
)
751 ret
= !wine_server_call_err( req
);
752 if (ret
&& mode
) *mode
= reply
->mode
;
759 /******************************************************************************
760 * SetConsoleMode [KERNEL32.@] Sets input mode of console's input buffer
763 * hcon [I] Handle to console input or screen buffer
764 * mode [I] Input or output mode to set
770 BOOL WINAPI
SetConsoleMode(HANDLE hcon
, DWORD mode
)
774 TRACE("(%x,%lx)\n", hcon
, mode
);
776 SERVER_START_REQ(set_console_mode
)
780 ret
= !wine_server_call_err( req
);
783 /* FIXME: when resetting a console input to editline mode, I think we should
784 * empty the S_EditString buffer
790 /******************************************************************
793 * WriteConsoleOutput helper: hides server call semantics
795 static int write_char(HANDLE hCon
, LPCWSTR lpBuffer
, int nc
, COORD
* pos
)
801 SERVER_START_REQ( write_console_output
)
806 req
->mode
= CHAR_INFO_MODE_TEXTSTDATTR
;
808 wine_server_add_data( req
, lpBuffer
, nc
* sizeof(WCHAR
) );
809 if (!wine_server_call_err( req
)) written
= reply
->written
;
813 if (written
> 0) pos
->X
+= written
;
817 /******************************************************************
820 * WriteConsoleOutput helper: handles passing to next line (+scrolling if necessary)
823 static int next_line(HANDLE hCon
, CONSOLE_SCREEN_BUFFER_INFO
* csbi
)
829 csbi
->dwCursorPosition
.X
= 0;
830 csbi
->dwCursorPosition
.Y
++;
832 if (csbi
->dwCursorPosition
.Y
< csbi
->dwSize
.Y
) return 1;
835 src
.Bottom
= csbi
->dwSize
.Y
- 1;
837 src
.Right
= csbi
->dwSize
.X
- 1;
842 ci
.Attributes
= csbi
->wAttributes
;
843 ci
.Char
.UnicodeChar
= ' ';
845 csbi
->dwCursorPosition
.Y
--;
846 if (!ScrollConsoleScreenBufferW(hCon
, &src
, NULL
, dst
, &ci
))
851 /******************************************************************
854 * WriteConsoleOutput helper: writes a block of non special characters
857 static int write_block(HANDLE hCon
, CONSOLE_SCREEN_BUFFER_INFO
* csbi
,
858 DWORD mode
, LPWSTR ptr
, int len
)
860 int blk
; /* number of chars to write on first line */
862 if (len
<= 0) return 1;
864 blk
= min(len
, csbi
->dwSize
.X
- csbi
->dwCursorPosition
.X
);
866 if (write_char(hCon
, ptr
, blk
, &csbi
->dwCursorPosition
) != blk
)
869 if (blk
< len
) /* special handling for right border */
871 if (mode
& ENABLE_WRAP_AT_EOL_OUTPUT
) /* writes remaining on next line */
873 if (!next_line(hCon
, csbi
) ||
874 write_char(hCon
, ptr
+ blk
, len
- blk
, &csbi
->dwCursorPosition
) != len
- blk
)
877 else /* all remaining chars should be written on last column, so only write the last one */
879 csbi
->dwCursorPosition
.X
= csbi
->dwSize
.X
- 1;
880 if (write_char(hCon
, ptr
+ len
- 1, 1, &csbi
->dwCursorPosition
) != 1)
882 csbi
->dwCursorPosition
.X
= csbi
->dwSize
.X
- 1;
888 /***********************************************************************
889 * WriteConsoleW (KERNEL32.@)
891 BOOL WINAPI
WriteConsoleW(HANDLE hConsoleOutput
, LPCVOID lpBuffer
, DWORD nNumberOfCharsToWrite
,
892 LPDWORD lpNumberOfCharsWritten
, LPVOID lpReserved
)
896 WCHAR
* psz
= (WCHAR
*)lpBuffer
;
897 CONSOLE_SCREEN_BUFFER_INFO csbi
;
900 TRACE("%d %s %ld %p %p\n",
901 hConsoleOutput
, debugstr_wn(lpBuffer
, nNumberOfCharsToWrite
),
902 nNumberOfCharsToWrite
, lpNumberOfCharsWritten
, lpReserved
);
904 if (lpNumberOfCharsWritten
) *lpNumberOfCharsWritten
= 0;
906 if (!GetConsoleMode(hConsoleOutput
, &mode
) ||
907 !GetConsoleScreenBufferInfo(hConsoleOutput
, &csbi
))
910 if (mode
& ENABLE_PROCESSED_OUTPUT
)
914 for (i
= 0; i
< nNumberOfCharsToWrite
; i
++)
918 case '\b': case '\t': case '\n': case '\a': case '\r':
919 /* don't handle here the i-th char... done below */
920 if ((k
= i
- first
) > 0)
922 if (!write_block(hConsoleOutput
, &csbi
, mode
, &psz
[first
], k
))
932 if (csbi
.dwCursorPosition
.X
> 0) csbi
.dwCursorPosition
.X
--;
936 WCHAR tmp
[8] = {' ',' ',' ',' ',' ',' ',' ',' '};
938 if (!write_block(hConsoleOutput
, &csbi
, mode
, tmp
,
939 ((csbi
.dwCursorPosition
.X
+ 8) & ~7) - csbi
.dwCursorPosition
.X
))
944 next_line(hConsoleOutput
, &csbi
);
950 csbi
.dwCursorPosition
.X
= 0;
958 /* write the remaining block (if any) if processed output is enabled, or the
959 * entire buffer otherwise
961 if ((k
= nNumberOfCharsToWrite
- first
) > 0)
963 if (!write_block(hConsoleOutput
, &csbi
, mode
, &psz
[first
], k
))
969 SetConsoleCursorPosition(hConsoleOutput
, csbi
.dwCursorPosition
);
970 if (lpNumberOfCharsWritten
) *lpNumberOfCharsWritten
= nw
;
975 /***********************************************************************
976 * WriteConsoleA (KERNEL32.@)
978 BOOL WINAPI
WriteConsoleA(HANDLE hConsoleOutput
, LPCVOID lpBuffer
, DWORD nNumberOfCharsToWrite
,
979 LPDWORD lpNumberOfCharsWritten
, LPVOID lpReserved
)
985 n
= MultiByteToWideChar(CP_ACP
, 0, lpBuffer
, nNumberOfCharsToWrite
, NULL
, 0);
987 if (lpNumberOfCharsWritten
) *lpNumberOfCharsWritten
= 0;
988 xstring
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(WCHAR
));
989 if (!xstring
) return 0;
991 MultiByteToWideChar(CP_ACP
, 0, lpBuffer
, nNumberOfCharsToWrite
, xstring
, n
);
993 ret
= WriteConsoleW(hConsoleOutput
, xstring
, n
, lpNumberOfCharsWritten
, 0);
995 HeapFree(GetProcessHeap(), 0, xstring
);
1000 /******************************************************************************
1001 * SetConsoleCursorPosition [KERNEL32.@]
1002 * Sets the cursor position in console
1005 * hConsoleOutput [I] Handle of console screen buffer
1006 * dwCursorPosition [I] New cursor position coordinates
1010 BOOL WINAPI
SetConsoleCursorPosition(HANDLE hcon
, COORD pos
)
1013 CONSOLE_SCREEN_BUFFER_INFO csbi
;
1017 TRACE("%x %d %d\n", hcon
, pos
.X
, pos
.Y
);
1019 SERVER_START_REQ(set_console_output_info
)
1022 req
->cursor_x
= pos
.X
;
1023 req
->cursor_y
= pos
.Y
;
1024 req
->mask
= SET_CONSOLE_OUTPUT_INFO_CURSOR_POS
;
1025 ret
= !wine_server_call_err( req
);
1029 if (!ret
|| !GetConsoleScreenBufferInfo(hcon
, &csbi
))
1032 /* if cursor is no longer visible, scroll the visible window... */
1033 w
= csbi
.srWindow
.Right
- csbi
.srWindow
.Left
+ 1;
1034 h
= csbi
.srWindow
.Bottom
- csbi
.srWindow
.Top
+ 1;
1035 if (pos
.X
< csbi
.srWindow
.Left
)
1037 csbi
.srWindow
.Left
= min(pos
.X
, csbi
.dwSize
.X
- w
);
1040 else if (pos
.X
> csbi
.srWindow
.Right
)
1042 csbi
.srWindow
.Left
= max(pos
.X
, w
) - w
+ 1;
1045 csbi
.srWindow
.Right
= csbi
.srWindow
.Left
+ w
- 1;
1047 if (pos
.Y
< csbi
.srWindow
.Top
)
1049 csbi
.srWindow
.Top
= min(pos
.Y
, csbi
.dwSize
.Y
- h
);
1052 else if (pos
.Y
> csbi
.srWindow
.Bottom
)
1054 csbi
.srWindow
.Top
= max(pos
.Y
, h
) - h
+ 1;
1057 csbi
.srWindow
.Bottom
= csbi
.srWindow
.Top
+ h
- 1;
1059 ret
= (do_move
) ? SetConsoleWindowInfo(hcon
, TRUE
, &csbi
.srWindow
) : TRUE
;
1064 /******************************************************************************
1065 * GetConsoleCursorInfo [KERNEL32.@] Gets size and visibility of console
1068 * hcon [I] Handle to console screen buffer
1069 * cinfo [O] Address of cursor information
1075 BOOL WINAPI
GetConsoleCursorInfo(HANDLE hcon
, LPCONSOLE_CURSOR_INFO cinfo
)
1079 SERVER_START_REQ(get_console_output_info
)
1082 ret
= !wine_server_call_err( req
);
1085 cinfo
->dwSize
= reply
->cursor_size
;
1086 cinfo
->bVisible
= reply
->cursor_visible
;
1094 /******************************************************************************
1095 * SetConsoleCursorInfo [KERNEL32.@] Sets size and visibility of cursor
1098 * hcon [I] Handle to console screen buffer
1099 * cinfo [I] Address of cursor information
1104 BOOL WINAPI
SetConsoleCursorInfo(HANDLE hCon
, LPCONSOLE_CURSOR_INFO cinfo
)
1108 SERVER_START_REQ(set_console_output_info
)
1111 req
->cursor_size
= cinfo
->dwSize
;
1112 req
->cursor_visible
= cinfo
->bVisible
;
1113 req
->mask
= SET_CONSOLE_OUTPUT_INFO_CURSOR_GEOM
;
1114 ret
= !wine_server_call_err( req
);
1121 /******************************************************************************
1122 * SetConsoleWindowInfo [KERNEL32.@] Sets size and position of console
1125 * hcon [I] Handle to console screen buffer
1126 * bAbsolute [I] Coordinate type flag
1127 * window [I] Address of new window rectangle
1132 BOOL WINAPI
SetConsoleWindowInfo(HANDLE hCon
, BOOL bAbsolute
, LPSMALL_RECT window
)
1134 SMALL_RECT p
= *window
;
1139 CONSOLE_SCREEN_BUFFER_INFO csbi
;
1140 if (!GetConsoleScreenBufferInfo(hCon
, &csbi
))
1142 p
.Left
+= csbi
.srWindow
.Left
;
1143 p
.Top
+= csbi
.srWindow
.Top
;
1144 p
.Right
+= csbi
.srWindow
.Left
;
1145 p
.Bottom
+= csbi
.srWindow
.Top
;
1147 SERVER_START_REQ(set_console_output_info
)
1150 req
->win_left
= p
.Left
;
1151 req
->win_top
= p
.Top
;
1152 req
->win_right
= p
.Right
;
1153 req
->win_bottom
= p
.Bottom
;
1154 req
->mask
= SET_CONSOLE_OUTPUT_INFO_DISPLAY_WINDOW
;
1155 ret
= !wine_server_call_err( req
);
1163 /******************************************************************************
1164 * SetConsoleTextAttribute [KERNEL32.@] Sets colors for text
1166 * Sets the foreground and background color attributes of characters
1167 * written to the screen buffer.
1173 BOOL WINAPI
SetConsoleTextAttribute(HANDLE hConsoleOutput
, WORD wAttr
)
1177 SERVER_START_REQ(set_console_output_info
)
1179 req
->handle
= hConsoleOutput
;
1181 req
->mask
= SET_CONSOLE_OUTPUT_INFO_ATTR
;
1182 ret
= !wine_server_call_err( req
);
1189 /******************************************************************************
1190 * SetConsoleScreenBufferSize [KERNEL32.@] Changes size of console
1193 * hConsoleOutput [I] Handle to console screen buffer
1194 * dwSize [I] New size in character rows and cols
1200 BOOL WINAPI
SetConsoleScreenBufferSize(HANDLE hConsoleOutput
, COORD dwSize
)
1204 SERVER_START_REQ(set_console_output_info
)
1206 req
->handle
= hConsoleOutput
;
1207 req
->width
= dwSize
.X
;
1208 req
->height
= dwSize
.Y
;
1209 req
->mask
= SET_CONSOLE_OUTPUT_INFO_SIZE
;
1210 ret
= !wine_server_call_err( req
);
1217 /******************************************************************************
1218 * ScrollConsoleScreenBufferA [KERNEL32.@]
1221 BOOL WINAPI
ScrollConsoleScreenBufferA(HANDLE hConsoleOutput
, LPSMALL_RECT lpScrollRect
,
1222 LPSMALL_RECT lpClipRect
, COORD dwDestOrigin
,
1227 ciw
.Attributes
= lpFill
->Attributes
;
1228 MultiByteToWideChar(CP_ACP
, 0, &lpFill
->Char
.AsciiChar
, 1, &ciw
.Char
.UnicodeChar
, 1);
1230 return ScrollConsoleScreenBufferW(hConsoleOutput
, lpScrollRect
, lpClipRect
,
1231 dwDestOrigin
, &ciw
);
1234 /******************************************************************
1237 * Helper function for ScrollConsoleScreenBufferW
1238 * Fills a part of a line with a constant character info
1240 static void fill_line_uniform(HANDLE hConsoleOutput
, int i
, int j
, int len
, LPCHAR_INFO lpFill
)
1242 SERVER_START_REQ( fill_console_output
)
1244 req
->handle
= hConsoleOutput
;
1245 req
->mode
= CHAR_INFO_MODE_TEXTATTR
;
1250 req
->data
.ch
= lpFill
->Char
.UnicodeChar
;
1251 req
->data
.attr
= lpFill
->Attributes
;
1252 wine_server_call_err( req
);
1257 /******************************************************************************
1258 * ScrollConsoleScreenBufferW [KERNEL32.@]
1262 BOOL WINAPI
ScrollConsoleScreenBufferW(HANDLE hConsoleOutput
, LPSMALL_RECT lpScrollRect
,
1263 LPSMALL_RECT lpClipRect
, COORD dwDestOrigin
,
1271 CONSOLE_SCREEN_BUFFER_INFO csbi
;
1275 TRACE("(%d,(%d,%d-%d,%d),(%d,%d-%d,%d),%d-%d,%p)\n", hConsoleOutput
,
1276 lpScrollRect
->Left
, lpScrollRect
->Top
,
1277 lpScrollRect
->Right
, lpScrollRect
->Bottom
,
1278 lpClipRect
->Left
, lpClipRect
->Top
,
1279 lpClipRect
->Right
, lpClipRect
->Bottom
,
1280 dwDestOrigin
.X
, dwDestOrigin
.Y
, lpFill
);
1282 TRACE("(%d,(%d,%d-%d,%d),(nil),%d-%d,%p)\n", hConsoleOutput
,
1283 lpScrollRect
->Left
, lpScrollRect
->Top
,
1284 lpScrollRect
->Right
, lpScrollRect
->Bottom
,
1285 dwDestOrigin
.X
, dwDestOrigin
.Y
, lpFill
);
1287 if (!GetConsoleScreenBufferInfo(hConsoleOutput
, &csbi
))
1290 /* step 1: get dst rect */
1291 dst
.Left
= dwDestOrigin
.X
;
1292 dst
.Top
= dwDestOrigin
.Y
;
1293 dst
.Right
= dst
.Left
+ (lpScrollRect
->Right
- lpScrollRect
->Left
);
1294 dst
.Bottom
= dst
.Top
+ (lpScrollRect
->Bottom
- lpScrollRect
->Top
);
1296 /* step 2a: compute the final clip rect (optional passed clip and screen buffer limits */
1299 clip
.Left
= max(0, lpClipRect
->Left
);
1300 clip
.Right
= min(csbi
.dwSize
.X
- 1, lpClipRect
->Right
);
1301 clip
.Top
= max(0, lpClipRect
->Top
);
1302 clip
.Bottom
= min(csbi
.dwSize
.Y
- 1, lpClipRect
->Bottom
);
1307 clip
.Right
= csbi
.dwSize
.X
- 1;
1309 clip
.Bottom
= csbi
.dwSize
.Y
- 1;
1311 if (clip
.Left
> clip
.Right
|| clip
.Top
> clip
.Bottom
) return FALSE
;
1313 /* step 2b: clip dst rect */
1314 if (dst
.Left
< clip
.Left
) dst
.Left
= clip
.Left
;
1315 if (dst
.Top
< clip
.Top
) dst
.Top
= clip
.Top
;
1316 if (dst
.Right
> clip
.Right
) dst
.Right
= clip
.Right
;
1317 if (dst
.Bottom
> clip
.Bottom
) dst
.Bottom
= clip
.Bottom
;
1319 /* step 3: transfer the bits */
1320 SERVER_START_REQ(move_console_output
)
1322 req
->handle
= hConsoleOutput
;
1323 req
->x_src
= lpScrollRect
->Left
;
1324 req
->y_src
= lpScrollRect
->Top
;
1325 req
->x_dst
= dst
.Left
;
1326 req
->y_dst
= dst
.Top
;
1327 req
->w
= dst
.Right
- dst
.Left
+ 1;
1328 req
->h
= dst
.Bottom
- dst
.Top
+ 1;
1329 ret
= !wine_server_call_err( req
);
1333 if (!ret
) return FALSE
;
1335 /* step 4: clean out the exposed part */
1337 /* have to write celll [i,j] if it is not in dst rect (because it has already
1338 * been written to by the scroll) and is in clip (we shall not write
1341 for (j
= max(lpScrollRect
->Top
, clip
.Top
); j
<= min(lpScrollRect
->Bottom
, clip
.Bottom
); j
++)
1343 inside
= dst
.Top
<= j
&& j
<= dst
.Bottom
;
1345 for (i
= max(lpScrollRect
->Left
, clip
.Left
); i
<= min(lpScrollRect
->Right
, clip
.Right
); i
++)
1347 if (inside
&& dst
.Left
<= i
&& i
<= dst
.Right
)
1351 fill_line_uniform(hConsoleOutput
, start
, j
, i
- start
, lpFill
);
1357 if (start
== -1) start
= i
;
1361 fill_line_uniform(hConsoleOutput
, start
, j
, i
- start
, lpFill
);
1368 /* ====================================================================
1370 * Console manipulation functions
1372 * ====================================================================*/
1373 /* some missing functions...
1374 * FIXME: those are likely to be defined as undocumented function in kernel32 (or part of them)
1375 * should get the right API and implement them
1376 * GetConsoleCommandHistory[AW] (dword dword dword)
1377 * GetConsoleCommandHistoryLength[AW]
1378 * SetConsoleCommandHistoryMode
1379 * SetConsoleNumberOfCommands[AW]
1381 int CONSOLE_GetHistory(int idx
, WCHAR
* buf
, int buf_len
)
1385 SERVER_START_REQ( get_console_input_history
)
1389 if (buf
&& buf_len
> 1)
1391 wine_server_set_reply( req
, buf
, (buf_len
- 1) * sizeof(WCHAR
) );
1393 if (!wine_server_call_err( req
))
1395 if (buf
) buf
[wine_server_reply_size(reply
) / sizeof(WCHAR
)] = 0;
1396 len
= reply
->total
/ sizeof(WCHAR
) + 1;
1403 /******************************************************************
1404 * CONSOLE_AppendHistory
1408 BOOL
CONSOLE_AppendHistory(const WCHAR
* ptr
)
1410 size_t len
= strlenW(ptr
);
1413 while (len
&& (ptr
[len
- 1] == '\n' || ptr
[len
- 1] == '\r')) len
--;
1415 SERVER_START_REQ( append_console_input_history
)
1418 wine_server_add_data( req
, ptr
, len
* sizeof(WCHAR
) );
1419 ret
= !wine_server_call_err( req
);
1425 /******************************************************************
1426 * CONSOLE_GetNumHistoryEntries
1430 unsigned CONSOLE_GetNumHistoryEntries(void)
1433 SERVER_START_REQ(get_console_input_info
)
1436 if (!wine_server_call_err( req
)) ret
= reply
->history_index
;