- adapted kernel32 so that it no longer (directly) manages console
handles as wineserver handles - console input handle object is no longer waitable (input record synchronisation is now implemented as a simple semaphore), and removed FD_TYPE_CONSOLE from fd types in wineserver - console handles now always have their two lower bit set so one can distinguish a console handle from a kernel object handle - implemented some undocumented kernel32 console related APIs (CloseConsoleHandle, GetConsoleInputWaitHandle, OpenConsoleW, VerifyConsoleIoHandle, DuplicateConsoleHandle) - allowed a few kernel32 APIs to take console pseudo-handles (FlushFileBuffer, GetFileType, WaitFor*Object*) - simplified the console inheritance at process creation - in console tests, no longer create a console if one already exists
This commit is contained in:
parent
64a41a2842
commit
412d37f6e6
|
@ -48,12 +48,14 @@
|
|||
#include "wine/debug.h"
|
||||
#include "excpt.h"
|
||||
#include "console_private.h"
|
||||
#include "kernel_private.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(console);
|
||||
|
||||
static UINT console_input_codepage;
|
||||
static UINT console_output_codepage;
|
||||
|
||||
|
||||
/* map input records to ASCII */
|
||||
static void input_records_WtoA( INPUT_RECORD *buffer, int count )
|
||||
{
|
||||
|
@ -189,20 +191,22 @@ BOOL WINAPI WriteConsoleInputW( HANDLE handle, const INPUT_RECORD *buffer,
|
|||
DWORD count, LPDWORD written )
|
||||
{
|
||||
BOOL ret;
|
||||
|
||||
DWORD w;
|
||||
TRACE("(%p,%p,%ld,%p)\n", handle, buffer, count, written);
|
||||
|
||||
if (written) *written = 0;
|
||||
SERVER_START_REQ( write_console_input )
|
||||
{
|
||||
req->handle = handle;
|
||||
req->handle = console_handle_unmap(handle);
|
||||
wine_server_add_data( req, buffer, count * sizeof(INPUT_RECORD) );
|
||||
if ((ret = !wine_server_call_err( req )))
|
||||
{
|
||||
if (written) *written = reply->written;
|
||||
}
|
||||
if ((ret = !wine_server_call_err( req ))) w = reply->written;
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
if (ret)
|
||||
{
|
||||
ReleaseSemaphore( GetConsoleInputWaitHandle(), w, NULL );
|
||||
if (written) *written = w;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -266,7 +270,7 @@ BOOL WINAPI WriteConsoleOutputW( HANDLE hConsoleOutput, const CHAR_INFO *lpBuffe
|
|||
{
|
||||
SERVER_START_REQ( write_console_output )
|
||||
{
|
||||
req->handle = hConsoleOutput;
|
||||
req->handle = console_handle_unmap(hConsoleOutput);
|
||||
req->x = region->Left;
|
||||
req->y = region->Top + y;
|
||||
req->mode = CHAR_INFO_MODE_TEXTATTR;
|
||||
|
@ -348,7 +352,7 @@ BOOL WINAPI WriteConsoleOutputAttribute( HANDLE hConsoleOutput, CONST WORD *attr
|
|||
|
||||
SERVER_START_REQ( write_console_output )
|
||||
{
|
||||
req->handle = hConsoleOutput;
|
||||
req->handle = console_handle_unmap(hConsoleOutput);
|
||||
req->x = coord.X;
|
||||
req->y = coord.Y;
|
||||
req->mode = CHAR_INFO_MODE_ATTR;
|
||||
|
@ -412,7 +416,7 @@ BOOL WINAPI FillConsoleOutputCharacterW( HANDLE hConsoleOutput, WCHAR ch, DWORD
|
|||
|
||||
SERVER_START_REQ( fill_console_output )
|
||||
{
|
||||
req->handle = hConsoleOutput;
|
||||
req->handle = console_handle_unmap(hConsoleOutput);
|
||||
req->x = coord.X;
|
||||
req->y = coord.Y;
|
||||
req->mode = CHAR_INFO_MODE_TEXT;
|
||||
|
@ -453,7 +457,7 @@ BOOL WINAPI FillConsoleOutputAttribute( HANDLE hConsoleOutput, WORD attr, DWORD
|
|||
|
||||
SERVER_START_REQ( fill_console_output )
|
||||
{
|
||||
req->handle = hConsoleOutput;
|
||||
req->handle = console_handle_unmap(hConsoleOutput);
|
||||
req->x = coord.X;
|
||||
req->y = coord.Y;
|
||||
req->mode = CHAR_INFO_MODE_ATTR;
|
||||
|
@ -507,7 +511,7 @@ BOOL WINAPI ReadConsoleOutputCharacterW( HANDLE hConsoleOutput, LPWSTR buffer, D
|
|||
|
||||
SERVER_START_REQ( read_console_output )
|
||||
{
|
||||
req->handle = hConsoleOutput;
|
||||
req->handle = console_handle_unmap(hConsoleOutput);
|
||||
req->x = coord.X;
|
||||
req->y = coord.Y;
|
||||
req->mode = CHAR_INFO_MODE_TEXT;
|
||||
|
@ -536,7 +540,7 @@ BOOL WINAPI ReadConsoleOutputAttribute(HANDLE hConsoleOutput, LPWORD lpAttribute
|
|||
|
||||
SERVER_START_REQ( read_console_output )
|
||||
{
|
||||
req->handle = hConsoleOutput;
|
||||
req->handle = console_handle_unmap(hConsoleOutput);
|
||||
req->x = coord.X;
|
||||
req->y = coord.Y;
|
||||
req->mode = CHAR_INFO_MODE_ATTR;
|
||||
|
@ -596,7 +600,7 @@ BOOL WINAPI ReadConsoleOutputW( HANDLE hConsoleOutput, LPCHAR_INFO lpBuffer, COO
|
|||
{
|
||||
SERVER_START_REQ( read_console_output )
|
||||
{
|
||||
req->handle = hConsoleOutput;
|
||||
req->handle = console_handle_unmap(hConsoleOutput);
|
||||
req->x = region->Left;
|
||||
req->y = region->Top + y;
|
||||
req->mode = CHAR_INFO_MODE_TEXTATTR;
|
||||
|
@ -667,7 +671,7 @@ BOOL WINAPI PeekConsoleInputW( HANDLE handle, LPINPUT_RECORD buffer, DWORD count
|
|||
BOOL ret;
|
||||
SERVER_START_REQ( read_console_input )
|
||||
{
|
||||
req->handle = handle;
|
||||
req->handle = console_handle_unmap(handle);
|
||||
req->flush = FALSE;
|
||||
wine_server_set_reply( req, buffer, count * sizeof(INPUT_RECORD) );
|
||||
if ((ret = !wine_server_call_err( req )))
|
||||
|
@ -688,7 +692,7 @@ BOOL WINAPI GetNumberOfConsoleInputEvents( HANDLE handle, LPDWORD nrofevents )
|
|||
BOOL ret;
|
||||
SERVER_START_REQ( read_console_input )
|
||||
{
|
||||
req->handle = handle;
|
||||
req->handle = console_handle_unmap(handle);
|
||||
req->flush = FALSE;
|
||||
if ((ret = !wine_server_call_err( req )))
|
||||
{
|
||||
|
@ -700,20 +704,46 @@ BOOL WINAPI GetNumberOfConsoleInputEvents( HANDLE handle, LPDWORD nrofevents )
|
|||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* read_console_input
|
||||
*
|
||||
* Helper function for ReadConsole, ReadConsoleInput and FlushConsoleInputBuffer
|
||||
*
|
||||
* Returns
|
||||
* 0 for error, 1 for no INPUT_RECORD ready, 2 with INPUT_RECORD ready
|
||||
*/
|
||||
enum read_console_input_return {rci_error = 0, rci_timeout = 1, rci_gotone = 2};
|
||||
static enum read_console_input_return read_console_input(HANDLE handle, LPINPUT_RECORD ir, DWORD timeout)
|
||||
{
|
||||
enum read_console_input_return ret;
|
||||
|
||||
if (WaitForSingleObject(GetConsoleInputWaitHandle(), timeout) != WAIT_OBJECT_0)
|
||||
return rci_timeout;
|
||||
SERVER_START_REQ( read_console_input )
|
||||
{
|
||||
req->handle = console_handle_unmap(handle);
|
||||
req->flush = TRUE;
|
||||
wine_server_set_reply( req, ir, sizeof(INPUT_RECORD) );
|
||||
if (wine_server_call_err( req ) || !reply->read) ret = rci_error;
|
||||
else ret = rci_gotone;
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* FlushConsoleInputBuffer (KERNEL32.@)
|
||||
*/
|
||||
BOOL WINAPI FlushConsoleInputBuffer( HANDLE handle )
|
||||
{
|
||||
BOOL ret;
|
||||
SERVER_START_REQ( read_console_input )
|
||||
{
|
||||
req->handle = handle;
|
||||
req->flush = TRUE;
|
||||
ret = !wine_server_call_err( req );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
return ret;
|
||||
enum read_console_input_return last;
|
||||
INPUT_RECORD ir;
|
||||
|
||||
while ((last = read_console_input(handle, &ir, 0)) == rci_gotone);
|
||||
|
||||
return last == rci_timeout;
|
||||
}
|
||||
|
||||
|
||||
|
@ -990,30 +1020,6 @@ BOOL WINAPI AllocConsole(void)
|
|||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* read_console_input
|
||||
*
|
||||
* Helper function for ReadConsole, ReadConsoleInput and PeekConsoleInput
|
||||
*/
|
||||
static BOOL read_console_input(HANDLE handle, LPINPUT_RECORD buffer, DWORD count,
|
||||
LPDWORD pRead, BOOL flush)
|
||||
{
|
||||
BOOL ret;
|
||||
unsigned read = 0;
|
||||
|
||||
SERVER_START_REQ( read_console_input )
|
||||
{
|
||||
req->handle = handle;
|
||||
req->flush = flush;
|
||||
wine_server_set_reply( req, buffer, count * sizeof(INPUT_RECORD) );
|
||||
if ((ret = !wine_server_call_err( req ))) read = reply->read;
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
if (pRead) *pRead = read;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* ReadConsoleA (KERNEL32.@)
|
||||
*/
|
||||
|
@ -1066,23 +1072,26 @@ BOOL WINAPI ReadConsoleW(HANDLE hConsoleInput, LPVOID lpBuffer,
|
|||
else
|
||||
{
|
||||
INPUT_RECORD ir;
|
||||
DWORD count;
|
||||
DWORD timeout = INFINITE;
|
||||
|
||||
/* FIXME: should we read at least 1 char? The SDK does not say */
|
||||
/* wait for at least one available input record (it doesn't mean we'll have
|
||||
* chars stored in xbuf...
|
||||
* chars stored in xbuf...)
|
||||
*/
|
||||
WaitForSingleObject(hConsoleInput, INFINITE);
|
||||
for (charsread = 0; charsread < nNumberOfCharsToRead;)
|
||||
charsread = 0;
|
||||
do
|
||||
{
|
||||
if (!read_console_input(hConsoleInput, &ir, 1, &count, TRUE)) return FALSE;
|
||||
if (count && ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown &&
|
||||
if (read_console_input(hConsoleInput, &ir, timeout) != rci_gotone) break;
|
||||
timeout = 0;
|
||||
if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown &&
|
||||
ir.Event.KeyEvent.uChar.UnicodeChar &&
|
||||
!(ir.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY))
|
||||
{
|
||||
xbuf[charsread++] = ir.Event.KeyEvent.uChar.UnicodeChar;
|
||||
}
|
||||
}
|
||||
} while (charsread < nNumberOfCharsToRead);
|
||||
/* nothing has been read */
|
||||
if (timeout == INFINITE) return FALSE;
|
||||
}
|
||||
|
||||
if (lpNumberOfCharsRead) *lpNumberOfCharsRead = charsread;
|
||||
|
@ -1097,7 +1106,8 @@ BOOL WINAPI ReadConsoleW(HANDLE hConsoleInput, LPVOID lpBuffer,
|
|||
BOOL WINAPI ReadConsoleInputW(HANDLE hConsoleInput, LPINPUT_RECORD lpBuffer,
|
||||
DWORD nLength, LPDWORD lpNumberOfEventsRead)
|
||||
{
|
||||
DWORD count;
|
||||
DWORD idx = 0;
|
||||
DWORD timeout = INFINITE;
|
||||
|
||||
if (!nLength)
|
||||
{
|
||||
|
@ -1106,17 +1116,12 @@ BOOL WINAPI ReadConsoleInputW(HANDLE hConsoleInput, LPINPUT_RECORD lpBuffer,
|
|||
}
|
||||
|
||||
/* loop until we get at least one event */
|
||||
for (;;)
|
||||
{
|
||||
WaitForSingleObject(hConsoleInput, INFINITE);
|
||||
if (!read_console_input(hConsoleInput, lpBuffer, nLength, &count, TRUE))
|
||||
return FALSE;
|
||||
if (count)
|
||||
{
|
||||
if (lpNumberOfEventsRead) *lpNumberOfEventsRead = count;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
while (read_console_input(hConsoleInput, &lpBuffer[idx], timeout) == rci_gotone &&
|
||||
++idx < nLength)
|
||||
timeout = 0;
|
||||
|
||||
if (lpNumberOfEventsRead) *lpNumberOfEventsRead = idx;
|
||||
return idx != 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1146,7 +1151,7 @@ BOOL WINAPI WriteConsoleOutputCharacterW( HANDLE hConsoleOutput, LPCWSTR str, DW
|
|||
|
||||
SERVER_START_REQ( write_console_output )
|
||||
{
|
||||
req->handle = hConsoleOutput;
|
||||
req->handle = console_handle_unmap(hConsoleOutput);
|
||||
req->x = coord.X;
|
||||
req->y = coord.Y;
|
||||
req->mode = CHAR_INFO_MODE_TEXT;
|
||||
|
@ -1474,7 +1479,7 @@ BOOL WINAPI GetConsoleScreenBufferInfo(HANDLE hConsoleOutput, LPCONSOLE_SCREEN_B
|
|||
|
||||
SERVER_START_REQ(get_console_output_info)
|
||||
{
|
||||
req->handle = hConsoleOutput;
|
||||
req->handle = console_handle_unmap(hConsoleOutput);
|
||||
if ((ret = !wine_server_call_err( req )))
|
||||
{
|
||||
csbi->dwSize.X = reply->width;
|
||||
|
@ -1530,7 +1535,7 @@ BOOL WINAPI GetConsoleMode(HANDLE hcon, LPDWORD mode)
|
|||
|
||||
SERVER_START_REQ(get_console_mode)
|
||||
{
|
||||
req->handle = hcon;
|
||||
req->handle = console_handle_unmap(hcon);
|
||||
ret = !wine_server_call_err( req );
|
||||
if (ret && mode) *mode = reply->mode;
|
||||
}
|
||||
|
@ -1563,7 +1568,7 @@ BOOL WINAPI SetConsoleMode(HANDLE hcon, DWORD mode)
|
|||
|
||||
SERVER_START_REQ(set_console_mode)
|
||||
{
|
||||
req->handle = hcon;
|
||||
req->handle = console_handle_unmap(hcon);
|
||||
req->mode = mode;
|
||||
ret = !wine_server_call_err( req );
|
||||
}
|
||||
|
@ -1592,7 +1597,7 @@ int CONSOLE_WriteChars(HANDLE hCon, LPCWSTR lpBuffer, int nc, COORD* pos)
|
|||
|
||||
SERVER_START_REQ( write_console_output )
|
||||
{
|
||||
req->handle = hCon;
|
||||
req->handle = console_handle_unmap(hCon);
|
||||
req->x = pos->X;
|
||||
req->y = pos->Y;
|
||||
req->mode = CHAR_INFO_MODE_TEXTSTDATTR;
|
||||
|
@ -1822,7 +1827,7 @@ BOOL WINAPI SetConsoleCursorPosition(HANDLE hcon, COORD pos)
|
|||
|
||||
SERVER_START_REQ(set_console_output_info)
|
||||
{
|
||||
req->handle = hcon;
|
||||
req->handle = console_handle_unmap(hcon);
|
||||
req->cursor_x = pos.X;
|
||||
req->cursor_y = pos.Y;
|
||||
req->mask = SET_CONSOLE_OUTPUT_INFO_CURSOR_POS;
|
||||
|
@ -1882,7 +1887,7 @@ BOOL WINAPI GetConsoleCursorInfo(HANDLE hcon, LPCONSOLE_CURSOR_INFO cinfo)
|
|||
|
||||
SERVER_START_REQ(get_console_output_info)
|
||||
{
|
||||
req->handle = hcon;
|
||||
req->handle = console_handle_unmap(hcon);
|
||||
ret = !wine_server_call_err( req );
|
||||
if (ret && cinfo)
|
||||
{
|
||||
|
@ -1911,7 +1916,7 @@ BOOL WINAPI SetConsoleCursorInfo(HANDLE hCon, LPCONSOLE_CURSOR_INFO cinfo)
|
|||
|
||||
SERVER_START_REQ(set_console_output_info)
|
||||
{
|
||||
req->handle = hCon;
|
||||
req->handle = console_handle_unmap(hCon);
|
||||
req->cursor_size = cinfo->dwSize;
|
||||
req->cursor_visible = cinfo->bVisible;
|
||||
req->mask = SET_CONSOLE_OUTPUT_INFO_CURSOR_GEOM;
|
||||
|
@ -1950,7 +1955,7 @@ BOOL WINAPI SetConsoleWindowInfo(HANDLE hCon, BOOL bAbsolute, LPSMALL_RECT windo
|
|||
}
|
||||
SERVER_START_REQ(set_console_output_info)
|
||||
{
|
||||
req->handle = hCon;
|
||||
req->handle = console_handle_unmap(hCon);
|
||||
req->win_left = p.Left;
|
||||
req->win_top = p.Top;
|
||||
req->win_right = p.Right;
|
||||
|
@ -1980,7 +1985,7 @@ BOOL WINAPI SetConsoleTextAttribute(HANDLE hConsoleOutput, WORD wAttr)
|
|||
|
||||
SERVER_START_REQ(set_console_output_info)
|
||||
{
|
||||
req->handle = hConsoleOutput;
|
||||
req->handle = console_handle_unmap(hConsoleOutput);
|
||||
req->attr = wAttr;
|
||||
req->mask = SET_CONSOLE_OUTPUT_INFO_ATTR;
|
||||
ret = !wine_server_call_err( req );
|
||||
|
@ -2007,7 +2012,7 @@ BOOL WINAPI SetConsoleScreenBufferSize(HANDLE hConsoleOutput, COORD dwSize)
|
|||
|
||||
SERVER_START_REQ(set_console_output_info)
|
||||
{
|
||||
req->handle = hConsoleOutput;
|
||||
req->handle = console_handle_unmap(hConsoleOutput);
|
||||
req->width = dwSize.X;
|
||||
req->height = dwSize.Y;
|
||||
req->mask = SET_CONSOLE_OUTPUT_INFO_SIZE;
|
||||
|
@ -2045,7 +2050,7 @@ void CONSOLE_FillLineUniform(HANDLE hConsoleOutput, int i, int j, int len, LPCHA
|
|||
{
|
||||
SERVER_START_REQ( fill_console_output )
|
||||
{
|
||||
req->handle = hConsoleOutput;
|
||||
req->handle = console_handle_unmap(hConsoleOutput);
|
||||
req->mode = CHAR_INFO_MODE_TEXTATTR;
|
||||
req->x = i;
|
||||
req->y = j;
|
||||
|
@ -2123,7 +2128,7 @@ BOOL WINAPI ScrollConsoleScreenBufferW(HANDLE hConsoleOutput, LPSMALL_RECT lpScr
|
|||
/* step 3: transfer the bits */
|
||||
SERVER_START_REQ(move_console_output)
|
||||
{
|
||||
req->handle = hConsoleOutput;
|
||||
req->handle = console_handle_unmap(hConsoleOutput);
|
||||
req->x_src = lpScrollRect->Left;
|
||||
req->y_src = lpScrollRect->Top;
|
||||
req->x_dst = dst.Left;
|
||||
|
@ -2254,7 +2259,7 @@ BOOL CONSOLE_GetEditionMode(HANDLE hConIn, int* mode)
|
|||
unsigned ret = FALSE;
|
||||
SERVER_START_REQ(get_console_input_info)
|
||||
{
|
||||
req->handle = hConIn;
|
||||
req->handle = console_handle_unmap(hConIn);
|
||||
if ((ret = !wine_server_call_err( req )))
|
||||
*mode = reply->edition_mode;
|
||||
}
|
||||
|
|
|
@ -88,29 +88,10 @@ static void WCEL_Dump(WCEL_Context* ctx, const char* pfx)
|
|||
|
||||
static BOOL WCEL_Get(WCEL_Context* ctx, INPUT_RECORD* ir)
|
||||
{
|
||||
DWORD retv;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/* data available ? */
|
||||
if (ReadConsoleInputW(ctx->hConIn, ir, 1, &retv) && retv == 1)
|
||||
return TRUE;
|
||||
/* then wait... */
|
||||
switch (WaitForSingleObject(ctx->hConIn, INFINITE))
|
||||
{
|
||||
case WAIT_OBJECT_0:
|
||||
break;
|
||||
default:
|
||||
/* we have checked that hConIn was a console handle (could be sb) */
|
||||
ERR("Shouldn't happen\n");
|
||||
/* fall thru */
|
||||
case WAIT_ABANDONED:
|
||||
case WAIT_TIMEOUT:
|
||||
ctx->error = 1;
|
||||
ERR("hmm bad situation\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
if (ReadConsoleInputW(ctx->hConIn, ir, 1, NULL)) return TRUE;
|
||||
ERR("hmm bad situation\n");
|
||||
ctx->error = 1;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static inline void WCEL_Beep(WCEL_Context* ctx)
|
||||
|
@ -633,7 +614,7 @@ static void WCEL_Redraw(WCEL_Context* ctx)
|
|||
static void WCEL_RepeatCount(WCEL_Context* ctx)
|
||||
{
|
||||
#if 0
|
||||
/* FIXME: wait untill all console code is in kernel32 */
|
||||
/* FIXME: wait until all console code is in kernel32 */
|
||||
INPUT_RECORD ir;
|
||||
unsigned repeat = 0;
|
||||
|
||||
|
@ -822,11 +803,12 @@ WCHAR* CONSOLE_Readline(HANDLE hConsoleIn)
|
|||
|
||||
while (!ctx.done && !ctx.error && WCEL_Get(&ctx, &ir))
|
||||
{
|
||||
if (ir.EventType != KEY_EVENT || !ir.Event.KeyEvent.bKeyDown) continue;
|
||||
if (ir.EventType != KEY_EVENT) continue;
|
||||
TRACE("key%s repeatCount=%u, keyCode=%02x scanCode=%02x char=%02x keyState=%08lx\n",
|
||||
ir.Event.KeyEvent.bKeyDown ? "Down" : "Up ", ir.Event.KeyEvent.wRepeatCount,
|
||||
ir.Event.KeyEvent.wVirtualKeyCode, ir.Event.KeyEvent.wVirtualScanCode,
|
||||
ir.Event.KeyEvent.uChar.UnicodeChar, ir.Event.KeyEvent.dwControlKeyState);
|
||||
if (!ir.Event.KeyEvent.bKeyDown) continue;
|
||||
|
||||
/* EPP WCEL_Dump(&ctx, "before func"); */
|
||||
ofs = ctx.ofs;
|
||||
|
|
|
@ -913,7 +913,7 @@
|
|||
@ stub AddConsoleAliasW
|
||||
@ stub BaseAttachCompleteThunk
|
||||
@ stub BasepDebugDump
|
||||
@ stub CloseConsoleHandle
|
||||
@ stdcall CloseConsoleHandle(long)
|
||||
@ stub CmdBatNotification
|
||||
@ stub ConsoleMenuControl
|
||||
@ stub ConsoleSubst
|
||||
|
@ -941,7 +941,7 @@
|
|||
@ stub GetConsoleFontInfo
|
||||
@ stub GetConsoleFontSize
|
||||
@ stub GetConsoleHardwareState
|
||||
@ stub GetConsoleInputWaitHandle
|
||||
@ stdcall GetConsoleInputWaitHandle()
|
||||
@ stub GetCurrentConsoleFont
|
||||
@ stub GetNextVDMCommand
|
||||
@ stub GetNumberOfConsoleFonts
|
||||
|
@ -953,7 +953,7 @@
|
|||
@ stub HeapUsage
|
||||
@ stub InvalidateConsoleDIBits
|
||||
@ stdcall IsDebuggerPresent()
|
||||
@ stub OpenConsoleW
|
||||
@ stdcall OpenConsoleW(wstr long ptr long)
|
||||
@ stub QueryWin31IniFilesMappedToRegistry
|
||||
@ stub RegisterConsoleVDM
|
||||
@ stub RegisterWaitForInputIdle
|
||||
|
@ -976,7 +976,7 @@
|
|||
@ stub TrimVirtualBuffer
|
||||
@ stub VDMConsoleOperation
|
||||
@ stub VDMOperationStarted
|
||||
@ stub VerifyConsoleIoHandle
|
||||
@ stdcall VerifyConsoleIoHandle(long)
|
||||
@ stub VirtualBufferExceptionHandler
|
||||
@ stub WriteConsoleInputVDMA
|
||||
@ stub WriteConsoleInputVDMW
|
||||
|
@ -991,7 +991,7 @@
|
|||
@ stdcall CreateWaitableTimerA(ptr long str)
|
||||
@ stdcall CreateWaitableTimerW(ptr long wstr)
|
||||
@ stdcall DeleteFiber(ptr)
|
||||
@ stub DuplicateConsoleHandle
|
||||
@ stdcall DuplicateConsoleHandle(long long long long)
|
||||
@ stdcall FindFirstFileExA(str long ptr long ptr long)
|
||||
@ stdcall FindFirstFileExW(wstr long ptr long ptr long)
|
||||
@ stub GetConsoleInputExeNameA
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Kernel32 undocumented and private functions definition
|
||||
*
|
||||
* Copyright 2003 Eric Pouech
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __WINE_KERNEL_PRIVATE_H
|
||||
#define __WINE_KERNEL_PRIVATE_H
|
||||
|
||||
HANDLE WINAPI OpenConsoleW(LPCWSTR, DWORD, LPSECURITY_ATTRIBUTES, DWORD);
|
||||
BOOL WINAPI VerifyConsoleIoHandle(HANDLE);
|
||||
HANDLE WINAPI DuplicateConsoleHandle(HANDLE, DWORD, BOOL, DWORD);
|
||||
BOOL WINAPI CloseConsoleHandle(HANDLE handle);
|
||||
HANDLE WINAPI GetConsoleInputWaitHandle(void);
|
||||
|
||||
static inline BOOL is_console_handle(HANDLE h)
|
||||
{
|
||||
return h != INVALID_HANDLE_VALUE && ((DWORD)h & 3) == 3;
|
||||
}
|
||||
|
||||
/* map a real wineserver handle onto a kernel32 console handle */
|
||||
static inline HANDLE console_handle_map(HANDLE h)
|
||||
{
|
||||
return h != INVALID_HANDLE_VALUE ? (HANDLE)((DWORD)h ^ 3) : INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
/* map a kernel32 console handle onto a real wineserver handle */
|
||||
static inline HANDLE console_handle_unmap(HANDLE h)
|
||||
{
|
||||
return h != INVALID_HANDLE_VALUE ? (HANDLE)((DWORD)h ^ 3) : INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -538,7 +538,7 @@ static void testScroll(HANDLE hCon, COORD sbSize)
|
|||
|
||||
START_TEST(console)
|
||||
{
|
||||
HANDLE hCon;
|
||||
HANDLE hConIn, hConOut;
|
||||
BOOL ret;
|
||||
CONSOLE_SCREEN_BUFFER_INFO sbi;
|
||||
|
||||
|
@ -548,16 +548,29 @@ START_TEST(console)
|
|||
* Another solution would be to rerun the test under wineconsole with
|
||||
* the curses backend
|
||||
*/
|
||||
FreeConsole();
|
||||
AllocConsole();
|
||||
hCon = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
ok(ret = GetConsoleScreenBufferInfo(hCon, &sbi), "Getting sb info");
|
||||
|
||||
hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
|
||||
hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
|
||||
|
||||
/* first, we need to be sure we're attached to a console */
|
||||
if (hConIn == INVALID_HANDLE_VALUE || hConOut == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
/* we're not attached to a console, let's do it */
|
||||
AllocConsole();
|
||||
hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
|
||||
hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
|
||||
}
|
||||
/* now verify everything's ok */
|
||||
ok(hConIn != INVALID_HANDLE_VALUE, "Opening ConIn");
|
||||
ok(hConOut != INVALID_HANDLE_VALUE, "Opening ConOut");
|
||||
|
||||
ok(ret = GetConsoleScreenBufferInfo(hConOut, &sbi), "Getting sb info");
|
||||
if (!ret) return;
|
||||
|
||||
/* Non interactive tests */
|
||||
testCursor(hCon, sbi.dwSize);
|
||||
testCursor(hConOut, sbi.dwSize);
|
||||
/* will test wrapped (on/off) & processed (on/off) strings output */
|
||||
testWrite(hCon, sbi.dwSize);
|
||||
testWrite(hConOut, sbi.dwSize);
|
||||
/* will test line scrolling at the bottom of the screen */
|
||||
/* testBottomScroll(); */
|
||||
/* will test all the scrolling operations */
|
||||
|
|
141
files/file.c
141
files/file.c
|
@ -70,6 +70,7 @@
|
|||
#include "heap.h"
|
||||
#include "msdos.h"
|
||||
#include "wincon.h"
|
||||
#include "../kernel/kernel_private.h"
|
||||
|
||||
#include "smb.h"
|
||||
#include "wine/unicode.h"
|
||||
|
@ -351,30 +352,124 @@ int FILE_GetUnixHandle( HANDLE handle, DWORD access )
|
|||
return FILE_GetUnixHandleType( handle, access, NULL, NULL );
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* FILE_OpenConsole
|
||||
/******************************************************************
|
||||
* OpenConsoleW (KERNEL32.@)
|
||||
*
|
||||
* Open a handle to the current process console.
|
||||
* Returns 0 on failure.
|
||||
* Undocumented
|
||||
* Open a handle to the current process console.
|
||||
* Returns INVALID_HANDLE_VALUE on failure.
|
||||
*/
|
||||
static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
|
||||
HANDLE WINAPI OpenConsoleW(LPCWSTR name, DWORD access, LPSECURITY_ATTRIBUTES sa,
|
||||
DWORD creation)
|
||||
{
|
||||
static const WCHAR coninW[] = {'C','O','N','I','N','$',0};
|
||||
static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
|
||||
BOOL output;
|
||||
HANDLE ret;
|
||||
|
||||
if (strcmpW(coninW, name) == 0)
|
||||
output = FALSE;
|
||||
else if (strcmpW(conoutW, name) == 0)
|
||||
output = TRUE;
|
||||
else
|
||||
{
|
||||
SetLastError(ERROR_INVALID_NAME);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (creation != OPEN_EXISTING)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
SERVER_START_REQ( open_console )
|
||||
{
|
||||
req->from = output;
|
||||
req->access = access;
|
||||
req->share = sharing;
|
||||
req->share = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||||
req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
|
||||
SetLastError(0);
|
||||
wine_server_call_err( req );
|
||||
ret = reply->handle;
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
return ret ? console_handle_map(ret) : INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* VerifyConsoleIoHandle (KERNEL32.@)
|
||||
*
|
||||
* Undocumented
|
||||
*/
|
||||
BOOL WINAPI VerifyConsoleIoHandle(HANDLE handle)
|
||||
{
|
||||
BOOL ret;
|
||||
|
||||
if (!is_console_handle(handle)) return FALSE;
|
||||
SERVER_START_REQ(get_console_mode)
|
||||
{
|
||||
req->handle = console_handle_unmap(handle);
|
||||
ret = !wine_server_call_err( req );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* DuplicateConsoleHandle (KERNEL32.@)
|
||||
*
|
||||
* Undocumented
|
||||
*/
|
||||
HANDLE WINAPI DuplicateConsoleHandle(HANDLE handle, DWORD access, BOOL inherit,
|
||||
DWORD options)
|
||||
{
|
||||
HANDLE ret;
|
||||
|
||||
if (!is_console_handle(handle) ||
|
||||
!DuplicateHandle(GetCurrentProcess(), console_handle_unmap(handle),
|
||||
GetCurrentProcess(), &ret, access, inherit, options))
|
||||
return INVALID_HANDLE_VALUE;
|
||||
return console_handle_map(ret);
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* CloseConsoleHandle (KERNEL32.@)
|
||||
*
|
||||
* Undocumented
|
||||
*/
|
||||
BOOL WINAPI CloseConsoleHandle(HANDLE handle)
|
||||
{
|
||||
if (!is_console_handle(handle))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
return CloseHandle(console_handle_unmap(handle));
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* GetConsoleInputWaitHandle (KERNEL32.@)
|
||||
*
|
||||
* Undocumented
|
||||
*/
|
||||
HANDLE WINAPI GetConsoleInputWaitHandle(void)
|
||||
{
|
||||
static HANDLE console_wait_event;
|
||||
|
||||
/* FIXME: this is not thread safe */
|
||||
if (!console_wait_event)
|
||||
{
|
||||
SERVER_START_REQ(get_console_wait_event)
|
||||
{
|
||||
if (!wine_server_call_err( req )) console_wait_event = reply->handle;
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
}
|
||||
return console_wait_event;
|
||||
}
|
||||
/* end of FIXME */
|
||||
|
||||
|
||||
/* FIXME: those routines defined as pointers are needed, because this file is
|
||||
* currently compiled into NTDLL whereas it belongs to kernel32.
|
||||
* this shall go away once all the DLL separation process is done
|
||||
|
@ -630,14 +725,9 @@ HANDLE WINAPI CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing,
|
|||
}
|
||||
|
||||
/* Open a console for CONIN$ or CONOUT$ */
|
||||
if (!strcmpiW(filename, coninW))
|
||||
if (!strcmpiW(filename, coninW) || !strcmpiW(filename, conoutW))
|
||||
{
|
||||
ret = FILE_OpenConsole( FALSE, access, sharing, sa );
|
||||
goto done;
|
||||
}
|
||||
if (!strcmpiW(filename, conoutW))
|
||||
{
|
||||
ret = FILE_OpenConsole( TRUE, access, sharing, sa );
|
||||
ret = OpenConsoleW(filename, access, sa, creation);
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -1807,6 +1897,9 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
|
|||
if (bytesRead) *bytesRead = 0; /* Do this before anything else */
|
||||
if (!bytesToRead) return TRUE;
|
||||
|
||||
if (is_console_handle(hFile))
|
||||
return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
|
||||
|
||||
unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags );
|
||||
|
||||
if (flags & FD_FLAG_OVERLAPPED)
|
||||
|
@ -1845,9 +1938,6 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
|
|||
case FD_TYPE_SMB:
|
||||
return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL);
|
||||
|
||||
case FD_TYPE_CONSOLE:
|
||||
return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL);
|
||||
|
||||
case FD_TYPE_DEFAULT:
|
||||
/* normal unix files */
|
||||
if (unix_handle == -1) return FALSE;
|
||||
|
@ -2031,6 +2121,9 @@ BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
|
|||
if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */
|
||||
if (!bytesToWrite) return TRUE;
|
||||
|
||||
if (is_console_handle(hFile))
|
||||
return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
|
||||
|
||||
unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags );
|
||||
|
||||
if (flags & FD_FLAG_OVERLAPPED)
|
||||
|
@ -2062,11 +2155,6 @@ BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
|
|||
|
||||
switch(type)
|
||||
{
|
||||
case FD_TYPE_CONSOLE:
|
||||
TRACE("%p %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite,
|
||||
bytesWritten, overlapped );
|
||||
return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL);
|
||||
|
||||
case FD_TYPE_DEFAULT:
|
||||
if (unix_handle == -1) return FALSE;
|
||||
|
||||
|
@ -2366,6 +2454,13 @@ BOOL WINAPI FlushFileBuffers( HANDLE hFile )
|
|||
NTSTATUS nts;
|
||||
IO_STATUS_BLOCK ioblk;
|
||||
|
||||
if (is_console_handle( hFile ))
|
||||
{
|
||||
/* this will fail (as expected) for an output handle */
|
||||
/* FIXME: wait until FlushFileBuffers is moved to dll/kernel */
|
||||
/* return FlushConsoleInputBuffer( hFile ); */
|
||||
return TRUE;
|
||||
}
|
||||
nts = NtFlushBuffersFile( hFile, &ioblk );
|
||||
if (nts != STATUS_SUCCESS)
|
||||
{
|
||||
|
@ -2473,6 +2568,10 @@ BOOL WINAPI DeleteFileA( LPCSTR path )
|
|||
DWORD WINAPI GetFileType( HANDLE hFile )
|
||||
{
|
||||
DWORD ret = FILE_TYPE_UNKNOWN;
|
||||
|
||||
if (is_console_handle( hFile ))
|
||||
return FILE_TYPE_CHAR;
|
||||
|
||||
SERVER_START_REQ( get_file_info )
|
||||
{
|
||||
req->handle = hFile;
|
||||
|
|
|
@ -815,7 +815,6 @@ enum fd_type
|
|||
{
|
||||
FD_TYPE_INVALID,
|
||||
FD_TYPE_DEFAULT,
|
||||
FD_TYPE_CONSOLE,
|
||||
FD_TYPE_SOCKET,
|
||||
FD_TYPE_SMB
|
||||
};
|
||||
|
@ -1037,6 +1036,7 @@ struct alloc_console_request
|
|||
unsigned int access;
|
||||
int inherit;
|
||||
process_id_t pid;
|
||||
obj_handle_t wait_event;
|
||||
};
|
||||
struct alloc_console_reply
|
||||
{
|
||||
|
@ -1132,6 +1132,17 @@ struct open_console_reply
|
|||
|
||||
|
||||
|
||||
struct get_console_wait_event_request
|
||||
{
|
||||
struct request_header __header;
|
||||
};
|
||||
struct get_console_wait_event_reply
|
||||
{
|
||||
struct reply_header __header;
|
||||
obj_handle_t handle;
|
||||
};
|
||||
|
||||
|
||||
struct get_console_mode_request
|
||||
{
|
||||
struct request_header __header;
|
||||
|
@ -3089,6 +3100,7 @@ enum request
|
|||
REQ_free_console,
|
||||
REQ_get_console_renderer_events,
|
||||
REQ_open_console,
|
||||
REQ_get_console_wait_event,
|
||||
REQ_get_console_mode,
|
||||
REQ_set_console_mode,
|
||||
REQ_set_console_input_info,
|
||||
|
@ -3270,6 +3282,7 @@ union generic_request
|
|||
struct free_console_request free_console_request;
|
||||
struct get_console_renderer_events_request get_console_renderer_events_request;
|
||||
struct open_console_request open_console_request;
|
||||
struct get_console_wait_event_request get_console_wait_event_request;
|
||||
struct get_console_mode_request get_console_mode_request;
|
||||
struct set_console_mode_request set_console_mode_request;
|
||||
struct set_console_input_info_request set_console_input_info_request;
|
||||
|
@ -3449,6 +3462,7 @@ union generic_reply
|
|||
struct free_console_reply free_console_reply;
|
||||
struct get_console_renderer_events_reply get_console_renderer_events_reply;
|
||||
struct open_console_reply open_console_reply;
|
||||
struct get_console_wait_event_reply get_console_wait_event_reply;
|
||||
struct get_console_mode_reply get_console_mode_reply;
|
||||
struct set_console_mode_reply set_console_mode_reply;
|
||||
struct set_console_input_info_reply set_console_input_info_reply;
|
||||
|
@ -3569,6 +3583,6 @@ union generic_reply
|
|||
struct get_next_hook_reply get_next_hook_reply;
|
||||
};
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 109
|
||||
#define SERVER_PROTOCOL_VERSION 110
|
||||
|
||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||
|
|
|
@ -535,6 +535,7 @@ static struct inner_data* WINECON_Init(HINSTANCE hInst, DWORD pid, LPCWSTR appna
|
|||
DWORD ret;
|
||||
struct config_data cfg;
|
||||
STARTUPINFOW si;
|
||||
HANDLE sem;
|
||||
|
||||
data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data));
|
||||
if (!data) return 0;
|
||||
|
@ -563,6 +564,7 @@ static struct inner_data* WINECON_Init(HINSTANCE hInst, DWORD pid, LPCWSTR appna
|
|||
/* should always be defined */
|
||||
}
|
||||
|
||||
sem = CreateSemaphore(NULL, 0, 65536, NULL);
|
||||
/* the handles here are created without the whistles and bells required by console
|
||||
* (mainly because wineconsole doesn't need it)
|
||||
* - they are not inheritable
|
||||
|
@ -570,9 +572,11 @@ static struct inner_data* WINECON_Init(HINSTANCE hInst, DWORD pid, LPCWSTR appna
|
|||
*/
|
||||
SERVER_START_REQ(alloc_console)
|
||||
{
|
||||
req->access = GENERIC_READ | GENERIC_WRITE;
|
||||
req->inherit = FALSE;
|
||||
req->pid = pid;
|
||||
req->access = GENERIC_READ | GENERIC_WRITE;
|
||||
req->inherit = FALSE;
|
||||
req->pid = pid;
|
||||
req->wait_event = sem;
|
||||
|
||||
ret = !wine_server_call_err( req );
|
||||
data->hConIn = (HANDLE)reply->handle_in;
|
||||
data->hSynchro = (HANDLE)reply->event;
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "wine/server.h"
|
||||
#include "winerror.h"
|
||||
#include "wine/debug.h"
|
||||
#include "../kernel/kernel_private.h" /* FIXME: to be changed when moving file to dlls/kernel */
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(win32);
|
||||
|
||||
|
@ -49,6 +50,9 @@ BOOL WINAPI CloseHandle( HANDLE handle )
|
|||
(handle == (HANDLE)STD_ERROR_HANDLE))
|
||||
handle = GetStdHandle( (DWORD)handle );
|
||||
|
||||
if (is_console_handle(handle))
|
||||
return CloseConsoleHandle(handle);
|
||||
|
||||
status = NtClose( handle );
|
||||
if (status) SetLastError( RtlNtStatusToDosError(status) );
|
||||
return !status;
|
||||
|
@ -101,8 +105,22 @@ BOOL WINAPI DuplicateHandle( HANDLE source_process, HANDLE source,
|
|||
HANDLE dest_process, HANDLE *dest,
|
||||
DWORD access, BOOL inherit, DWORD options )
|
||||
{
|
||||
NTSTATUS status = NtDuplicateObject( source_process, source, dest_process, dest,
|
||||
access, inherit ? OBJ_INHERIT : 0, options );
|
||||
NTSTATUS status;
|
||||
|
||||
if (is_console_handle(source))
|
||||
{
|
||||
/* FIXME: this test is not sufficient, we need to test process ids, not handles */
|
||||
if (source_process != dest_process ||
|
||||
source_process != GetCurrentProcess())
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
*dest = DuplicateConsoleHandle( source, access, inherit, options );
|
||||
return (*dest != INVALID_HANDLE_VALUE);
|
||||
}
|
||||
status = NtDuplicateObject( source_process, source, dest_process, dest,
|
||||
access, inherit ? OBJ_INHERIT : 0, options );
|
||||
if (status) SetLastError( RtlNtStatusToDosError(status) );
|
||||
return !status;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "wine/server.h"
|
||||
#include "options.h"
|
||||
#include "wine/debug.h"
|
||||
#include "../kernel/kernel_private.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(process);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(server);
|
||||
|
@ -328,19 +329,31 @@ static BOOL process_init( char *argv[] )
|
|||
/* Create the process heap */
|
||||
current_process.heap = HeapCreate( HEAP_GROWABLE, 0, 0 );
|
||||
|
||||
if (main_create_flags == 0 &&
|
||||
process_pmts.hStdInput == 0 &&
|
||||
process_pmts.hStdOutput == 0 &&
|
||||
process_pmts.hStdError == 0)
|
||||
if (info_size == 0)
|
||||
{
|
||||
/* This is wine specific:
|
||||
* no parent, and no new console requested, create a simple console with bare handles to
|
||||
* unix stdio input & output streams (aka simple console)
|
||||
/* This is wine specific: we have no parent (we're started from unix)
|
||||
* so, create a simple console with bare handles to unix stdio
|
||||
* input & output streams (aka simple console)
|
||||
*/
|
||||
wine_server_fd_to_handle( 0, GENERIC_READ|SYNCHRONIZE, TRUE, &process_pmts.hStdInput );
|
||||
wine_server_fd_to_handle( 1, GENERIC_WRITE|SYNCHRONIZE, TRUE, &process_pmts.hStdOutput );
|
||||
wine_server_fd_to_handle( 1, GENERIC_WRITE|SYNCHRONIZE, TRUE, &process_pmts.hStdError );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!process_pmts.hStdInput)
|
||||
process_pmts.hStdInput = INVALID_HANDLE_VALUE;
|
||||
else if (VerifyConsoleIoHandle(console_handle_map(process_pmts.hStdInput)))
|
||||
process_pmts.hStdInput = console_handle_map(process_pmts.hStdInput);
|
||||
if (!process_pmts.hStdOutput)
|
||||
process_pmts.hStdOutput = INVALID_HANDLE_VALUE;
|
||||
else if (VerifyConsoleIoHandle(console_handle_map(process_pmts.hStdOutput)))
|
||||
process_pmts.hStdOutput = console_handle_map(process_pmts.hStdOutput);
|
||||
if (!process_pmts.hStdError)
|
||||
process_pmts.hStdError = INVALID_HANDLE_VALUE;
|
||||
else if (VerifyConsoleIoHandle(console_handle_map(process_pmts.hStdError)))
|
||||
process_pmts.hStdError = console_handle_map(process_pmts.hStdError);
|
||||
}
|
||||
|
||||
/* Now we can use the pthreads routines */
|
||||
PTHREAD_init_done();
|
||||
|
@ -951,6 +964,20 @@ static BOOL create_process( HANDLE hFile, LPCSTR filename, LPSTR cmd_line, LPCST
|
|||
req->hstderr = GetStdHandle( STD_ERROR_HANDLE );
|
||||
}
|
||||
|
||||
if ((flags & (CREATE_NEW_CONSOLE | DETACHED_PROCESS)) != 0)
|
||||
{
|
||||
/* this is temporary (for console handles). We have no way to control that the handle is invalid in child process otherwise */
|
||||
if (is_console_handle(req->hstdin)) req->hstdin = INVALID_HANDLE_VALUE;
|
||||
if (is_console_handle(req->hstdout)) req->hstdout = INVALID_HANDLE_VALUE;
|
||||
if (is_console_handle(req->hstderr)) req->hstderr = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_console_handle(req->hstdin)) req->hstdin = console_handle_unmap(req->hstdin);
|
||||
if (is_console_handle(req->hstdout)) req->hstdout = console_handle_unmap(req->hstdout);
|
||||
if (is_console_handle(req->hstderr)) req->hstderr = console_handle_unmap(req->hstderr);
|
||||
}
|
||||
|
||||
if (GetLongPathNameA( filename, buf, MAX_PATH ))
|
||||
nameptr = buf;
|
||||
else
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "winbase.h"
|
||||
#include "winternl.h"
|
||||
#include "../kernel/kernel_private.h" /* FIXME: to be changed when moving file to dlls/kernel */
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -80,10 +81,39 @@ DWORD WINAPI WaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
|
|||
BOOL alertable )
|
||||
{
|
||||
NTSTATUS status;
|
||||
HANDLE hloc[MAXIMUM_WAIT_OBJECTS];
|
||||
int i;
|
||||
|
||||
if (count >= MAXIMUM_WAIT_OBJECTS)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return WAIT_FAILED;
|
||||
}
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if ((handles[i] == (HANDLE)STD_INPUT_HANDLE) ||
|
||||
(handles[i] == (HANDLE)STD_OUTPUT_HANDLE) ||
|
||||
(handles[i] == (HANDLE)STD_ERROR_HANDLE))
|
||||
hloc[i] = GetStdHandle( (DWORD)handles[i] );
|
||||
else
|
||||
hloc[i] = handles[i];
|
||||
|
||||
/* yes, even screen buffer console handles are waitable, and are
|
||||
* handled as a handle to the console itself !!
|
||||
*/
|
||||
if (is_console_handle(hloc[i]))
|
||||
{
|
||||
if (!VerifyConsoleIoHandle(hloc[i]))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
hloc[i] = GetConsoleInputWaitHandle();
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout == INFINITE)
|
||||
{
|
||||
status = NtWaitForMultipleObjects( count, handles, wait_all, alertable, NULL );
|
||||
status = NtWaitForMultipleObjects( count, hloc, wait_all, alertable, NULL );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -91,7 +121,7 @@ DWORD WINAPI WaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
|
|||
|
||||
time.QuadPart = timeout * (ULONGLONG)10000;
|
||||
time.QuadPart = -time.QuadPart;
|
||||
status = NtWaitForMultipleObjects( count, handles, wait_all, alertable, &time );
|
||||
status = NtWaitForMultipleObjects( count, hloc, wait_all, alertable, &time );
|
||||
}
|
||||
|
||||
if (HIWORD(status)) /* is it an error code? */
|
||||
|
|
|
@ -35,18 +35,16 @@
|
|||
#include "unicode.h"
|
||||
#include "console.h"
|
||||
|
||||
|
||||
static void console_input_dump( struct object *obj, int verbose );
|
||||
static void console_input_destroy( struct object *obj );
|
||||
static int console_input_signaled( struct object *obj, struct thread *thread );
|
||||
|
||||
static const struct object_ops console_input_ops =
|
||||
{
|
||||
sizeof(struct console_input), /* size */
|
||||
console_input_dump, /* dump */
|
||||
add_queue, /* add_queue */
|
||||
remove_queue, /* remove_queue */
|
||||
console_input_signaled, /* signaled */
|
||||
no_add_queue, /* add_queue */
|
||||
NULL, /* remove_queue */
|
||||
NULL, /* signaled */
|
||||
no_satisfied, /* satisfied */
|
||||
no_get_fd, /* get_fd */
|
||||
console_input_destroy /* destroy */
|
||||
|
@ -205,7 +203,7 @@ static struct console_input_events *create_console_input_events(void)
|
|||
return evt;
|
||||
}
|
||||
|
||||
static struct object *create_console_input( struct thread* renderer )
|
||||
static struct object *create_console_input( struct thread* renderer, struct object* wait_obj )
|
||||
{
|
||||
struct console_input *console_input;
|
||||
|
||||
|
@ -224,6 +222,7 @@ static struct object *create_console_input( struct thread* renderer )
|
|||
console_input->history_index = 0;
|
||||
console_input->history_mode = 0;
|
||||
console_input->edition_mode = 0;
|
||||
console_input->wait_obj = wait_obj;
|
||||
|
||||
if (!console_input->history || !console_input->evt)
|
||||
{
|
||||
|
@ -368,11 +367,6 @@ void inherit_console(struct thread *parent_thread, struct process *process, obj_
|
|||
}
|
||||
}
|
||||
|
||||
int is_console_object( struct object *obj )
|
||||
{
|
||||
return (obj->ops == &console_input_ops || obj->ops == &screen_buffer_ops);
|
||||
}
|
||||
|
||||
static struct console_input* console_input_get( obj_handle_t handle, unsigned access )
|
||||
{
|
||||
struct console_input* console = 0;
|
||||
|
@ -390,14 +384,6 @@ static struct console_input* console_input_get( obj_handle_t handle, unsigned ac
|
|||
return console;
|
||||
}
|
||||
|
||||
/* check if a console input is signaled: yes if non read input records */
|
||||
static int console_input_signaled( struct object *obj, struct thread *thread )
|
||||
{
|
||||
struct console_input *console = (struct console_input *)obj;
|
||||
assert( obj->ops == &console_input_ops );
|
||||
return console->recnum ? 1 : 0;
|
||||
}
|
||||
|
||||
struct console_signal_info {
|
||||
struct console_input *console;
|
||||
process_id_t group;
|
||||
|
@ -957,6 +943,7 @@ static void console_input_destroy( struct object *obj )
|
|||
|
||||
release_object( console_in->evt );
|
||||
console_in->evt = NULL;
|
||||
release_object( console_in->wait_obj );
|
||||
|
||||
for (i = 0; i < console_in->history_size; i++)
|
||||
if (console_in->history[i]) free( console_in->history[i] );
|
||||
|
@ -1222,6 +1209,7 @@ DECL_HANDLER(alloc_console)
|
|||
struct process *process;
|
||||
struct process *renderer = current->process;
|
||||
struct console_input *console;
|
||||
struct object *wait_event;
|
||||
|
||||
process = (req->pid) ? get_process_from_id( req->pid ) :
|
||||
(struct process *)grab_object( renderer->parent );
|
||||
|
@ -1234,8 +1222,13 @@ DECL_HANDLER(alloc_console)
|
|||
set_error( STATUS_ACCESS_DENIED );
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
if ((console = (struct console_input*)create_console_input( current )))
|
||||
wait_event = get_handle_obj( renderer, req->wait_event, 0, NULL);
|
||||
if (!wait_event)
|
||||
{
|
||||
set_error( STATUS_INVALID_PARAMETER );
|
||||
goto the_end;
|
||||
}
|
||||
if ((console = (struct console_input*)create_console_input( current, wait_event )))
|
||||
{
|
||||
if ((in = alloc_handle( renderer, console, req->access, req->inherit )))
|
||||
{
|
||||
|
@ -1512,7 +1505,35 @@ DECL_HANDLER(send_console_signal)
|
|||
group = req->group_id ? req->group_id : current->process->group_id;
|
||||
|
||||
if (!group)
|
||||
set_error( STATUS_INVALID_PARAMETER);
|
||||
set_error( STATUS_INVALID_PARAMETER );
|
||||
else
|
||||
propagate_console_signal( current->process->console, req->signal, group );
|
||||
}
|
||||
|
||||
/* get console which renderer is 'current' */
|
||||
static int cgwe_enum( struct process* process, void* user)
|
||||
{
|
||||
if (process->console && process->console->renderer == current)
|
||||
{
|
||||
*(struct console_input**)user = process->console;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECL_HANDLER(get_console_wait_event)
|
||||
{
|
||||
struct console_input* console = NULL;
|
||||
|
||||
if (current->process->console && current->process->console->renderer)
|
||||
console = (struct console_input*)grab_object( (struct object*)current->process->console );
|
||||
else enum_processes(cgwe_enum, &console);
|
||||
|
||||
if (console)
|
||||
{
|
||||
reply->handle = alloc_handle( current->process, console->wait_obj,
|
||||
SEMAPHORE_ALL_ACCESS, FALSE);
|
||||
release_object( console );
|
||||
}
|
||||
else set_error( STATUS_INVALID_PARAMETER );
|
||||
}
|
||||
|
|
|
@ -42,12 +42,12 @@ struct console_input
|
|||
int history_index; /* number of used entries in history array */
|
||||
int history_mode; /* mode of history (non zero means remove doubled strings */
|
||||
int edition_mode; /* index to edition mode flavors */
|
||||
struct object *wait_obj; /* object to wait on for input queue */
|
||||
};
|
||||
|
||||
/* console functions */
|
||||
|
||||
extern void inherit_console(struct thread *parent_thread, struct process *process, obj_handle_t hconin);
|
||||
extern int free_console( struct process *process );
|
||||
extern int is_console_object( struct object *obj );
|
||||
|
||||
#endif /* __WINE_SERVER_CONSOLE_H */
|
||||
|
|
11
server/fd.c
11
server/fd.c
|
@ -42,7 +42,6 @@
|
|||
#include "handle.h"
|
||||
#include "process.h"
|
||||
#include "request.h"
|
||||
#include "console.h"
|
||||
|
||||
/* Because of the stupid Posix locking semantics, we need to keep
|
||||
* track of all file descriptors referencing a given file, and not
|
||||
|
@ -1035,16 +1034,6 @@ DECL_HANDLER(get_handle_fd)
|
|||
reply->type = fd->fd_ops->get_file_info( fd, NULL, &reply->flags );
|
||||
release_object( fd );
|
||||
}
|
||||
else /* check for console handle (FIXME: should be done in the client) */
|
||||
{
|
||||
struct object *obj;
|
||||
|
||||
if ((obj = get_handle_obj( current->process, req->handle, req->access, NULL )))
|
||||
{
|
||||
if (is_console_object( obj )) reply->type = FD_TYPE_CONSOLE;
|
||||
release_object( obj );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* get a file information */
|
||||
|
|
|
@ -221,40 +221,11 @@ static int set_process_console( struct process *process, struct thread *parent_t
|
|||
}
|
||||
if (info)
|
||||
{
|
||||
if (!info->inherit_all && !info->use_handles)
|
||||
{
|
||||
/* duplicate the handle from the parent into this process */
|
||||
reply->hstdin = duplicate_handle( parent_thread->process, info->hstdin, process,
|
||||
0, TRUE, DUPLICATE_SAME_ACCESS );
|
||||
reply->hstdout = duplicate_handle( parent_thread->process, info->hstdout, process,
|
||||
0, TRUE, DUPLICATE_SAME_ACCESS );
|
||||
reply->hstderr = duplicate_handle( parent_thread->process, info->hstderr, process,
|
||||
0, TRUE, DUPLICATE_SAME_ACCESS );
|
||||
}
|
||||
else
|
||||
{
|
||||
reply->hstdin = info->hstdin;
|
||||
reply->hstdout = info->hstdout;
|
||||
reply->hstderr = info->hstderr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (process->console)
|
||||
{
|
||||
reply->hstdin = alloc_handle( process, process->console,
|
||||
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
|
||||
reply->hstdout = alloc_handle( process, process->console->active,
|
||||
GENERIC_READ | GENERIC_WRITE, 1 );
|
||||
reply->hstderr = alloc_handle( process, process->console->active,
|
||||
GENERIC_READ | GENERIC_WRITE, 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no parent, let the caller decide what to do */
|
||||
reply->hstdin = reply->hstdout = reply->hstderr = 0;
|
||||
}
|
||||
reply->hstdin = info->hstdin;
|
||||
reply->hstdout = info->hstdout;
|
||||
reply->hstderr = info->hstderr;
|
||||
}
|
||||
else reply->hstdin = reply->hstdout = reply->hstderr = 0;
|
||||
/* some handles above may have been invalid; this is not an error */
|
||||
if (get_error() == STATUS_INVALID_HANDLE) clear_error();
|
||||
return 1;
|
||||
|
|
|
@ -627,7 +627,6 @@ enum fd_type
|
|||
{
|
||||
FD_TYPE_INVALID,
|
||||
FD_TYPE_DEFAULT,
|
||||
FD_TYPE_CONSOLE,
|
||||
FD_TYPE_SOCKET,
|
||||
FD_TYPE_SMB
|
||||
};
|
||||
|
@ -776,6 +775,7 @@ enum fd_type
|
|||
unsigned int access; /* wanted access rights */
|
||||
int inherit; /* inherit flag */
|
||||
process_id_t pid; /* pid of process which shall be attached to the console */
|
||||
obj_handle_t wait_event; /* semaphore for number of active input events */
|
||||
@REPLY
|
||||
obj_handle_t handle_in; /* handle to console input */
|
||||
obj_handle_t event; /* handle to renderer events change notification */
|
||||
|
@ -851,6 +851,12 @@ struct console_renderer_event
|
|||
@END
|
||||
|
||||
|
||||
/* Get the input queue wait event */
|
||||
@REQ(get_console_wait_event)
|
||||
@REPLY
|
||||
obj_handle_t handle;
|
||||
@END
|
||||
|
||||
/* Get a console mode (input or output) */
|
||||
@REQ(get_console_mode)
|
||||
obj_handle_t handle; /* handle to the console */
|
||||
|
|
|
@ -159,6 +159,7 @@ DECL_HANDLER(alloc_console);
|
|||
DECL_HANDLER(free_console);
|
||||
DECL_HANDLER(get_console_renderer_events);
|
||||
DECL_HANDLER(open_console);
|
||||
DECL_HANDLER(get_console_wait_event);
|
||||
DECL_HANDLER(get_console_mode);
|
||||
DECL_HANDLER(set_console_mode);
|
||||
DECL_HANDLER(set_console_input_info);
|
||||
|
@ -339,6 +340,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
|
|||
(req_handler)req_free_console,
|
||||
(req_handler)req_get_console_renderer_events,
|
||||
(req_handler)req_open_console,
|
||||
(req_handler)req_get_console_wait_event,
|
||||
(req_handler)req_get_console_mode,
|
||||
(req_handler)req_set_console_mode,
|
||||
(req_handler)req_set_console_input_info,
|
||||
|
|
|
@ -997,7 +997,8 @@ static void dump_alloc_console_request( const struct alloc_console_request *req
|
|||
{
|
||||
fprintf( stderr, " access=%08x,", req->access );
|
||||
fprintf( stderr, " inherit=%d,", req->inherit );
|
||||
fprintf( stderr, " pid=%04x", req->pid );
|
||||
fprintf( stderr, " pid=%04x,", req->pid );
|
||||
fprintf( stderr, " wait_event=%p", req->wait_event );
|
||||
}
|
||||
|
||||
static void dump_alloc_console_reply( const struct alloc_console_reply *req )
|
||||
|
@ -1034,6 +1035,15 @@ static void dump_open_console_reply( const struct open_console_reply *req )
|
|||
fprintf( stderr, " handle=%p", req->handle );
|
||||
}
|
||||
|
||||
static void dump_get_console_wait_event_request( const struct get_console_wait_event_request *req )
|
||||
{
|
||||
}
|
||||
|
||||
static void dump_get_console_wait_event_reply( const struct get_console_wait_event_reply *req )
|
||||
{
|
||||
fprintf( stderr, " handle=%p", req->handle );
|
||||
}
|
||||
|
||||
static void dump_get_console_mode_request( const struct get_console_mode_request *req )
|
||||
{
|
||||
fprintf( stderr, " handle=%p", req->handle );
|
||||
|
@ -2506,6 +2516,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
|||
(dump_func)dump_free_console_request,
|
||||
(dump_func)dump_get_console_renderer_events_request,
|
||||
(dump_func)dump_open_console_request,
|
||||
(dump_func)dump_get_console_wait_event_request,
|
||||
(dump_func)dump_get_console_mode_request,
|
||||
(dump_func)dump_set_console_mode_request,
|
||||
(dump_func)dump_set_console_input_info_request,
|
||||
|
@ -2683,6 +2694,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
|||
(dump_func)0,
|
||||
(dump_func)dump_get_console_renderer_events_reply,
|
||||
(dump_func)dump_open_console_reply,
|
||||
(dump_func)dump_get_console_wait_event_reply,
|
||||
(dump_func)dump_get_console_mode_reply,
|
||||
(dump_func)0,
|
||||
(dump_func)0,
|
||||
|
@ -2860,6 +2872,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
|
|||
"free_console",
|
||||
"get_console_renderer_events",
|
||||
"open_console",
|
||||
"get_console_wait_event",
|
||||
"get_console_mode",
|
||||
"set_console_mode",
|
||||
"set_console_input_info",
|
||||
|
|
Loading…
Reference in New Issue