Commit 412d37f6 authored by Eric Pouech's avatar Eric Pouech Committed by Alexandre Julliard

- 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
parent 64a41a28
......@@ -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;
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
......
/*
* 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();
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();
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);
}
/* 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 */
......
......@@ -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.@)
*
* Undocumented
* Open a handle to the current process console.
* Returns 0 on failure.
* 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
......@@ -573,6 +575,8 @@ static struct inner_data* WINECON_Init(HINSTANCE hInst, DWORD pid, LPCWSTR appna
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,7 +105,21 @@ 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,
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 */
......@@ -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;
}
}
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",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment