diff --git a/dlls/kernel/console.c b/dlls/kernel/console.c index d065178023f..7b3eba1266c 100644 --- a/dlls/kernel/console.c +++ b/dlls/kernel/console.c @@ -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; } diff --git a/dlls/kernel/editline.c b/dlls/kernel/editline.c index 086b2bc0ee3..48998cd2bbf 100644 --- a/dlls/kernel/editline.c +++ b/dlls/kernel/editline.c @@ -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; diff --git a/dlls/kernel/kernel32.spec b/dlls/kernel/kernel32.spec index c572e9d814c..6797b4d982e 100644 --- a/dlls/kernel/kernel32.spec +++ b/dlls/kernel/kernel32.spec @@ -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 diff --git a/dlls/kernel/kernel_private.h b/dlls/kernel/kernel_private.h new file mode 100644 index 00000000000..fa3b99c287e --- /dev/null +++ b/dlls/kernel/kernel_private.h @@ -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 diff --git a/dlls/kernel/tests/console.c b/dlls/kernel/tests/console.c index 5dcd115b003..06cba392cd5 100644 --- a/dlls/kernel/tests/console.c +++ b/dlls/kernel/tests/console.c @@ -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 */ diff --git a/files/file.c b/files/file.c index 5603a424012..0982999e2b0 100644 --- a/files/file.c +++ b/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; diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index f4a9fc5b5fc..1c99f758bf8 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -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 */ diff --git a/programs/wineconsole/wineconsole.c b/programs/wineconsole/wineconsole.c index 7d8c6bae28e..e549d5ccb06 100644 --- a/programs/wineconsole/wineconsole.c +++ b/programs/wineconsole/wineconsole.c @@ -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; diff --git a/scheduler/handle.c b/scheduler/handle.c index c78c5f43338..b3f2ed0f85b 100644 --- a/scheduler/handle.c +++ b/scheduler/handle.c @@ -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; } diff --git a/scheduler/process.c b/scheduler/process.c index e559457380f..e32a7b1bb15 100644 --- a/scheduler/process.c +++ b/scheduler/process.c @@ -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 diff --git a/scheduler/synchro.c b/scheduler/synchro.c index 22bed1b51fe..fd20d8861bf 100644 --- a/scheduler/synchro.c +++ b/scheduler/synchro.c @@ -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? */ diff --git a/server/console.c b/server/console.c index 2cd08ff36bb..a0687c8bac2 100644 --- a/server/console.c +++ b/server/console.c @@ -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 ); +} diff --git a/server/console.h b/server/console.h index c3b4aae50c6..95bae25fbe4 100644 --- a/server/console.h +++ b/server/console.h @@ -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 */ diff --git a/server/fd.c b/server/fd.c index 072d3496637..b35ad6f747a 100644 --- a/server/fd.c +++ b/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 */ diff --git a/server/process.c b/server/process.c index 0617bb50b31..3e6e9473fd0 100644 --- a/server/process.c +++ b/server/process.c @@ -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; diff --git a/server/protocol.def b/server/protocol.def index 51e3bc9c5a4..c117b413b88 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -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 */ diff --git a/server/request.h b/server/request.h index 3157bf09441..60d943972c4 100644 --- a/server/request.h +++ b/server/request.h @@ -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, diff --git a/server/trace.c b/server/trace.c index 0d43904435c..ae215d0c560 100644 --- a/server/trace.c +++ b/server/trace.c @@ -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",