From c34686cca0b303fce02c16fad45071a85de834a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Sun, 23 Jun 2013 00:18:47 +0000 Subject: [PATCH] [CONSRV] Start to separate better the CSR console server layer from the pure set of console functions (which will constitute a future console driver called... condrv :) ), and rework the terminal frontends interface. Now load the frontends by order : - the tui if we're in console mode - the gui, otherwise. (It's a temporary solution) More modifications to come ! svn path=/trunk/; revision=59297 --- reactos/win32ss/user/consrv/CMakeLists.txt | 5 +- reactos/win32ss/user/consrv/condrv/console.c | 984 ++++++++++++ .../user/consrv/{ => condrv}/graphics.c | 0 reactos/win32ss/user/consrv/coninput.c | 196 +-- reactos/win32ss/user/consrv/coninput.h | 9 + reactos/win32ss/user/consrv/conio.h | 36 +- reactos/win32ss/user/consrv/conoutput.c | 5 + reactos/win32ss/user/consrv/conoutput.h | 3 + reactos/win32ss/user/consrv/console.c | 1401 +++-------------- reactos/win32ss/user/consrv/console.h | 36 +- reactos/win32ss/user/consrv/frontendctl.c | 379 +++++ .../user/consrv/frontends/gui/guiterm.c | 698 +++++--- reactos/win32ss/user/consrv/frontends/input.c | 146 ++ .../user/consrv/frontends/tui/tuiterm.c | 257 +-- reactos/win32ss/user/consrv/handle.c | 10 +- reactos/win32ss/user/consrv/include/conio.h | 70 +- reactos/win32ss/user/consrv/include/console.h | 25 +- reactos/win32ss/user/consrv/init.c | 4 +- 18 files changed, 2502 insertions(+), 1762 deletions(-) create mode 100644 reactos/win32ss/user/consrv/condrv/console.c rename reactos/win32ss/user/consrv/{ => condrv}/graphics.c (100%) create mode 100644 reactos/win32ss/user/consrv/frontendctl.c create mode 100644 reactos/win32ss/user/consrv/frontends/input.c diff --git a/reactos/win32ss/user/consrv/CMakeLists.txt b/reactos/win32ss/user/consrv/CMakeLists.txt index ca5fae6d87b..40432db8fef 100644 --- a/reactos/win32ss/user/consrv/CMakeLists.txt +++ b/reactos/win32ss/user/consrv/CMakeLists.txt @@ -12,13 +12,16 @@ list(APPEND SOURCE alias.c coninput.c conoutput.c - graphics.c text.c console.c + frontendctl.c handle.c init.c lineinput.c settings.c + condrv/console.c + condrv/graphics.c + frontends/input.c frontends/gui/guiterm.c frontends/gui/guisettings.c frontends/gui/graphics.c diff --git a/reactos/win32ss/user/consrv/condrv/console.c b/reactos/win32ss/user/consrv/condrv/console.c new file mode 100644 index 00000000000..80fdda8cf91 --- /dev/null +++ b/reactos/win32ss/user/consrv/condrv/console.c @@ -0,0 +1,984 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Console Server DLL + * FILE: win32ss/user/consrv/condrv/console.c + * PURPOSE: Console Management Functions + * PROGRAMMERS: Gé van Geldorp + * Jeffrey Morlan + * Hermes Belusca-Maito (hermes.belusca@sfr.fr) + */ + +/* INCLUDES *******************************************************************/ + +#include "consrv.h" +#include "include/conio.h" +#include "conio.h" +#include "handle.h" +#include "procinit.h" +#include "alias.h" +#include "coninput.h" +#include "conoutput.h" +#include "lineinput.h" +#include "include/settings.h" + +#include "include/console.h" +#include "console.h" +#include "resource.h" + +#define NDEBUG +#include + +// FIXME: Add this prototype to winternl.h / rtlfuncs.h / ... +NTSTATUS NTAPI RtlGetLastNtStatus(VOID); + + +/* GLOBALS ********************************************************************/ + +static LIST_ENTRY ConsoleList; /* The list of all the allocated consoles */ +static RTL_RESOURCE ListLock; + +#define ConDrvLockConsoleListExclusive() \ + RtlAcquireResourceExclusive(&ListLock, TRUE) + +#define ConDrvLockConsoleListShared() \ + RtlAcquireResourceShared(&ListLock, TRUE) + +#define ConDrvUnlockConsoleList() \ + RtlReleaseResource(&ListLock) + +// Adapted from reactos/lib/rtl/unicode.c, RtlCreateUnicodeString line 2180 +BOOLEAN +ConsoleCreateUnicodeString(IN OUT PUNICODE_STRING UniDest, + IN PCWSTR Source) +{ + SIZE_T Size = (wcslen(Source) + 1) * sizeof(WCHAR); + if (Size > MAXUSHORT) return FALSE; + + UniDest->Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size); + if (UniDest->Buffer == NULL) return FALSE; + + RtlCopyMemory(UniDest->Buffer, Source, Size); + UniDest->MaximumLength = (USHORT)Size; + UniDest->Length = (USHORT)Size - sizeof(WCHAR); + + return TRUE; +} + +// Adapted from reactos/lib/rtl/unicode.c, RtlFreeUnicodeString line 431 +VOID +ConsoleFreeUnicodeString(IN PUNICODE_STRING UnicodeString) +{ + if (UnicodeString->Buffer) + { + ConsoleFreeHeap(UnicodeString->Buffer); + RtlZeroMemory(UnicodeString, sizeof(UNICODE_STRING)); + } +} + + +/* PRIVATE FUNCTIONS **********************************************************/ + +static NTSTATUS +ConDrvConsoleCtrlEventTimeout(IN ULONG Event, + IN PCONSOLE_PROCESS_DATA ProcessData, + IN ULONG Timeout) +{ + NTSTATUS Status = STATUS_SUCCESS; + + DPRINT("ConDrvConsoleCtrlEventTimeout Parent ProcessId = %x\n", ProcessData->Process->ClientId.UniqueProcess); + + if (ProcessData->CtrlDispatcher) + { + _SEH2_TRY + { + HANDLE Thread = NULL; + + _SEH2_TRY + { + Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0, + ProcessData->CtrlDispatcher, + UlongToPtr(Event), 0, NULL); + if (NULL == Thread) + { + Status = RtlGetLastNtStatus(); + DPRINT1("Failed thread creation, Status = 0x%08lx\n", Status); + } + else + { + DPRINT("ProcessData->CtrlDispatcher remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n", ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process); + WaitForSingleObject(Thread, Timeout); + } + } + _SEH2_FINALLY + { + CloseHandle(Thread); + } + _SEH2_END; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + Status = _SEH2_GetExceptionCode(); + DPRINT1("ConDrvConsoleCtrlEventTimeout - Caught an exception, Status = 0x%08lx\n", Status); + } + _SEH2_END; + } + + return Status; +} + +static NTSTATUS +ConDrvConsoleCtrlEvent(IN ULONG Event, + IN PCONSOLE_PROCESS_DATA ProcessData) +{ + return ConDrvConsoleCtrlEventTimeout(Event, ProcessData, 0); +} + +VOID FASTCALL +ConioPause(PCONSOLE Console, UINT Flags) +{ + Console->PauseFlags |= Flags; + if (!Console->UnpauseEvent) + Console->UnpauseEvent = CreateEvent(NULL, TRUE, FALSE, NULL); +} + +VOID FASTCALL +ConioUnpause(PCONSOLE Console, UINT Flags) +{ + Console->PauseFlags &= ~Flags; + + // if ((Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION)) == 0) + if (Console->PauseFlags == 0 && Console->UnpauseEvent) + { + SetEvent(Console->UnpauseEvent); + CloseHandle(Console->UnpauseEvent); + Console->UnpauseEvent = NULL; + + CsrNotifyWait(&Console->WriteWaitQueue, + WaitAll, + NULL, + NULL); + if (!IsListEmpty(&Console->WriteWaitQueue)) + { + CsrDereferenceWait(&Console->WriteWaitQueue); + } + } +} + + +/* + * Console accessibility check helpers + */ + +BOOLEAN NTAPI +ConDrvValidateConsolePointer(IN PCONSOLE Console) +{ + PLIST_ENTRY ConsoleEntry; + PCONSOLE CurrentConsole = NULL; + + if (!Console) return FALSE; + + /* The console list must be locked */ + // ASSERT(Console_list_locked); + + ConsoleEntry = ConsoleList.Flink; + while (ConsoleEntry != &ConsoleList) + { + CurrentConsole = CONTAINING_RECORD(ConsoleEntry, CONSOLE, Entry); + ConsoleEntry = ConsoleEntry->Flink; + if (CurrentConsole == Console) return TRUE; + } + + return FALSE; +} + +BOOLEAN NTAPI +ConDrvValidateConsoleState(IN PCONSOLE Console, + IN CONSOLE_STATE ExpectedState) +{ + // if (!Console) return FALSE; + + /* The console must be locked */ + // ASSERT(Console_locked); + + return (Console->State == ExpectedState); +} + +BOOLEAN NTAPI +ConDrvValidateConsoleUnsafe(IN PCONSOLE Console, + IN CONSOLE_STATE ExpectedState, + IN BOOLEAN LockConsole) +{ + if (!Console) return FALSE; + + /* + * Lock the console to forbid possible console's state changes + * (which must be done when the console is already locked). + * If we don't want to lock it, it's because the lock is already + * held. So there must be no problems. + */ + if (LockConsole) EnterCriticalSection(&Console->Lock); + + // ASSERT(Console_locked); + + /* Check whether the console's state is what we expect */ + if (!ConDrvValidateConsoleState(Console, ExpectedState)) + { + if (LockConsole) LeaveCriticalSection(&Console->Lock); + return FALSE; + } + + return TRUE; +} + +BOOLEAN NTAPI +ConDrvValidateConsole(IN PCONSOLE Console, + IN CONSOLE_STATE ExpectedState, + IN BOOLEAN LockConsole) +{ + BOOLEAN RetVal = FALSE; + + if (!Console) return FALSE; + + /* + * Forbid creation or deletion of consoles when + * checking for the existence of a console. + */ + ConDrvLockConsoleListShared(); + + if (ConDrvValidateConsolePointer(Console)) + { + RetVal = ConDrvValidateConsoleUnsafe(Console, + ExpectedState, + LockConsole); + } + + /* Unlock the console list and return */ + ConDrvUnlockConsoleList(); + return RetVal; +} + +NTSTATUS NTAPI +ConDrvGrabConsole(IN PCONSOLE Console, + IN BOOLEAN LockConsole) +{ + NTSTATUS Status = STATUS_INVALID_HANDLE; + + if (ConDrvValidateConsole(Console, CONSOLE_RUNNING, LockConsole)) + { + InterlockedIncrement(&Console->ReferenceCount); + Status = STATUS_SUCCESS; + } + + return Status; +} + +VOID NTAPI +ConDrvReleaseConsole(IN PCONSOLE Console, + IN BOOLEAN WasConsoleLocked) +{ + LONG RefCount = 0; + + if (!Console) return; + // if (Console->ReferenceCount == 0) return; // This shouldn't happen + ASSERT(Console->ReferenceCount > 0); + + /* The console must be locked */ + // ASSERT(Console_locked); + + /* + * Decrement the reference count. Save the new value too, + * because Console->ReferenceCount might be modified after + * the console gets unlocked but before we check whether we + * can destroy it. + */ + RefCount = _InterlockedDecrement(&Console->ReferenceCount); + + /* Unlock the console if needed */ + if (WasConsoleLocked) LeaveCriticalSection(&Console->Lock); + + /* Delete the console if needed */ + if (RefCount <= 0) ConDrvDeleteConsole(Console); +} + + +/* CONSOLE INITIALIZATION FUNCTIONS *******************************************/ + +VOID NTAPI +ConDrvInitConsoleSupport(VOID) +{ + DPRINT("CONSRV: ConDrvInitConsoleSupport()\n"); + + /* Initialize the console list and its lock */ + InitializeListHead(&ConsoleList); + RtlInitializeResource(&ListLock); + + /* Should call LoadKeyboardLayout */ +} + + +NTSTATUS NTAPI +ConDrvInitConsole(OUT PCONSOLE* NewConsole, + IN PCONSOLE_INFO ConsoleInfo, + IN ULONG ConsoleLeaderProcessId) +{ + NTSTATUS Status; + SECURITY_ATTRIBUTES SecurityAttributes; + // CONSOLE_INFO CapturedConsoleInfo; + TEXTMODE_BUFFER_INFO ScreenBufferInfo; + PCONSOLE Console; + PCONSOLE_SCREEN_BUFFER NewBuffer; + // WCHAR DefaultTitle[128]; + + if (NewConsole == NULL || ConsoleInfo == NULL) + return STATUS_INVALID_PARAMETER; + + *NewConsole = NULL; + + /* + * Allocate a console structure + */ + Console = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(CONSOLE)); + if (NULL == Console) + { + DPRINT1("Not enough memory for console creation.\n"); + return STATUS_NO_MEMORY; + } + + /* + * Load the console settings + */ + + /* 1. Load the default settings */ + // ConSrvGetDefaultSettings(ConsoleInfo, ProcessId); + + // /* 2. Get the title of the console (initialize ConsoleInfo.ConsoleTitle) */ + // Length = min(wcslen(ConsoleStartInfo->ConsoleTitle), + // sizeof(ConsoleInfo.ConsoleTitle) / sizeof(ConsoleInfo.ConsoleTitle[0]) - 1); + // wcsncpy(ConsoleInfo.ConsoleTitle, ConsoleStartInfo->ConsoleTitle, Length); + // ConsoleInfo.ConsoleTitle[Length] = L'\0'; + + /* + * 4. Load the remaining console settings via the registry. + */ +#if 0 + if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0) + { + /* + * Either we weren't created by an app launched via a shell-link, + * or we failed to load shell-link console properties. + * Therefore, load the console infos for the application from the registry. + */ + ConSrvReadUserSettings(ConsoleInfo, ProcessId); + + /* + * Now, update them with the properties the user might gave to us + * via the STARTUPINFO structure before calling CreateProcess + * (and which was transmitted via the ConsoleStartInfo structure). + * We therefore overwrite the values read in the registry. + */ + if (ConsoleStartInfo->dwStartupFlags & STARTF_USEFILLATTRIBUTE) + { + ConsoleInfo->ScreenAttrib = (USHORT)ConsoleStartInfo->FillAttribute; + } + if (ConsoleStartInfo->dwStartupFlags & STARTF_USECOUNTCHARS) + { + ConsoleInfo->ScreenBufferSize = ConsoleStartInfo->ScreenBufferSize; + } + if (ConsoleStartInfo->dwStartupFlags & STARTF_USESIZE) + { + // ConsoleInfo->ConsoleSize = ConsoleStartInfo->ConsoleWindowSize; + ConsoleInfo->ConsoleSize.X = (SHORT)ConsoleStartInfo->ConsoleWindowSize.cx; + ConsoleInfo->ConsoleSize.Y = (SHORT)ConsoleStartInfo->ConsoleWindowSize.cy; + } + } +#endif + + /* + * Fix the screen buffer size if needed. The rule is: + * ScreenBufferSize >= ConsoleSize + */ + if (ConsoleInfo->ScreenBufferSize.X < ConsoleInfo->ConsoleSize.X) + ConsoleInfo->ScreenBufferSize.X = ConsoleInfo->ConsoleSize.X; + if (ConsoleInfo->ScreenBufferSize.Y < ConsoleInfo->ConsoleSize.Y) + ConsoleInfo->ScreenBufferSize.Y = ConsoleInfo->ConsoleSize.Y; + + /* + * Initialize the console + */ + Console->State = CONSOLE_INITIALIZING; + Console->ReferenceCount = 0; + InitializeCriticalSection(&Console->Lock); + InitializeListHead(&Console->ProcessList); + RtlZeroMemory(&Console->TermIFace, sizeof(Console->TermIFace)); + + memcpy(Console->Colors, ConsoleInfo->Colors, sizeof(ConsoleInfo->Colors)); + Console->ConsoleSize = ConsoleInfo->ConsoleSize; + Console->FixedSize = FALSE; // Value by default; is reseted by the front-ends if needed. + + /* + * Initialize the input buffer + */ + ConSrvInitObject(&Console->InputBuffer.Header, INPUT_BUFFER, Console); + + SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); + SecurityAttributes.lpSecurityDescriptor = NULL; + SecurityAttributes.bInheritHandle = TRUE; + Console->InputBuffer.ActiveEvent = CreateEventW(&SecurityAttributes, TRUE, FALSE, NULL); + if (NULL == Console->InputBuffer.ActiveEvent) + { + DeleteCriticalSection(&Console->Lock); + ConsoleFreeHeap(Console); + return STATUS_UNSUCCESSFUL; + } + + Console->InputBuffer.InputBufferSize = 0; // FIXME! + InitializeListHead(&Console->InputBuffer.InputEvents); + InitializeListHead(&Console->InputBuffer.ReadWaitQueue); + Console->InputBuffer.Mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | + ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT; + + Console->QuickEdit = ConsoleInfo->QuickEdit; + Console->InsertMode = ConsoleInfo->InsertMode; + Console->LineBuffer = NULL; + Console->LineMaxSize = Console->LineSize = Console->LinePos = 0; + Console->LineComplete = Console->LineUpPressed = Console->LineInsertToggle = FALSE; + // LineWakeupMask + + // FIXME: This is terminal-specific !! VV + RtlZeroMemory(&Console->Selection, sizeof(CONSOLE_SELECTION_INFO)); + Console->Selection.dwFlags = CONSOLE_NO_SELECTION; + // dwSelectionCursor + + /* Set-up the code page */ + Console->CodePage = Console->OutputCodePage = ConsoleInfo->CodePage; + + /* Initialize a new text-mode screen buffer with default settings */ + ScreenBufferInfo.ScreenBufferSize = ConsoleInfo->ScreenBufferSize; + ScreenBufferInfo.ScreenAttrib = ConsoleInfo->ScreenAttrib; + ScreenBufferInfo.PopupAttrib = ConsoleInfo->PopupAttrib; + ScreenBufferInfo.IsCursorVisible = TRUE; + ScreenBufferInfo.CursorSize = ConsoleInfo->CursorSize; + + InitializeListHead(&Console->BufferList); + Status = ConSrvCreateScreenBuffer(&NewBuffer, + Console, + CONSOLE_TEXTMODE_BUFFER, + &ScreenBufferInfo); + if (!NT_SUCCESS(Status)) + { + DPRINT1("ConSrvCreateScreenBuffer: failed, Status = 0x%08lx\n", Status); + CloseHandle(Console->InputBuffer.ActiveEvent); + DeleteCriticalSection(&Console->Lock); + ConsoleFreeHeap(Console); + return Status; + } + /* Make the new screen buffer active */ + Console->ActiveBuffer = NewBuffer; + InitializeListHead(&Console->WriteWaitQueue); + Console->PauseFlags = 0; + Console->UnpauseEvent = NULL; + + /* + * Initialize the alias and history buffers + */ + Console->Aliases = NULL; + InitializeListHead(&Console->HistoryBuffers); + Console->HistoryBufferSize = ConsoleInfo->HistoryBufferSize; + Console->NumberOfHistoryBuffers = ConsoleInfo->NumberOfHistoryBuffers; + Console->HistoryNoDup = ConsoleInfo->HistoryNoDup; + + /* Initialize the console title */ + ConsoleCreateUnicodeString(&Console->OriginalTitle, ConsoleInfo->ConsoleTitle); + // if (ConsoleInfo.ConsoleTitle[0] == L'\0') + // { + // if (LoadStringW(ConSrvDllInstance, IDS_CONSOLE_TITLE, DefaultTitle, sizeof(DefaultTitle) / sizeof(DefaultTitle[0]))) + // { + // ConsoleCreateUnicodeString(&Console->Title, DefaultTitle); + // } + // else + // { + // ConsoleCreateUnicodeString(&Console->Title, L"ReactOS Console"); + // } + // } + // else + // { + ConsoleCreateUnicodeString(&Console->Title, ConsoleInfo->ConsoleTitle); + // } + + /* Lock the console until its initialization is finished */ + // EnterCriticalSection(&Console->Lock); + + DPRINT("Console initialized\n"); + + /* All went right, so add the console to the list */ + ConDrvLockConsoleListExclusive(); + DPRINT("Insert in the list\n"); + InsertTailList(&ConsoleList, &Console->Entry); + + /* The initialization is finished */ + DPRINT("Change state\n"); + Console->State = CONSOLE_RUNNING; + + /* Unlock the console */ + // LeaveCriticalSection(&Console->Lock); + + /* Unlock the console list */ + ConDrvUnlockConsoleList(); + + /* Return the newly created console to the caller and a success code too */ + *NewConsole = Console; + return STATUS_SUCCESS; +} + +NTSTATUS NTAPI +ConDrvRegisterFrontEnd(IN PCONSOLE Console, + IN PFRONTEND FrontEnd) +{ + NTSTATUS Status; + + if (Console == NULL || FrontEnd == NULL) + return STATUS_INVALID_PARAMETER; + + /* FIXME: Lock the console before ?? */ + + /* + * Attach the frontend to the console. Use now the TermIFace of the console, + * and not the user-defined temporary FrontEnd pointer. + */ + Console->TermIFace = *FrontEnd; + Console->TermIFace.Console = Console; + + /* Initialize the frontend AFTER having attached it to the console */ + DPRINT("Finish initialization of frontend\n"); + Status = Console->TermIFace.Vtbl->InitFrontEnd(&Console->TermIFace, Console); + if (!NT_SUCCESS(Status)) + { + DPRINT1("FrontEnd initialization failed, Status = 0x%08lx\n", Status); + + /* We failed, detach the frontend from the console */ + FrontEnd->Console = NULL; // For the caller + RtlZeroMemory(&Console->TermIFace, sizeof(Console->TermIFace)); + + return Status; + } + + /* Copy buffer contents to screen */ + // FrontEnd.Draw(); + // ConioDrawConsole(Console); + DPRINT("Console drawn\n"); + + DPRINT("Terminal FrontEnd initialization done\n"); + return STATUS_SUCCESS; +} + +NTSTATUS NTAPI +ConDrvDeregisterFrontEnd(IN PCONSOLE Console) +{ + if (Console == NULL) return STATUS_INVALID_PARAMETER; + + /* FIXME: Lock the console before ?? */ + + /* Deinitialize the frontend BEFORE detaching it from the console */ + Console->TermIFace.Vtbl->DeinitFrontEnd(&Console->TermIFace/*, Console*/); + + /* Detach the frontend from the console */ + RtlZeroMemory(&Console->TermIFace, sizeof(Console->TermIFace)); + + DPRINT("Terminal FrontEnd unregistered\n"); + return STATUS_SUCCESS; +} + +VOID NTAPI +ConDrvDeleteConsole(IN PCONSOLE Console) +{ + DPRINT("ConDrvDeleteConsole(0x%p)\n", Console); + + /* + * Forbid validation of any console by other threads + * during the deletion of this console. + */ + ConDrvLockConsoleListExclusive(); + + /* Check the existence of the console, and if it's ok, continue */ + if (!ConDrvValidateConsolePointer(Console)) + { + /* Unlock the console list and return */ + ConDrvUnlockConsoleList(); + return; + } + + /* + * If the console is already being destroyed + * (thus not running), just return. + */ + if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) + { + /* Unlock the console list and return */ + ConDrvUnlockConsoleList(); + return; + } + + /* + * We are about to be destroyed. Signal it to other people + * so that they can terminate what they are doing, and that + * they cannot longer validate the console. + */ + Console->State = CONSOLE_TERMINATING; + + /* + * Allow other threads to finish their job: basically, unlock + * all other calls to EnterCriticalSection(&Console->Lock); by + * ConDrvValidateConsole(Unsafe) functions so that they just see + * that we are not in CONSOLE_RUNNING state anymore, or unlock + * other concurrent calls to ConDrvDeleteConsole so that they + * can see that we are in fact already deleting the console. + */ + LeaveCriticalSection(&Console->Lock); + ConDrvUnlockConsoleList(); + + /* FIXME: Send a terminate message to all the processes owning this console */ + + /* Cleanup the UI-oriented part */ + DPRINT("Deregister console\n"); + ConDrvDeregisterFrontEnd(Console); + DPRINT("Console deregistered\n"); + + /*** + * Check that the console is in terminating state before continuing + * (the cleanup code must not change the state of the console... + * ...unless to cancel console deletion ?). + ***/ + + ConDrvLockConsoleListExclusive(); + + /* Re-check the existence of the console, and if it's ok, continue */ + if (!ConDrvValidateConsolePointer(Console)) + { + /* Unlock the console list and return */ + ConDrvUnlockConsoleList(); + return; + } + + if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_TERMINATING, TRUE)) + { + ConDrvUnlockConsoleList(); + return; + } + + /* We are now in destruction */ + Console->State = CONSOLE_IN_DESTRUCTION; + + /* Remove the console from the list */ + RemoveEntryList(&Console->Entry); + + /* We really delete the console. Reset the count to be sure. */ + Console->ReferenceCount = 0; + + /* Discard all entries in the input event queue */ + PurgeInputBuffer(Console); + + if (Console->LineBuffer) ConsoleFreeHeap(Console->LineBuffer); + + IntDeleteAllAliases(Console); + HistoryDeleteBuffers(Console); + + ConioDeleteScreenBuffer(Console->ActiveBuffer); + if (!IsListEmpty(&Console->BufferList)) + { + DPRINT1("BUG: screen buffer list not empty\n"); + ASSERT(FALSE); + } + + /**/ CloseHandle(Console->InputBuffer.ActiveEvent); /**/ + if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent); + + ConsoleFreeUnicodeString(&Console->OriginalTitle); + ConsoleFreeUnicodeString(&Console->Title); + + DPRINT("ConDrvDeleteConsole - Unlocking\n"); + LeaveCriticalSection(&Console->Lock); + DPRINT("ConDrvDeleteConsole - Destroying lock\n"); + DeleteCriticalSection(&Console->Lock); + DPRINT("ConDrvDeleteConsole - Lock destroyed ; freeing console\n"); + + ConsoleFreeHeap(Console); + DPRINT("ConDrvDeleteConsole - Console destroyed\n"); + + /* Unlock the console list and return */ + ConDrvUnlockConsoleList(); +} + + +/* PUBLIC SERVER APIS *********************************************************/ + +NTSTATUS NTAPI +ConDrvGetConsoleMode(IN PCONSOLE Console, + IN PCONSOLE_IO_OBJECT Object, + OUT PULONG ConsoleMode) +{ + NTSTATUS Status = STATUS_SUCCESS; + + if (Console == NULL || Object == NULL || ConsoleMode == NULL) + return STATUS_INVALID_PARAMETER; + + /* Validity check */ + ASSERT(Console == Object->Console); + + /*** FIXME: */ *ConsoleMode = 0; /***/ + + if (INPUT_BUFFER == Object->Type) + { + PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object; + + *ConsoleMode = InputBuffer->Mode; + + if (Console->QuickEdit || Console->InsertMode) + { + // Windows does this, even if it's not documented on MSDN + *ConsoleMode |= ENABLE_EXTENDED_FLAGS; + + if (Console->QuickEdit ) *ConsoleMode |= ENABLE_QUICK_EDIT_MODE; + if (Console->InsertMode) *ConsoleMode |= ENABLE_INSERT_MODE; + } + } + else if (TEXTMODE_BUFFER == Object->Type || GRAPHICS_BUFFER == Object->Type) + { + PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object; + *ConsoleMode = Buffer->Mode; + } + else + { + Status = STATUS_INVALID_HANDLE; + } + + return Status; +} + +NTSTATUS NTAPI +ConDrvSetConsoleMode(IN PCONSOLE Console, + IN PCONSOLE_IO_OBJECT Object, + IN ULONG ConsoleMode) +{ +#define CONSOLE_VALID_CONTROL_MODES ( ENABLE_EXTENDED_FLAGS | ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE ) +#define CONSOLE_VALID_INPUT_MODES ( ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | \ + ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT | \ + ENABLE_MOUSE_INPUT ) +#define CONSOLE_VALID_OUTPUT_MODES ( ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT ) + + NTSTATUS Status = STATUS_SUCCESS; + + if (Console == NULL || Object == NULL) + return STATUS_INVALID_PARAMETER; + + /* Validity check */ + ASSERT(Console == Object->Console); + + if (INPUT_BUFFER == Object->Type) + { + PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object; + + DPRINT("SetConsoleMode(Input, %d)\n", ConsoleMode); + + /* + * 1. Only the presence of valid mode flags is allowed. + */ + if (ConsoleMode & ~(CONSOLE_VALID_INPUT_MODES | CONSOLE_VALID_CONTROL_MODES)) + { + Status = STATUS_INVALID_PARAMETER; + goto Quit; + } + + /* + * 2. If we use control mode flags without ENABLE_EXTENDED_FLAGS, + * then consider the flags invalid. + * + if ( (ConsoleMode & CONSOLE_VALID_CONTROL_MODES) && + (ConsoleMode & ENABLE_EXTENDED_FLAGS) == 0 ) + { + Status = STATUS_INVALID_PARAMETER; + goto Quit; + } + */ + + /* + * 3. Now we can continue. + */ + if (ConsoleMode & CONSOLE_VALID_CONTROL_MODES) + { + Console->QuickEdit = !!(ConsoleMode & ENABLE_QUICK_EDIT_MODE); + Console->InsertMode = !!(ConsoleMode & ENABLE_INSERT_MODE); + } + InputBuffer->Mode = (ConsoleMode & CONSOLE_VALID_INPUT_MODES); + } + else if (TEXTMODE_BUFFER == Object->Type || GRAPHICS_BUFFER == Object->Type) + { + PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object; + + DPRINT("SetConsoleMode(Output, %d)\n", ConsoleMode); + + if (ConsoleMode & ~CONSOLE_VALID_OUTPUT_MODES) + { + Status = STATUS_INVALID_PARAMETER; + } + else + { + Buffer->Mode = (ConsoleMode & CONSOLE_VALID_OUTPUT_MODES); + } + } + else + { + Status = STATUS_INVALID_HANDLE; + } + +Quit: + return Status; +} + +NTSTATUS NTAPI +ConDrvGetConsoleTitle(IN PCONSOLE Console, + IN OUT PWCHAR Title, + IN OUT PULONG BufLength) +{ + ULONG Length; + + if (Console == NULL || Title == NULL || BufLength == NULL) + return STATUS_INVALID_PARAMETER; + + /* Copy title of the console to the user title buffer */ + if (*BufLength >= sizeof(WCHAR)) + { + Length = min(*BufLength - sizeof(WCHAR), Console->Title.Length); + RtlCopyMemory(Title, Console->Title.Buffer, Length); + Title[Length / sizeof(WCHAR)] = L'\0'; + } + + *BufLength = Console->Title.Length; + + return STATUS_SUCCESS; +} + +NTSTATUS NTAPI +ConDrvSetConsoleTitle(IN PCONSOLE Console, + IN PWCHAR Title, + IN ULONG BufLength) +{ + PWCHAR Buffer; + + if (Console == NULL || Title == NULL) + return STATUS_INVALID_PARAMETER; + + /* Allocate a new buffer to hold the new title (NULL-terminated) */ + Buffer = ConsoleAllocHeap(0, BufLength + sizeof(WCHAR)); + if (!Buffer) return STATUS_NO_MEMORY; + + /* Free the old title */ + ConsoleFreeUnicodeString(&Console->Title); + + /* Copy title to console */ + Console->Title.Buffer = Buffer; + Console->Title.Length = BufLength; + Console->Title.MaximumLength = Console->Title.Length + sizeof(WCHAR); + RtlCopyMemory(Console->Title.Buffer, Title, Console->Title.Length); + Console->Title.Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0'; + + // ConioChangeTitle(Console); + return STATUS_SUCCESS; +} + +NTSTATUS NTAPI +ConDrvGetConsoleCP(IN PCONSOLE Console, + OUT PUINT CodePage, + IN BOOLEAN InputCP) +{ + if (Console == NULL || CodePage == NULL) + return STATUS_INVALID_PARAMETER; + + *CodePage = (InputCP ? Console->CodePage : Console->OutputCodePage); + + return STATUS_SUCCESS; +} + +NTSTATUS NTAPI +ConDrvSetConsoleCP(IN PCONSOLE Console, + IN UINT CodePage, + IN BOOLEAN InputCP) +{ + if (Console == NULL || !IsValidCodePage(CodePage)) + return STATUS_INVALID_PARAMETER; + + if (InputCP) + Console->CodePage = CodePage; + else + Console->OutputCodePage = CodePage; + + return STATUS_SUCCESS; +} + +NTSTATUS NTAPI +ConDrvGetConsoleProcessList(IN PCONSOLE Console, + IN OUT PULONG ProcessIdsList, + IN ULONG MaxIdListItems, + OUT PULONG ProcessIdsTotal) +{ + PCONSOLE_PROCESS_DATA current; + PLIST_ENTRY current_entry; + + if (Console == NULL || ProcessIdsList == NULL || ProcessIdsTotal == NULL) + return STATUS_INVALID_PARAMETER; + + *ProcessIdsTotal = 0; + + for (current_entry = Console->ProcessList.Flink; + current_entry != &Console->ProcessList; + current_entry = current_entry->Flink) + { + current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink); + if (++(*ProcessIdsTotal) <= MaxIdListItems) + { + *ProcessIdsList++ = HandleToUlong(current->Process->ClientId.UniqueProcess); + } + } + + return STATUS_SUCCESS; +} + +// ConDrvGenerateConsoleCtrlEvent +NTSTATUS NTAPI +ConDrvConsoleProcessCtrlEvent(IN PCONSOLE Console, + IN ULONG ProcessGroupId, + IN ULONG Event) +{ + NTSTATUS Status = STATUS_SUCCESS; + PLIST_ENTRY current_entry; + PCONSOLE_PROCESS_DATA current; + + /* If the console is already being destroyed, just return */ + if (!ConDrvValidateConsole(Console, CONSOLE_RUNNING, FALSE)) + return STATUS_UNSUCCESSFUL; + + /* + * Loop through the process list, from the most recent process + * (the active one) to the oldest one (the first created, i.e. + * the console leader process), and for each, send an event + * (new processes are inserted at the head of the console process list). + */ + current_entry = Console->ProcessList.Flink; + while (current_entry != &Console->ProcessList) + { + current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink); + current_entry = current_entry->Flink; + + /* + * Only processes belonging to the same process group are signaled. + * If the process group ID is zero, then all the processes are signaled. + */ + if (ProcessGroupId == 0 || current->Process->ProcessGroupId == ProcessGroupId) + { + Status = ConDrvConsoleCtrlEvent(Event, current); + } + } + + return Status; +} + +/* EOF */ diff --git a/reactos/win32ss/user/consrv/graphics.c b/reactos/win32ss/user/consrv/condrv/graphics.c similarity index 100% rename from reactos/win32ss/user/consrv/graphics.c rename to reactos/win32ss/user/consrv/condrv/graphics.c diff --git a/reactos/win32ss/user/consrv/coninput.c b/reactos/win32ss/user/consrv/coninput.c index fbf552314e1..e1f7b7ea949 100644 --- a/reactos/win32ss/user/consrv/coninput.c +++ b/reactos/win32ss/user/consrv/coninput.c @@ -135,137 +135,24 @@ PurgeInputBuffer(PCONSOLE Console) CloseHandle(Console->InputBuffer.ActiveEvent); } -static DWORD FASTCALL -ConioGetShiftState(PBYTE KeyState, LPARAM lParam) +VOID NTAPI +ConDrvProcessKey(IN PCONSOLE Console, + IN BOOLEAN Down, + IN UINT VirtualKeyCode, + IN UINT VirtualScanCode, + IN WCHAR UnicodeChar, + IN ULONG ShiftState, + IN BYTE KeyStateCtrl) { - DWORD ssOut = 0; - - if (KeyState[VK_CAPITAL] & 0x01) - ssOut |= CAPSLOCK_ON; - - if (KeyState[VK_NUMLOCK] & 0x01) - ssOut |= NUMLOCK_ON; - - if (KeyState[VK_SCROLL] & 0x01) - ssOut |= SCROLLLOCK_ON; - - if (KeyState[VK_SHIFT] & 0x80) - ssOut |= SHIFT_PRESSED; - - if (KeyState[VK_LCONTROL] & 0x80) - ssOut |= LEFT_CTRL_PRESSED; - if (KeyState[VK_RCONTROL] & 0x80) - ssOut |= RIGHT_CTRL_PRESSED; - - if (KeyState[VK_LMENU] & 0x80) - ssOut |= LEFT_ALT_PRESSED; - if (KeyState[VK_RMENU] & 0x80) - ssOut |= RIGHT_ALT_PRESSED; - - /* See WM_CHAR MSDN documentation for instance */ - if (lParam & 0x01000000) - ssOut |= ENHANCED_KEY; - - return ssOut; -} - -VOID WINAPI -ConioProcessKey(PCONSOLE Console, MSG* msg) -{ - static BYTE KeyState[256] = { 0 }; - /* MSDN mentions that you should use the last virtual key code received - * when putting a virtual key identity to a WM_CHAR message since multiple - * or translated keys may be involved. */ - static UINT LastVirtualKey = 0; - DWORD ShiftState; - WCHAR UnicodeChar; - UINT VirtualKeyCode; - UINT VirtualScanCode; - BOOL Down = FALSE; INPUT_RECORD er; - BOOLEAN Fake; // synthesized, not a real event - BOOLEAN NotChar; // message should not be used to return a character - - if (NULL == Console) - { - DPRINT1("No Active Console!\n"); - return; - } - - VirtualScanCode = HIWORD(msg->lParam) & 0xFF; - Down = msg->message == WM_KEYDOWN || msg->message == WM_CHAR || - msg->message == WM_SYSKEYDOWN || msg->message == WM_SYSCHAR; - - GetKeyboardState(KeyState); - ShiftState = ConioGetShiftState(KeyState, msg->lParam); - - if (msg->message == WM_CHAR || msg->message == WM_SYSCHAR) - { - VirtualKeyCode = LastVirtualKey; - UnicodeChar = msg->wParam; - } - else - { - WCHAR Chars[2]; - INT RetChars = 0; - - VirtualKeyCode = msg->wParam; - RetChars = ToUnicodeEx(VirtualKeyCode, - VirtualScanCode, - KeyState, - Chars, - 2, - 0, - NULL); - UnicodeChar = (1 == RetChars ? Chars[0] : 0); - } - - er.EventType = KEY_EVENT; - er.Event.KeyEvent.bKeyDown = Down; - er.Event.KeyEvent.wRepeatCount = 1; - er.Event.KeyEvent.wVirtualKeyCode = VirtualKeyCode; - er.Event.KeyEvent.wVirtualScanCode = VirtualScanCode; - er.Event.KeyEvent.uChar.UnicodeChar = UnicodeChar; - er.Event.KeyEvent.dwControlKeyState = ShiftState; - - if (ConioProcessKeyCallback(Console, - msg, - KeyState[VK_MENU], - ShiftState, - VirtualKeyCode, - Down)) - { - return; - } - - Fake = UnicodeChar && - (msg->message != WM_CHAR && msg->message != WM_SYSCHAR && - msg->message != WM_KEYUP && msg->message != WM_SYSKEYUP); - NotChar = (msg->message != WM_CHAR && msg->message != WM_SYSCHAR); - if (NotChar) LastVirtualKey = msg->wParam; - - DPRINT("CONSRV: %s %s %s %s %02x %02x '%lc' %04x\n", - Down ? "down" : "up ", - (msg->message == WM_CHAR || msg->message == WM_SYSCHAR) ? - "char" : "key ", - Fake ? "fake" : "real", - NotChar ? "notc" : "char", - VirtualScanCode, - VirtualKeyCode, - (UnicodeChar >= L' ') ? UnicodeChar : L'.', - ShiftState); - - if (Fake) return; /* process Ctrl-C and Ctrl-Break */ - if (Console->InputBuffer.Mode & ENABLE_PROCESSED_INPUT && - er.Event.KeyEvent.bKeyDown && - ((er.Event.KeyEvent.wVirtualKeyCode == VK_PAUSE) || - (er.Event.KeyEvent.wVirtualKeyCode == 'C')) && - (er.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) || KeyState[VK_CONTROL] & 0x80)) + if ( Console->InputBuffer.Mode & ENABLE_PROCESSED_INPUT && + Down && (VirtualKeyCode == VK_PAUSE || VirtualKeyCode == 'C') && + (ShiftState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) || KeyStateCtrl & 0x80) ) { DPRINT1("Console_Api Ctrl-C\n"); - ConSrvConsoleProcessCtrlEvent(Console, 0, CTRL_C_EVENT); + ConDrvConsoleProcessCtrlEvent(Console, 0, CTRL_C_EVENT); if (Console->LineBuffer && !Console->LineComplete) { @@ -276,39 +163,46 @@ ConioProcessKey(PCONSOLE Console, MSG* msg) return; } - if (0 != (er.Event.KeyEvent.dwControlKeyState - & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) - && (VK_UP == er.Event.KeyEvent.wVirtualKeyCode - || VK_DOWN == er.Event.KeyEvent.wVirtualKeyCode)) + if ( (ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) != 0 && + (VK_UP == VirtualKeyCode || VK_DOWN == VirtualKeyCode) ) { - if (er.Event.KeyEvent.bKeyDown) + if (!Down) return; + + /* scroll up or down */ + if (VK_UP == VirtualKeyCode) { - /* scroll up or down */ - if (VK_UP == er.Event.KeyEvent.wVirtualKeyCode) + /* only scroll up if there is room to scroll up into */ + if (Console->ActiveBuffer->CursorPosition.Y != Console->ActiveBuffer->ScreenBufferSize.Y - 1) { - /* only scroll up if there is room to scroll up into */ - if (Console->ActiveBuffer->CursorPosition.Y != Console->ActiveBuffer->ScreenBufferSize.Y - 1) - { - Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY + - Console->ActiveBuffer->ScreenBufferSize.Y - 1) % - Console->ActiveBuffer->ScreenBufferSize.Y; - Console->ActiveBuffer->CursorPosition.Y++; - } + Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY + + Console->ActiveBuffer->ScreenBufferSize.Y - 1) % + Console->ActiveBuffer->ScreenBufferSize.Y; + Console->ActiveBuffer->CursorPosition.Y++; } - else - { - /* only scroll down if there is room to scroll down into */ - if (Console->ActiveBuffer->CursorPosition.Y != 0) - { - Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY + 1) % - Console->ActiveBuffer->ScreenBufferSize.Y; - Console->ActiveBuffer->CursorPosition.Y--; - } - } - ConioDrawConsole(Console); } + else + { + /* only scroll down if there is room to scroll down into */ + if (Console->ActiveBuffer->CursorPosition.Y != 0) + { + Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY + 1) % + Console->ActiveBuffer->ScreenBufferSize.Y; + Console->ActiveBuffer->CursorPosition.Y--; + } + } + + ConioDrawConsole(Console); return; } + + er.EventType = KEY_EVENT; + er.Event.KeyEvent.bKeyDown = Down; + er.Event.KeyEvent.wRepeatCount = 1; + er.Event.KeyEvent.wVirtualKeyCode = VirtualKeyCode; + er.Event.KeyEvent.wVirtualScanCode = VirtualScanCode; + er.Event.KeyEvent.uChar.UnicodeChar = UnicodeChar; + er.Event.KeyEvent.dwControlKeyState = ShiftState; + ConioProcessInputEvent(Console, &er); } diff --git a/reactos/win32ss/user/consrv/coninput.h b/reactos/win32ss/user/consrv/coninput.h index 4f3efbac369..b7ac14e544d 100644 --- a/reactos/win32ss/user/consrv/coninput.h +++ b/reactos/win32ss/user/consrv/coninput.h @@ -11,4 +11,13 @@ VOID FASTCALL PurgeInputBuffer(PCONSOLE Console); +VOID NTAPI +ConDrvProcessKey(IN PCONSOLE Console, + IN BOOLEAN Down, + IN UINT VirtualKeyCode, + IN UINT VirtualScanCode, + IN WCHAR UnicodeChar, + IN ULONG ShiftState, + IN BYTE KeyStateCtrl); + /* EOF */ diff --git a/reactos/win32ss/user/consrv/conio.h b/reactos/win32ss/user/consrv/conio.h index da698a1c3ed..17281a585e4 100644 --- a/reactos/win32ss/user/consrv/conio.h +++ b/reactos/win32ss/user/consrv/conio.h @@ -10,43 +10,41 @@ /* Macros used to call functions in the FRONTEND_VTBL virtual table */ -#define ConioCleanupConsole(Console) \ - (Console)->TermIFace.Vtbl->CleanupConsole(Console) #define ConioDrawRegion(Console, Region) \ - (Console)->TermIFace.Vtbl->DrawRegion((Console), (Region)) + (Console)->TermIFace.Vtbl->DrawRegion(&(Console)->TermIFace, (Region)) #define ConioWriteStream(Console, Block, CurStartX, CurStartY, ScrolledLines, Buffer, Length) \ - (Console)->TermIFace.Vtbl->WriteStream((Console), (Block), (CurStartX), (CurStartY), \ + (Console)->TermIFace.Vtbl->WriteStream(&(Console)->TermIFace, (Block), (CurStartX), (CurStartY), \ (ScrolledLines), (Buffer), (Length)) #define ConioSetCursorInfo(Console, Buff) \ - (Console)->TermIFace.Vtbl->SetCursorInfo((Console), (Buff)) + (Console)->TermIFace.Vtbl->SetCursorInfo(&(Console)->TermIFace, (Buff)) #define ConioSetScreenInfo(Console, Buff, OldCursorX, OldCursorY) \ - (Console)->TermIFace.Vtbl->SetScreenInfo((Console), (Buff), (OldCursorX), (OldCursorY)) + (Console)->TermIFace.Vtbl->SetScreenInfo(&(Console)->TermIFace, (Buff), (OldCursorX), (OldCursorY)) #define ConioResizeTerminal(Console) \ - (Console)->TermIFace.Vtbl->ResizeTerminal(Console) + (Console)->TermIFace.Vtbl->ResizeTerminal(&(Console)->TermIFace) #define ConioProcessKeyCallback(Console, Msg, KeyStateMenu, ShiftState, VirtualKeyCode, Down) \ - (Console)->TermIFace.Vtbl->ProcessKeyCallback((Console), (Msg), (KeyStateMenu), (ShiftState), (VirtualKeyCode), (Down)) + (Console)->TermIFace.Vtbl->ProcessKeyCallback(&(Console)->TermIFace, (Msg), (KeyStateMenu), (ShiftState), (VirtualKeyCode), (Down)) #define ConioRefreshInternalInfo(Console) \ - (Console)->TermIFace.Vtbl->RefreshInternalInfo(Console) + (Console)->TermIFace.Vtbl->RefreshInternalInfo(&(Console)->TermIFace) #define ConioChangeTitle(Console) \ - (Console)->TermIFace.Vtbl->ChangeTitle(Console) + (Console)->TermIFace.Vtbl->ChangeTitle(&(Console)->TermIFace) #define ConioChangeIcon(Console, hWindowIcon) \ - (Console)->TermIFace.Vtbl->ChangeIcon((Console), (hWindowIcon)) + (Console)->TermIFace.Vtbl->ChangeIcon(&(Console)->TermIFace, (hWindowIcon)) #define ConioGetConsoleWindowHandle(Console) \ - (Console)->TermIFace.Vtbl->GetConsoleWindowHandle(Console) + (Console)->TermIFace.Vtbl->GetConsoleWindowHandle(&(Console)->TermIFace) #define ConioGetLargestConsoleWindowSize(Console, pSize) \ - (Console)->TermIFace.Vtbl->GetLargestConsoleWindowSize((Console), (pSize)) + (Console)->TermIFace.Vtbl->GetLargestConsoleWindowSize(&(Console)->TermIFace, (pSize)) #define ConioGetDisplayMode(Console) \ - (Console)->TermIFace.Vtbl->GetDisplayMode(Console) + (Console)->TermIFace.Vtbl->GetDisplayMode(&(Console)->TermIFace) #define ConioSetDisplayMode(Console, NewMode) \ - (Console)->TermIFace.Vtbl->SetDisplayMode((Console), (NewMode)) + (Console)->TermIFace.Vtbl->SetDisplayMode(&(Console)->TermIFace, (NewMode)) #define ConioShowMouseCursor(Console, Show) \ - (Console)->TermIFace.Vtbl->ShowMouseCursor((Console), (Show)) + (Console)->TermIFace.Vtbl->ShowMouseCursor(&(Console)->TermIFace, (Show)) #define ConioSetMouseCursor(Console, hCursor) \ - (Console)->TermIFace.Vtbl->SetMouseCursor((Console), (hCursor)) + (Console)->TermIFace.Vtbl->SetMouseCursor(&(Console)->TermIFace, (hCursor)) #define ConioMenuControl(Console, CmdIdLow, CmdIdHigh) \ - (Console)->TermIFace.Vtbl->MenuControl((Console), (CmdIdLow), (CmdIdHigh)) + (Console)->TermIFace.Vtbl->MenuControl(&(Console)->TermIFace, (CmdIdLow), (CmdIdHigh)) #define ConioSetMenuClose(Console, Enable) \ - (Console)->TermIFace.Vtbl->SetMenuClose((Console), (Enable)) + (Console)->TermIFace.Vtbl->SetMenuClose(&(Console)->TermIFace, (Enable)) /* EOF */ diff --git a/reactos/win32ss/user/consrv/conoutput.c b/reactos/win32ss/user/consrv/conoutput.c index d74f76dee06..39fd9c66085 100644 --- a/reactos/win32ss/user/consrv/conoutput.c +++ b/reactos/win32ss/user/consrv/conoutput.c @@ -150,6 +150,11 @@ ConioSetActiveScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer) // ConioDrawConsole(Console); } +PCONSOLE_SCREEN_BUFFER +ConDrvGetActiveScreenBuffer(IN PCONSOLE Console) +{ + return (Console ? Console->ActiveBuffer : NULL); +} /* PUBLIC SERVER APIS *********************************************************/ diff --git a/reactos/win32ss/user/consrv/conoutput.h b/reactos/win32ss/user/consrv/conoutput.h index f10320b53db..8d11d7bf902 100644 --- a/reactos/win32ss/user/consrv/conoutput.h +++ b/reactos/win32ss/user/consrv/conoutput.h @@ -40,4 +40,7 @@ NTSTATUS FASTCALL ConSrvCreateScreenBuffer(OUT PCONSOLE_SCREEN_BUFFER* Buffer, VOID WINAPI ConioDeleteScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer); VOID FASTCALL ConioSetActiveScreenBuffer(PCONSOLE_SCREEN_BUFFER Buffer); +PCONSOLE_SCREEN_BUFFER +ConDrvGetActiveScreenBuffer(IN PCONSOLE Console); + /* EOF */ diff --git a/reactos/win32ss/user/consrv/console.c b/reactos/win32ss/user/consrv/console.c index deed524978a..d0e02438802 100644 --- a/reactos/win32ss/user/consrv/console.c +++ b/reactos/win32ss/user/consrv/console.c @@ -10,9 +10,6 @@ /* INCLUDES *******************************************************************/ -#define COBJMACROS -#define NONAMELESSUNION - #include "consrv.h" #include "include/conio.h" #include "conio.h" @@ -25,163 +22,88 @@ #include "include/settings.h" #include "frontends/gui/guiterm.h" +#ifdef TUITERM_COMPILE #include "frontends/tui/tuiterm.h" +#endif #include "include/console.h" #include "console.h" #include "resource.h" -#include -#include - #define NDEBUG #include + /* GLOBALS ********************************************************************/ -static LIST_ENTRY ConsoleList; /* The list of all the allocated consoles */ -static RTL_RESOURCE ListLock; +/***************/ +#ifdef TUITERM_COMPILE +NTSTATUS NTAPI +TuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd, + IN OUT PCONSOLE_INFO ConsoleInfo, + IN OUT PVOID ExtraConsoleInfo, + IN ULONG ProcessId); +NTSTATUS NTAPI +TuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd); +#endif -#define ConSrvLockConsoleListExclusive() \ - RtlAcquireResourceExclusive(&ListLock, TRUE) +NTSTATUS NTAPI +GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd, + IN OUT PCONSOLE_INFO ConsoleInfo, + IN OUT PVOID ExtraConsoleInfo, + IN ULONG ProcessId); +NTSTATUS NTAPI +GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd); +/***************/ -#define ConSrvLockConsoleListShared() \ - RtlAcquireResourceShared(&ListLock, TRUE) +typedef +NTSTATUS NTAPI +(*FRONTEND_LOAD)(IN OUT PFRONTEND FrontEnd, + IN OUT PCONSOLE_INFO ConsoleInfo, + IN OUT PVOID ExtraConsoleInfo, + IN ULONG ProcessId); -#define ConSrvUnlockConsoleList() \ - RtlReleaseResource(&ListLock) +typedef +NTSTATUS NTAPI +(*FRONTEND_UNLOAD)(IN OUT PFRONTEND FrontEnd); -// Adapted from reactos/lib/rtl/unicode.c, RtlCreateUnicodeString line 2180 -BOOLEAN -ConsoleCreateUnicodeString(IN OUT PUNICODE_STRING UniDest, - IN PCWSTR Source) +/* + * If we are not in GUI-mode, start the text-mode terminal emulator. + * If we fail, try to start the GUI-mode terminal emulator. + * + * Try to open the GUI-mode terminal emulator. Two cases are possible: + * - We are in GUI-mode, therefore GuiMode == TRUE, the previous test-case + * failed and we start GUI-mode terminal emulator. + * - We are in text-mode, therefore GuiMode == FALSE, the previous test-case + * succeeded BUT we failed at starting text-mode terminal emulator. + * Then GuiMode was switched to TRUE in order to try to open the GUI-mode + * terminal emulator (Win32k will automatically switch to graphical mode, + * therefore no additional code is needed). + */ + +/* + * NOTE: Each entry of the table should be retrieved when loading a front-end + * (examples of the CSR servers which register some data for CSRSS). + */ +struct { - SIZE_T Size = (wcslen(Source) + 1) * sizeof(WCHAR); - if (Size > MAXUSHORT) return FALSE; - - UniDest->Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size); - if (UniDest->Buffer == NULL) return FALSE; - - RtlCopyMemory(UniDest->Buffer, Source, Size); - UniDest->MaximumLength = (USHORT)Size; - UniDest->Length = (USHORT)Size - sizeof(WCHAR); - - return TRUE; -} - -// Adapted from reactos/lib/rtl/unicode.c, RtlFreeUnicodeString line 431 -VOID -ConsoleFreeUnicodeString(IN PUNICODE_STRING UnicodeString) + CHAR FrontEndName[80]; + FRONTEND_LOAD FrontEndLoad; + FRONTEND_UNLOAD FrontEndUnload; +} FrontEndLoadingMethods[] = { - if (UnicodeString->Buffer) - { - ConsoleFreeHeap(UnicodeString->Buffer); - RtlZeroMemory(UnicodeString, sizeof(UNICODE_STRING)); - } -} +#ifdef TUITERM_COMPILE + {"TUI", TuiLoadFrontEnd, TuiUnloadFrontEnd}, +#endif + {"GUI", GuiLoadFrontEnd, GuiUnloadFrontEnd}, + +// {"Not found", 0, NULL} +}; /* PRIVATE FUNCTIONS **********************************************************/ -static BOOL -DtbgIsDesktopVisible(VOID) -{ - return !((BOOL)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE)); -} - -static ULONG -ConSrvConsoleCtrlEventTimeout(DWORD Event, - PCONSOLE_PROCESS_DATA ProcessData, - DWORD Timeout) -{ - ULONG Status = ERROR_SUCCESS; - - DPRINT("ConSrvConsoleCtrlEventTimeout Parent ProcessId = %x\n", ProcessData->Process->ClientId.UniqueProcess); - - if (ProcessData->CtrlDispatcher) - { - _SEH2_TRY - { - HANDLE Thread = NULL; - - _SEH2_TRY - { - Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0, - ProcessData->CtrlDispatcher, - UlongToPtr(Event), 0, NULL); - if (NULL == Thread) - { - Status = GetLastError(); - DPRINT1("Failed thread creation (Error: 0x%x)\n", Status); - } - else - { - DPRINT("ProcessData->CtrlDispatcher remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n", ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process); - WaitForSingleObject(Thread, Timeout); - } - } - _SEH2_FINALLY - { - CloseHandle(Thread); - } - _SEH2_END; - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - Status = RtlNtStatusToDosError(_SEH2_GetExceptionCode()); - DPRINT1("ConSrvConsoleCtrlEventTimeout - Caught an exception, Status = %08X\n", Status); - } - _SEH2_END; - } - - return Status; -} - -static ULONG -ConSrvConsoleCtrlEvent(DWORD Event, - PCONSOLE_PROCESS_DATA ProcessData) -{ - return ConSrvConsoleCtrlEventTimeout(Event, ProcessData, 0); -} - -ULONG FASTCALL -ConSrvConsoleProcessCtrlEvent(PCONSOLE Console, - ULONG ProcessGroupId, - DWORD Event) -{ - ULONG Status = ERROR_SUCCESS; - PLIST_ENTRY current_entry; - PCONSOLE_PROCESS_DATA current; - - /* If the console is already being destroyed, just return */ - if (!ConSrvValidateConsole(Console, CONSOLE_RUNNING, FALSE)) - return STATUS_UNSUCCESSFUL; - - /* - * Loop through the process list, from the most recent process - * (the active one) to the oldest one (the first created, i.e. - * the console leader process), and for each, send an event - * (new processes are inserted at the head of the console process list). - */ - current_entry = Console->ProcessList.Flink; - while (current_entry != &Console->ProcessList) - { - current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink); - current_entry = current_entry->Flink; - - /* - * Only processes belonging to the same process group are signaled. - * If the process group ID is zero, then all the processes are signaled. - */ - if (ProcessGroupId == 0 || current->Process->ProcessGroupId == ProcessGroupId) - { - Status = ConSrvConsoleCtrlEvent(Event, current); - } - } - - return Status; -} - +#if 0000 VOID FASTCALL ConioPause(PCONSOLE Console, UINT Flags) { @@ -212,97 +134,10 @@ ConioUnpause(PCONSOLE Console, UINT Flags) } } } +#endif -BOOL FASTCALL -ConSrvValidateConsolePointer(PCONSOLE Console) -{ - PLIST_ENTRY ConsoleEntry; - PCONSOLE CurrentConsole = NULL; - if (!Console) return FALSE; - - /* The console list must be locked */ - // ASSERT(Console_list_locked); - - ConsoleEntry = ConsoleList.Flink; - while (ConsoleEntry != &ConsoleList) - { - CurrentConsole = CONTAINING_RECORD(ConsoleEntry, CONSOLE, Entry); - ConsoleEntry = ConsoleEntry->Flink; - if (CurrentConsole == Console) return TRUE; - } - - return FALSE; -} - -BOOL FASTCALL -ConSrvValidateConsoleState(PCONSOLE Console, - CONSOLE_STATE ExpectedState) -{ - // if (!Console) return FALSE; - - /* The console must be locked */ - // ASSERT(Console_locked); - - return (Console->State == ExpectedState); -} - -BOOL FASTCALL -ConSrvValidateConsoleUnsafe(PCONSOLE Console, - CONSOLE_STATE ExpectedState, - BOOL LockConsole) -{ - if (!Console) return FALSE; - - /* - * Lock the console to forbid possible console's state changes - * (which must be done when the console is already locked). - * If we don't want to lock it, it's because the lock is already - * held. So there must be no problems. - */ - if (LockConsole) EnterCriticalSection(&Console->Lock); - - // ASSERT(Console_locked); - - /* Check whether the console's state is what we expect */ - if (!ConSrvValidateConsoleState(Console, ExpectedState)) - { - if (LockConsole) LeaveCriticalSection(&Console->Lock); - return FALSE; - } - - return TRUE; -} - -BOOL FASTCALL -ConSrvValidateConsole(PCONSOLE Console, - CONSOLE_STATE ExpectedState, - BOOL LockConsole) -{ - BOOL RetVal = FALSE; - - if (!Console) return FALSE; - - /* - * Forbid creation or deletion of consoles when - * checking for the existence of a console. - */ - ConSrvLockConsoleListShared(); - - if (ConSrvValidateConsolePointer(Console)) - { - RetVal = ConSrvValidateConsoleUnsafe(Console, - ExpectedState, - LockConsole); - } - - /* Unlock the console list and return */ - ConSrvUnlockConsoleList(); - return RetVal; -} - -NTSTATUS -FASTCALL +NTSTATUS FASTCALL ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData, PCONSOLE* Console, BOOL LockConsole) @@ -310,19 +145,14 @@ ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData, NTSTATUS Status = STATUS_SUCCESS; PCONSOLE ProcessConsole; + ASSERT(Console); + *Console = NULL; + // RtlEnterCriticalSection(&ProcessData->HandleTableLock); ProcessConsole = ProcessData->Console; - if (ConSrvValidateConsole(ProcessConsole, CONSOLE_RUNNING, LockConsole)) - { - InterlockedIncrement(&ProcessConsole->ReferenceCount); - *Console = ProcessConsole; - } - else - { - *Console = NULL; - Status = STATUS_INVALID_HANDLE; - } + Status = ConDrvGrabConsole(ProcessConsole, LockConsole); + if (NT_SUCCESS(Status)) *Console = ProcessConsole; // RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return Status; @@ -332,183 +162,34 @@ VOID FASTCALL ConSrvReleaseConsole(PCONSOLE Console, BOOL WasConsoleLocked) { - LONG RefCount = 0; - - if (!Console) return; - // if (Console->ReferenceCount == 0) return; // This shouldn't happen - ASSERT(Console->ReferenceCount > 0); - - /* The console must be locked */ - // ASSERT(Console_locked); - - /* - * Decrement the reference count. Save the new value too, - * because Console->ReferenceCount might be modified after - * the console gets unlocked but before we check whether we - * can destroy it. - */ - RefCount = _InterlockedDecrement(&Console->ReferenceCount); - - /* Unlock the console if needed */ - if (WasConsoleLocked) LeaveCriticalSection(&Console->Lock); - - /* Delete the console if needed */ - if (RefCount <= 0) ConSrvDeleteConsole(Console); + /* Just call the driver*/ + ConDrvReleaseConsole(Console, WasConsoleLocked); } -VOID WINAPI -ConSrvInitConsoleSupport(VOID) -{ - DPRINT("CONSRV: ConSrvInitConsoleSupport()\n"); - - /* Initialize the console list and its lock */ - InitializeListHead(&ConsoleList); - RtlInitializeResource(&ListLock); - - /* Should call LoadKeyboardLayout */ -} - -static BOOL -LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo, - IN OUT PCONSOLE_INFO ConsoleInfo, - OUT LPWSTR IconPath, - IN SIZE_T IconPathLength, - OUT PINT piIcon) -{ -#define PATH_SEPARATOR L'\\' - - BOOL RetVal = FALSE; - HRESULT hRes = S_OK; - LPWSTR LinkName = NULL; - SIZE_T Length = 0; - - if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0) - return FALSE; - - if (IconPath == NULL || piIcon == NULL) - return FALSE; - - IconPath[0] = L'\0'; - *piIcon = 0; - - /* 1- Find the last path separator if any */ - LinkName = wcsrchr(ConsoleStartInfo->ConsoleTitle, PATH_SEPARATOR); - if (LinkName == NULL) - { - LinkName = ConsoleStartInfo->ConsoleTitle; - } - else - { - /* Skip the path separator */ - ++LinkName; - } - - /* 2- Check for the link extension. The name ".lnk" is considered invalid. */ - Length = wcslen(LinkName); - if ( (Length <= 4) || (wcsicmp(LinkName + (Length - 4), L".lnk") != 0) ) - return FALSE; - - /* 3- It may be a link. Try to retrieve some properties */ - hRes = CoInitialize(NULL); - if (SUCCEEDED(hRes)) - { - /* Get a pointer to the IShellLink interface */ - IShellLinkW* pshl = NULL; - hRes = CoCreateInstance(&CLSID_ShellLink, - NULL, - CLSCTX_INPROC_SERVER, - &IID_IShellLinkW, - (LPVOID*)&pshl); - if (SUCCEEDED(hRes)) - { - /* Get a pointer to the IPersistFile interface */ - IPersistFile* ppf = NULL; - hRes = IPersistFile_QueryInterface(pshl, &IID_IPersistFile, (LPVOID*)&ppf); - if (SUCCEEDED(hRes)) - { - /* Load the shortcut */ - hRes = IPersistFile_Load(ppf, ConsoleStartInfo->ConsoleTitle, STGM_READ); - if (SUCCEEDED(hRes)) - { - /* - * Finally we can get the properties ! - * Update the old ones if needed. - */ - INT ShowCmd = 0; - // WORD HotKey = 0; - - /* Reset the name of the console with the name of the shortcut */ - Length = min(/*Length*/ Length - 4, // 4 == len(".lnk") - sizeof(ConsoleInfo->ConsoleTitle) / sizeof(ConsoleInfo->ConsoleTitle[0]) - 1); - wcsncpy(ConsoleInfo->ConsoleTitle, LinkName, Length); - ConsoleInfo->ConsoleTitle[Length] = L'\0'; - - /* Get the window showing command */ - hRes = IShellLinkW_GetShowCmd(pshl, &ShowCmd); - if (SUCCEEDED(hRes)) ConsoleStartInfo->ShowWindow = (WORD)ShowCmd; - - /* Get the hotkey */ - // hRes = pshl->GetHotkey(&ShowCmd); - // if (SUCCEEDED(hRes)) ConsoleStartInfo->HotKey = HotKey; - - /* Get the icon location, if any */ - hRes = IShellLinkW_GetIconLocation(pshl, IconPath, IconPathLength, piIcon); - if (!SUCCEEDED(hRes)) - { - IconPath[0] = L'\0'; - } - - // FIXME: Since we still don't load console properties from the shortcut, - // return false. When this will be done, we will return true instead. - RetVal = FALSE; - } - IPersistFile_Release(ppf); - } - IShellLinkW_Release(pshl); - } - } - CoUninitialize(); - - return RetVal; -} NTSTATUS WINAPI ConSrvInitConsole(OUT PCONSOLE* NewConsole, IN OUT PCONSOLE_START_INFO ConsoleStartInfo, - IN PCSR_PROCESS ConsoleLeaderProcess) + IN ULONG ConsoleLeaderProcessId) { NTSTATUS Status; - SECURITY_ATTRIBUTES SecurityAttributes; - SIZE_T Length = 0; - DWORD ProcessId = HandleToUlong(ConsoleLeaderProcess->ClientId.UniqueProcess); - CONSOLE_INFO ConsoleInfo; - TEXTMODE_BUFFER_INFO ScreenBufferInfo; PCONSOLE Console; - PCONSOLE_SCREEN_BUFFER NewBuffer; - BOOL GuiMode; - WCHAR DefaultTitle[128]; - WCHAR IconPath[MAX_PATH + 1] = L""; - INT iIcon = 0; + CONSOLE_INFO ConsoleInfo; + SIZE_T Length = 0; + ULONG i = 0; + FRONTEND FrontEnd; + + if (NewConsole == NULL || ConsoleStartInfo == NULL) + return STATUS_INVALID_PARAMETER; - if (NewConsole == NULL) return STATUS_INVALID_PARAMETER; *NewConsole = NULL; - /* - * Allocate a console structure - */ - Console = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(CONSOLE)); - if (NULL == Console) - { - DPRINT1("Not enough memory for console creation.\n"); - return STATUS_NO_MEMORY; - } - /* * Load the console settings */ /* 1. Load the default settings */ - ConSrvGetDefaultSettings(&ConsoleInfo, ProcessId); + ConSrvGetDefaultSettings(&ConsoleInfo, ConsoleLeaderProcessId); /* 2. Get the title of the console (initialize ConsoleInfo.ConsoleTitle) */ Length = min(wcslen(ConsoleStartInfo->ConsoleTitle), @@ -516,23 +197,39 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole, wcsncpy(ConsoleInfo.ConsoleTitle, ConsoleStartInfo->ConsoleTitle, Length); ConsoleInfo.ConsoleTitle[Length] = L'\0'; + /* - * 3. Check whether the process creating the console was launched - * via a shell-link. ConsoleInfo.ConsoleTitle may be updated by - * the name of the shortcut. + * Choose an adequate terminal front-end to load, and load it */ - if (ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) + Status = STATUS_SUCCESS; + for (i = 0; i < sizeof(FrontEndLoadingMethods) / sizeof(FrontEndLoadingMethods[0]); ++i) { - if (!LoadShellLinkConsoleInfo(ConsoleStartInfo, - &ConsoleInfo, - IconPath, - MAX_PATH, - &iIcon)) + DPRINT("CONSRV: Trying to load %s terminal emulator...\n", FrontEndLoadingMethods[i].FrontEndName); + Status = FrontEndLoadingMethods[i].FrontEndLoad(&FrontEnd, + &ConsoleInfo, + ConsoleStartInfo, + ConsoleLeaderProcessId); + if (NT_SUCCESS(Status)) { - ConsoleStartInfo->dwStartupFlags &= ~STARTF_TITLEISLINKNAME; + DPRINT("CONSRV: %s terminal emulator loaded successfully\n", FrontEndLoadingMethods[i].FrontEndName); + break; + } + else + { + DPRINT1("CONSRV: Loading %s terminal emulator failed, Status = 0x%08lx , continuing...\n", FrontEndLoadingMethods[i].FrontEndName, Status); } } + if (!NT_SUCCESS(Status)) + { + DPRINT1("CONSRV: Failed to initialize a frontend, Status = 0x%08lx\n", Status); + return Status; + } + + DPRINT("CONSRV: Frontend initialized\n"); + + +/******************************************************************************/ /* * 4. Load the remaining console settings via the registry. */ @@ -543,7 +240,7 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole, * or we failed to load shell-link console properties. * Therefore, load the console infos for the application from the registry. */ - ConSrvReadUserSettings(&ConsoleInfo, ProcessId); + ConSrvReadUserSettings(&ConsoleInfo, ConsoleLeaderProcessId); /* * Now, update them with the properties the user might gave to us @@ -561,198 +258,36 @@ ConSrvInitConsole(OUT PCONSOLE* NewConsole, } if (ConsoleStartInfo->dwStartupFlags & STARTF_USESIZE) { - // ConsoleInfo->ConsoleSize = ConsoleStartInfo->ConsoleWindowSize; + // ConsoleInfo.ConsoleSize = ConsoleStartInfo->ConsoleWindowSize; ConsoleInfo.ConsoleSize.X = (SHORT)ConsoleStartInfo->ConsoleWindowSize.cx; ConsoleInfo.ConsoleSize.Y = (SHORT)ConsoleStartInfo->ConsoleWindowSize.cy; } } - /* - * Fix the screen buffer size if needed. The rule is: - * ScreenBufferSize >= ConsoleSize - */ - if (ConsoleInfo.ScreenBufferSize.X < ConsoleInfo.ConsoleSize.X) - ConsoleInfo.ScreenBufferSize.X = ConsoleInfo.ConsoleSize.X; - if (ConsoleInfo.ScreenBufferSize.Y < ConsoleInfo.ConsoleSize.Y) - ConsoleInfo.ScreenBufferSize.Y = ConsoleInfo.ConsoleSize.Y; + /* Set-up the code page */ + ConsoleInfo.CodePage = GetOEMCP(); +/******************************************************************************/ - /* - * Initialize the console - */ - Console->State = CONSOLE_INITIALIZING; - Console->ReferenceCount = 0; - InitializeCriticalSection(&Console->Lock); - InitializeListHead(&Console->ProcessList); - RtlZeroMemory(&Console->TermIFace, sizeof(Console->TermIFace)); - - memcpy(Console->Colors, ConsoleInfo.Colors, sizeof(ConsoleInfo.Colors)); - Console->ConsoleSize = ConsoleInfo.ConsoleSize; - Console->FixedSize = FALSE; // Value by default; is reseted by the front-ends if needed. - - /* - * Initialize the input buffer - */ - ConSrvInitObject(&Console->InputBuffer.Header, INPUT_BUFFER, Console); - - SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); - SecurityAttributes.lpSecurityDescriptor = NULL; - SecurityAttributes.bInheritHandle = TRUE; - Console->InputBuffer.ActiveEvent = CreateEventW(&SecurityAttributes, TRUE, FALSE, NULL); - if (NULL == Console->InputBuffer.ActiveEvent) - { - DeleteCriticalSection(&Console->Lock); - ConsoleFreeHeap(Console); - return STATUS_UNSUCCESSFUL; - } - - Console->InputBuffer.InputBufferSize = 0; // FIXME! - InitializeListHead(&Console->InputBuffer.InputEvents); - InitializeListHead(&Console->InputBuffer.ReadWaitQueue); - Console->InputBuffer.Mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | - ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT; - - Console->QuickEdit = ConsoleInfo.QuickEdit; - Console->InsertMode = ConsoleInfo.InsertMode; - Console->LineBuffer = NULL; - Console->LineMaxSize = Console->LineSize = Console->LinePos = 0; - Console->LineComplete = Console->LineUpPressed = Console->LineInsertToggle = FALSE; - // LineWakeupMask - RtlZeroMemory(&Console->Selection, sizeof(CONSOLE_SELECTION_INFO)); - Console->Selection.dwFlags = CONSOLE_NO_SELECTION; - // dwSelectionCursor - - Console->CodePage = GetOEMCP(); - Console->OutputCodePage = GetOEMCP(); - - /* Initialize a new text-mode screen buffer with default settings */ - ScreenBufferInfo.ScreenBufferSize = ConsoleInfo.ScreenBufferSize; - ScreenBufferInfo.ScreenAttrib = ConsoleInfo.ScreenAttrib; - ScreenBufferInfo.PopupAttrib = ConsoleInfo.PopupAttrib; - ScreenBufferInfo.IsCursorVisible = TRUE; - ScreenBufferInfo.CursorSize = ConsoleInfo.CursorSize; - - InitializeListHead(&Console->BufferList); - Status = ConSrvCreateScreenBuffer(&NewBuffer, - Console, - CONSOLE_TEXTMODE_BUFFER, - &ScreenBufferInfo); + Status = ConDrvInitConsole(&Console, &ConsoleInfo, ConsoleLeaderProcessId); if (!NT_SUCCESS(Status)) { - DPRINT1("ConSrvCreateScreenBuffer: failed, Status = 0x%08lx\n", Status); - CloseHandle(Console->InputBuffer.ActiveEvent); - DeleteCriticalSection(&Console->Lock); - ConsoleFreeHeap(Console); + DPRINT1("Creating a new console failed, Status = 0x%08lx\n", Status); + FrontEndLoadingMethods[i].FrontEndUnload(&FrontEnd); return Status; } - /* Make the new screen buffer active */ - Console->ActiveBuffer = NewBuffer; - InitializeListHead(&Console->WriteWaitQueue); - Console->PauseFlags = 0; - Console->UnpauseEvent = NULL; - /* - * Initialize the alias and history buffers - */ - Console->Aliases = NULL; - InitializeListHead(&Console->HistoryBuffers); - Console->HistoryBufferSize = ConsoleInfo.HistoryBufferSize; - Console->NumberOfHistoryBuffers = ConsoleInfo.NumberOfHistoryBuffers; - Console->HistoryNoDup = ConsoleInfo.HistoryNoDup; + ASSERT(Console); + DPRINT("Console initialized\n"); - /* Initialize the console title */ - ConsoleCreateUnicodeString(&Console->OriginalTitle, ConsoleInfo.ConsoleTitle); - if (ConsoleInfo.ConsoleTitle[0] == L'\0') + Status = ConDrvRegisterFrontEnd(Console, &FrontEnd); + if (!NT_SUCCESS(Status)) { - if (LoadStringW(ConSrvDllInstance, IDS_CONSOLE_TITLE, DefaultTitle, sizeof(DefaultTitle) / sizeof(DefaultTitle[0]))) - { - ConsoleCreateUnicodeString(&Console->Title, DefaultTitle); - } - else - { - ConsoleCreateUnicodeString(&Console->Title, L"ReactOS Console"); - } + DPRINT1("Failed to register frontend to the given console, Status = 0x%08lx\n", Status); + ConDrvDeleteConsole(Console); + FrontEndLoadingMethods[i].FrontEndUnload(&FrontEnd); + return Status; } - else - { - ConsoleCreateUnicodeString(&Console->Title, ConsoleInfo.ConsoleTitle); - } - - /* Lock the console until its initialization is finished */ - // EnterCriticalSection(&Console->Lock); - - /* - * If we are not in GUI-mode, start the text-mode terminal emulator. - * If we fail, try to start the GUI-mode terminal emulator. - */ - GuiMode = DtbgIsDesktopVisible(); - - if (!GuiMode) - { - DPRINT("CONSRV: Opening text-mode terminal emulator\n"); - Status = TuiInitConsole(Console, - ConsoleStartInfo, - &ConsoleInfo, - ProcessId); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to open text-mode terminal emulator, switching to gui-mode, Status = 0x%08lx\n", Status); - GuiMode = TRUE; - } - } - - /* - * Try to open the GUI-mode terminal emulator. Two cases are possible: - * - We are in GUI-mode, therefore GuiMode == TRUE, the previous test-case - * failed and we start GUI-mode terminal emulator. - * - We are in text-mode, therefore GuiMode == FALSE, the previous test-case - * succeeded BUT we failed at starting text-mode terminal emulator. - * Then GuiMode was switched to TRUE in order to try to open the GUI-mode - * terminal emulator (Win32k will automatically switch to graphical mode, - * therefore no additional code is needed). - */ - if (GuiMode) - { - DPRINT("CONSRV: Opening GUI-mode terminal emulator\n"); - Status = GuiInitConsole(Console, - ConsoleStartInfo, - &ConsoleInfo, - ProcessId, - IconPath, - iIcon); - if (!NT_SUCCESS(Status)) - { - DPRINT1("GuiInitConsole: failed, Status = 0x%08lx\n", Status); - ConsoleFreeUnicodeString(&Console->OriginalTitle); - ConsoleFreeUnicodeString(&Console->Title); - ConioDeleteScreenBuffer(NewBuffer); - CloseHandle(Console->InputBuffer.ActiveEvent); - // LeaveCriticalSection(&Console->Lock); - DeleteCriticalSection(&Console->Lock); - ConsoleFreeHeap(Console); - return Status; - } - } - - DPRINT("Terminal initialized\n"); - - /* All went right, so add the console to the list */ - ConSrvLockConsoleListExclusive(); - DPRINT("Insert in the list\n"); - InsertTailList(&ConsoleList, &Console->Entry); - - /* The initialization is finished */ - DPRINT("Change state\n"); - Console->State = CONSOLE_RUNNING; - - /* Unlock the console */ - // LeaveCriticalSection(&Console->Lock); - - /* Unlock the console list */ - ConSrvUnlockConsoleList(); - - /* Copy buffer contents to screen */ - ConioDrawConsole(Console); - DPRINT("Console drawn\n"); + DPRINT("FrontEnd registered\n"); /* Return the newly created console to the caller and a success code too */ *NewConsole = Console; @@ -764,116 +299,8 @@ ConSrvDeleteConsole(PCONSOLE Console) { DPRINT("ConSrvDeleteConsole\n"); - /* - * Forbid validation of any console by other threads - * during the deletion of this console. - */ - ConSrvLockConsoleListExclusive(); - - /* Check the existence of the console, and if it's ok, continue */ - if (!ConSrvValidateConsolePointer(Console)) - { - /* Unlock the console list and return */ - ConSrvUnlockConsoleList(); - return; - } - - /* - * If the console is already being destroyed - * (thus not running), just return. - */ - if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) - { - /* Unlock the console list and return */ - ConSrvUnlockConsoleList(); - return; - } - - /* - * We are about to be destroyed. Signal it to other people - * so that they can terminate what they are doing, and that - * they cannot longer validate the console. - */ - Console->State = CONSOLE_TERMINATING; - - /* - * Allow other threads to finish their job: basically, unlock - * all other calls to EnterCriticalSection(&Console->Lock); by - * ConSrvValidateConsole(Unsafe) functions so that they just see - * that we are not in CONSOLE_RUNNING state anymore, or unlock - * other concurrent calls to ConSrvDeleteConsole so that they - * can see that we are in fact already deleting the console. - */ - LeaveCriticalSection(&Console->Lock); - ConSrvUnlockConsoleList(); - - /* FIXME: Send a terminate message to all the processes owning this console */ - - /* Cleanup the UI-oriented part */ - ConioCleanupConsole(Console); - - /*** - * Check that the console is in terminating state before continuing - * (the cleanup code must not change the state of the console... - * ...unless to cancel console deletion ?). - ***/ - - ConSrvLockConsoleListExclusive(); - - /* Re-check the existence of the console, and if it's ok, continue */ - if (!ConSrvValidateConsolePointer(Console)) - { - /* Unlock the console list and return */ - ConSrvUnlockConsoleList(); - return; - } - - if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_TERMINATING, TRUE)) - { - ConSrvUnlockConsoleList(); - return; - } - - /* We are in destruction */ - Console->State = CONSOLE_IN_DESTRUCTION; - - /* Remove the console from the list */ - RemoveEntryList(&Console->Entry); - - /* Reset the count to be sure */ - Console->ReferenceCount = 0; - - /* Discard all entries in the input event queue */ - PurgeInputBuffer(Console); - - if (Console->LineBuffer) ConsoleFreeHeap(Console->LineBuffer); - - IntDeleteAllAliases(Console); - HistoryDeleteBuffers(Console); - - ConioDeleteScreenBuffer(Console->ActiveBuffer); - if (!IsListEmpty(&Console->BufferList)) - { - DPRINT1("BUG: screen buffer list not empty\n"); - } - - // CloseHandle(Console->InputBuffer.ActiveEvent); - if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent); - - ConsoleFreeUnicodeString(&Console->OriginalTitle); - ConsoleFreeUnicodeString(&Console->Title); - - DPRINT("ConSrvDeleteConsole - Unlocking\n"); - LeaveCriticalSection(&Console->Lock); - DPRINT("ConSrvDeleteConsole - Destroying lock\n"); - DeleteCriticalSection(&Console->Lock); - DPRINT("ConSrvDeleteConsole - Lock destroyed ; freeing console\n"); - - ConsoleFreeHeap(Console); - DPRINT("ConSrvDeleteConsole - Console freed\n"); - - /* Unlock the console list and return */ - ConSrvUnlockConsoleList(); + /* Just call the driver. ConSrvDeregisterFrontEnd is called on-demand. */ + ConDrvDeleteConsole(Console); } @@ -1019,140 +446,59 @@ CSR_API(SrvFreeConsole) return STATUS_SUCCESS; } +NTSTATUS NTAPI +ConDrvGetConsoleMode(IN PCONSOLE Console, + IN PCONSOLE_IO_OBJECT Object, + OUT PULONG ConsoleMode); CSR_API(SrvGetConsoleMode) { NTSTATUS Status; PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest; - PCONSOLE_IO_OBJECT Object = NULL; + PCONSOLE_IO_OBJECT Object; Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process), ConsoleModeRequest->ConsoleHandle, &Object, NULL, GENERIC_READ, TRUE, 0); if (!NT_SUCCESS(Status)) return Status; - Status = STATUS_SUCCESS; - - if (INPUT_BUFFER == Object->Type) - { - PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object; - PCONSOLE Console = InputBuffer->Header.Console; - DWORD ConsoleMode = InputBuffer->Mode; - - if (Console->QuickEdit || Console->InsertMode) - { - // Windows does this, even if it's not documented on MSDN - ConsoleMode |= ENABLE_EXTENDED_FLAGS; - - if (Console->QuickEdit ) ConsoleMode |= ENABLE_QUICK_EDIT_MODE; - if (Console->InsertMode) ConsoleMode |= ENABLE_INSERT_MODE; - } - - ConsoleModeRequest->ConsoleMode = ConsoleMode; - } - else if (TEXTMODE_BUFFER == Object->Type || GRAPHICS_BUFFER == Object->Type) - { - PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object; - ConsoleModeRequest->ConsoleMode = Buffer->Mode; - } - else - { - Status = STATUS_INVALID_HANDLE; - } + Status = ConDrvGetConsoleMode(Object->Console, Object, + &ConsoleModeRequest->ConsoleMode); ConSrvReleaseObject(Object, TRUE); return Status; } +NTSTATUS NTAPI +ConDrvSetConsoleMode(IN PCONSOLE Console, + IN PCONSOLE_IO_OBJECT Object, + IN ULONG ConsoleMode); CSR_API(SrvSetConsoleMode) { -#define CONSOLE_VALID_CONTROL_MODES ( ENABLE_EXTENDED_FLAGS | ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE ) -#define CONSOLE_VALID_INPUT_MODES ( ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | \ - ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT | \ - ENABLE_MOUSE_INPUT ) -#define CONSOLE_VALID_OUTPUT_MODES ( ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT ) - NTSTATUS Status; PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest; - DWORD ConsoleMode = ConsoleModeRequest->ConsoleMode; - PCONSOLE_IO_OBJECT Object = NULL; + PCONSOLE_IO_OBJECT Object; Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process), ConsoleModeRequest->ConsoleHandle, &Object, NULL, GENERIC_WRITE, TRUE, 0); if (!NT_SUCCESS(Status)) return Status; - Status = STATUS_SUCCESS; + Status = ConDrvSetConsoleMode(Object->Console, Object, + ConsoleModeRequest->ConsoleMode); - if (INPUT_BUFFER == Object->Type) - { - PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object; - PCONSOLE Console = InputBuffer->Header.Console; - - DPRINT("SetConsoleMode(Input, %d)\n", ConsoleMode); - - /* - * 1. Only the presence of valid mode flags is allowed. - */ - if (ConsoleMode & ~(CONSOLE_VALID_INPUT_MODES | CONSOLE_VALID_CONTROL_MODES)) - { - Status = STATUS_INVALID_PARAMETER; - goto Quit; - } - - /* - * 2. If we use control mode flags without ENABLE_EXTENDED_FLAGS, - * then consider the flags invalid. - * - if ( (ConsoleMode & CONSOLE_VALID_CONTROL_MODES) && - (ConsoleMode & ENABLE_EXTENDED_FLAGS) == 0 ) - { - Status = STATUS_INVALID_PARAMETER; - goto Quit; - } - */ - - /* - * 3. Now we can continue. - */ - if (ConsoleMode & CONSOLE_VALID_CONTROL_MODES) - { - Console->QuickEdit = !!(ConsoleMode & ENABLE_QUICK_EDIT_MODE); - Console->InsertMode = !!(ConsoleMode & ENABLE_INSERT_MODE); - } - InputBuffer->Mode = (ConsoleMode & CONSOLE_VALID_INPUT_MODES); - } - else if (TEXTMODE_BUFFER == Object->Type || GRAPHICS_BUFFER == Object->Type) - { - PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object; - - DPRINT("SetConsoleMode(Output, %d)\n", ConsoleMode); - - if (ConsoleMode & ~CONSOLE_VALID_OUTPUT_MODES) - { - Status = STATUS_INVALID_PARAMETER; - } - else - { - Buffer->Mode = (ConsoleMode & CONSOLE_VALID_OUTPUT_MODES); - } - } - else - { - Status = STATUS_INVALID_HANDLE; - } - -Quit: ConSrvReleaseObject(Object, TRUE); return Status; } +NTSTATUS NTAPI +ConDrvGetConsoleTitle(IN PCONSOLE Console, + IN OUT PWCHAR Title, + IN OUT PULONG BufLength); CSR_API(SrvGetConsoleTitle) { NTSTATUS Status; PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest; - // PCSR_PROCESS Process = CsrGetClientThread()->Process; PCONSOLE Console; - DWORD Length; if (!CsrValidateMessageBuffer(ApiMessage, (PVOID)&TitleRequest->Title, @@ -1169,27 +515,23 @@ CSR_API(SrvGetConsoleTitle) return Status; } - /* Copy title of the console to the user title buffer */ - if (TitleRequest->Length >= sizeof(WCHAR)) - { - Length = min(TitleRequest->Length - sizeof(WCHAR), Console->Title.Length); - memcpy(TitleRequest->Title, Console->Title.Buffer, Length); - TitleRequest->Title[Length / sizeof(WCHAR)] = L'\0'; - } - - TitleRequest->Length = Console->Title.Length; + Status = ConDrvGetConsoleTitle(Console, + TitleRequest->Title, + &TitleRequest->Length); ConSrvReleaseConsole(Console, TRUE); - return STATUS_SUCCESS; + return Status; } +NTSTATUS NTAPI +ConDrvSetConsoleTitle(IN PCONSOLE Console, + IN PWCHAR Title, + IN ULONG BufLength); CSR_API(SrvSetConsoleTitle) { NTSTATUS Status; PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest; - // PCSR_PROCESS Process = CsrGetClientThread()->Process; PCONSOLE Console; - PWCHAR Buffer; if (!CsrValidateMessageBuffer(ApiMessage, (PVOID)&TitleRequest->Title, @@ -1206,368 +548,20 @@ CSR_API(SrvSetConsoleTitle) return Status; } - /* Allocate a new buffer to hold the new title (NULL-terminated) */ - Buffer = ConsoleAllocHeap(0, TitleRequest->Length + sizeof(WCHAR)); - if (Buffer) - { - /* Free the old title */ - ConsoleFreeUnicodeString(&Console->Title); + Status = ConDrvSetConsoleTitle(Console, + TitleRequest->Title, + TitleRequest->Length); - /* Copy title to console */ - Console->Title.Buffer = Buffer; - Console->Title.Length = TitleRequest->Length; - Console->Title.MaximumLength = Console->Title.Length + sizeof(WCHAR); - RtlCopyMemory(Console->Title.Buffer, - TitleRequest->Title, - Console->Title.Length); - Console->Title.Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0'; - - ConioChangeTitle(Console); - Status = STATUS_SUCCESS; - } - else - { - Status = STATUS_NO_MEMORY; - } - - ConSrvReleaseConsole(Console, TRUE); - return Status; -} - -/********************************************************************** - * HardwareStateProperty - * - * DESCRIPTION - * Set/Get the value of the HardwareState and switch - * between direct video buffer ouput and GDI windowed - * output. - * ARGUMENTS - * Client hands us a CONSOLE_GETSETHWSTATE object. - * We use the same object to Request. - * NOTE - * ConsoleHwState has the correct size to be compatible - * with NT's, but values are not. - */ -#if 0 -static NTSTATUS FASTCALL -SetConsoleHardwareState(PCONSOLE Console, ULONG ConsoleHwState) -{ - DPRINT1("Console Hardware State: %d\n", ConsoleHwState); - - if ((CONSOLE_HARDWARE_STATE_GDI_MANAGED == ConsoleHwState) - ||(CONSOLE_HARDWARE_STATE_DIRECT == ConsoleHwState)) - { - if (Console->HardwareState != ConsoleHwState) - { - /* TODO: implement switching from full screen to windowed mode */ - /* TODO: or back; now simply store the hardware state */ - Console->HardwareState = ConsoleHwState; - } - - return STATUS_SUCCESS; - } - - return STATUS_INVALID_PARAMETER_3; /* Client: (handle, set_get, [mode]) */ -} -#endif - -CSR_API(SrvGetConsoleHardwareState) -{ -#if 0 - NTSTATUS Status; - PCONSOLE_GETSETHWSTATE HardwareStateRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.HardwareStateRequest; - PCONSOLE_SCREEN_BUFFER Buff; - PCONSOLE Console; - - Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), - HardwareStateRequest->OutputHandle, - &Buff, - GENERIC_READ, - TRUE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to get console handle in SrvGetConsoleHardwareState\n"); - return Status; - } - - Console = Buff->Header.Console; - HardwareStateRequest->State = Console->HardwareState; - - ConSrvReleaseScreenBuffer(Buff, TRUE); - return Status; -#else - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; -#endif -} - -CSR_API(SrvSetConsoleHardwareState) -{ -#if 0 - NTSTATUS Status; - PCONSOLE_GETSETHWSTATE HardwareStateRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.HardwareStateRequest; - PCONSOLE_SCREEN_BUFFER Buff; - PCONSOLE Console; - - Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), - HardwareStateRequest->OutputHandle, - &Buff, - GENERIC_WRITE, - TRUE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to get console handle in SrvSetConsoleHardwareState\n"); - return Status; - } - - DPRINT("Setting console hardware state.\n"); - Console = Buff->Header.Console; - Status = SetConsoleHardwareState(Console, HardwareStateRequest->State); - - ConSrvReleaseScreenBuffer(Buff, TRUE); - return Status; -#else - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; -#endif -} - -CSR_API(SrvGetConsoleDisplayMode) -{ - NTSTATUS Status; - PCONSOLE_GETDISPLAYMODE GetDisplayModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetDisplayModeRequest; - PCONSOLE Console; - - Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), - &Console, TRUE); - if (!NT_SUCCESS(Status)) return Status; - - GetDisplayModeRequest->DisplayMode = ConioGetDisplayMode(Console); - - ConSrvReleaseConsole(Console, TRUE); - return STATUS_SUCCESS; -} - -CSR_API(SrvSetConsoleDisplayMode) -{ - NTSTATUS Status; - PCONSOLE_SETDISPLAYMODE SetDisplayModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetDisplayModeRequest; - PCONSOLE Console; - PCONSOLE_SCREEN_BUFFER Buff; - - Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), - SetDisplayModeRequest->OutputHandle, - &Buff, - GENERIC_WRITE, - TRUE); - if (!NT_SUCCESS(Status)) return Status; - - Console = Buff->Header.Console; - - if (ConioSetDisplayMode(Console, SetDisplayModeRequest->DisplayMode)) - { - SetDisplayModeRequest->NewSBDim = Buff->ScreenBufferSize; - Status = STATUS_SUCCESS; - } - else - { - Status = STATUS_INVALID_PARAMETER; - } - - ConSrvReleaseScreenBuffer(Buff, TRUE); - return Status; -} - -CSR_API(SrvGetLargestConsoleWindowSize) -{ - NTSTATUS Status; - PCONSOLE_GETLARGESTWINDOWSIZE GetLargestWindowSizeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetLargestWindowSizeRequest; - PCONSOLE_SCREEN_BUFFER Buff; - PCONSOLE Console; - - Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), - GetLargestWindowSizeRequest->OutputHandle, - &Buff, - GENERIC_READ, - TRUE); - if (!NT_SUCCESS(Status)) return Status; - - Console = Buff->Header.Console; - ConioGetLargestConsoleWindowSize(Console, &GetLargestWindowSizeRequest->Size); - - ConSrvReleaseScreenBuffer(Buff, TRUE); - return STATUS_SUCCESS; -} - -CSR_API(SrvShowConsoleCursor) -{ - NTSTATUS Status; - PCONSOLE_SHOWCURSOR ShowCursorRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ShowCursorRequest; - PCONSOLE Console; - PCONSOLE_SCREEN_BUFFER Buff; - - Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), - ShowCursorRequest->OutputHandle, - &Buff, - GENERIC_WRITE, - TRUE); - if (!NT_SUCCESS(Status)) return Status; - - Console = Buff->Header.Console; - - ShowCursorRequest->RefCount = ConioShowMouseCursor(Console, ShowCursorRequest->Show); - - ConSrvReleaseScreenBuffer(Buff, TRUE); - return STATUS_SUCCESS; -} - -CSR_API(SrvSetConsoleCursor) -{ - NTSTATUS Status; - BOOL Success; - PCONSOLE_SETCURSOR SetCursorRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetCursorRequest; - PCONSOLE Console; - PCONSOLE_SCREEN_BUFFER Buff; - - // FIXME: Tests show that this function is used only for graphics screen buffers - // and otherwise it returns false + set last error to invalid handle. - // NOTE: I find that behaviour is ridiculous but ok, let's accept that at the moment... - Status = ConSrvGetGraphicsBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), - SetCursorRequest->OutputHandle, - &Buff, - GENERIC_WRITE, - TRUE); - if (!NT_SUCCESS(Status)) return Status; - - Console = Buff->Header.Console; - - Success = ConioSetMouseCursor(Console, SetCursorRequest->hCursor); - - ConSrvReleaseScreenBuffer(Buff, TRUE); - return (Success ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL); -} - -CSR_API(SrvConsoleMenuControl) -{ - NTSTATUS Status; - PCONSOLE_MENUCONTROL MenuControlRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.MenuControlRequest; - PCONSOLE Console; - PCONSOLE_SCREEN_BUFFER Buff; - - Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), - MenuControlRequest->OutputHandle, - &Buff, - GENERIC_WRITE, - TRUE); - if (!NT_SUCCESS(Status)) return Status; - - Console = Buff->Header.Console; - - MenuControlRequest->hMenu = ConioMenuControl(Console, - MenuControlRequest->dwCmdIdLow, - MenuControlRequest->dwCmdIdHigh); - - ConSrvReleaseScreenBuffer(Buff, TRUE); - return STATUS_SUCCESS; -} - -CSR_API(SrvSetConsoleMenuClose) -{ - NTSTATUS Status; - BOOL Success; - PCONSOLE_SETMENUCLOSE SetMenuCloseRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetMenuCloseRequest; - PCONSOLE Console; - - Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), - &Console, TRUE); - if (!NT_SUCCESS(Status)) return Status; - - Success = ConioSetMenuClose(Console, SetMenuCloseRequest->Enable); - - ConSrvReleaseConsole(Console, TRUE); - return (Success ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL); -} - -CSR_API(SrvSetConsoleWindowInfo) -{ - NTSTATUS Status; - PCONSOLE_SETWINDOWINFO SetWindowInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetWindowInfoRequest; - PCONSOLE_SCREEN_BUFFER Buff; - SMALL_RECT WindowRect = SetWindowInfoRequest->WindowRect; - - DPRINT("SrvSetConsoleWindowInfo(0x%08x, %d, {L%d, T%d, R%d, B%d}) called\n", - SetWindowInfoRequest->OutputHandle, SetWindowInfoRequest->Absolute, - WindowRect.Left, WindowRect.Top, WindowRect.Right, WindowRect.Bottom); - - Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), - SetWindowInfoRequest->OutputHandle, - &Buff, - GENERIC_READ, - TRUE); - if (!NT_SUCCESS(Status)) return Status; - - if (SetWindowInfoRequest->Absolute == FALSE) - { - /* Relative positions given. Transform them to absolute ones */ - WindowRect.Left += Buff->ViewOrigin.X; - WindowRect.Top += Buff->ViewOrigin.Y; - WindowRect.Right += Buff->ViewOrigin.X + Buff->ViewSize.X - 1; - WindowRect.Bottom += Buff->ViewOrigin.Y + Buff->ViewSize.Y - 1; - } - - /* See MSDN documentation on SetConsoleWindowInfo about the performed checks */ - if ( (WindowRect.Left < 0) || (WindowRect.Top < 0) || - (WindowRect.Right >= Buff->ScreenBufferSize.X) || - (WindowRect.Bottom >= Buff->ScreenBufferSize.Y) || - (WindowRect.Right <= WindowRect.Left) || - (WindowRect.Bottom <= WindowRect.Top) ) - { - ConSrvReleaseScreenBuffer(Buff, TRUE); - return STATUS_INVALID_PARAMETER; - } - - Buff->ViewOrigin.X = WindowRect.Left; - Buff->ViewOrigin.Y = WindowRect.Top; - - Buff->ViewSize.X = WindowRect.Right - WindowRect.Left + 1; - Buff->ViewSize.Y = WindowRect.Bottom - WindowRect.Top + 1; - - ConSrvReleaseScreenBuffer(Buff, TRUE); - return STATUS_SUCCESS; -} - -CSR_API(SrvGetConsoleWindow) -{ - NTSTATUS Status; - PCONSOLE_GETWINDOW GetWindowRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetWindowRequest; - PCONSOLE Console; - - Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE); - if (!NT_SUCCESS(Status)) return Status; - - GetWindowRequest->WindowHandle = ConioGetConsoleWindowHandle(Console); - - ConSrvReleaseConsole(Console, TRUE); - return STATUS_SUCCESS; -} - -CSR_API(SrvSetConsoleIcon) -{ - NTSTATUS Status; - PCONSOLE_SETICON SetIconRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetIconRequest; - PCONSOLE Console; - - Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE); - if (!NT_SUCCESS(Status)) return Status; - - Status = (ConioChangeIcon(Console, SetIconRequest->WindowIcon) - ? STATUS_SUCCESS - : STATUS_UNSUCCESSFUL); + if (NT_SUCCESS(Status)) ConioChangeTitle(Console); ConSrvReleaseConsole(Console, TRUE); return Status; } +NTSTATUS NTAPI +ConDrvGetConsoleCP(IN PCONSOLE Console, + OUT PUINT CodePage, + IN BOOLEAN InputCP); CSR_API(SrvGetConsoleCP) { NTSTATUS Status; @@ -1580,15 +574,21 @@ CSR_API(SrvGetConsoleCP) Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE); if (!NT_SUCCESS(Status)) return Status; - ConsoleCPRequest->CodePage = (ConsoleCPRequest->InputCP ? Console->CodePage - : Console->OutputCodePage); + Status = ConDrvGetConsoleCP(Console, + &ConsoleCPRequest->CodePage, + ConsoleCPRequest->InputCP); + ConSrvReleaseConsole(Console, TRUE); - return STATUS_SUCCESS; + return Status; } +NTSTATUS NTAPI +ConDrvSetConsoleCP(IN PCONSOLE Console, + IN UINT CodePage, + IN BOOLEAN InputCP); CSR_API(SrvSetConsoleCP) { - NTSTATUS Status; + NTSTATUS Status = STATUS_INVALID_PARAMETER; PCONSOLE_GETSETINPUTOUTPUTCP ConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleCPRequest; PCONSOLE Console; @@ -1598,31 +598,24 @@ CSR_API(SrvSetConsoleCP) Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE); if (!NT_SUCCESS(Status)) return Status; - if (IsValidCodePage(ConsoleCPRequest->CodePage)) - { - if (ConsoleCPRequest->InputCP) - Console->CodePage = ConsoleCPRequest->CodePage; - else - Console->OutputCodePage = ConsoleCPRequest->CodePage; - - ConSrvReleaseConsole(Console, TRUE); - return STATUS_SUCCESS; - } + Status = ConDrvSetConsoleCP(Console, + ConsoleCPRequest->CodePage, + ConsoleCPRequest->InputCP); ConSrvReleaseConsole(Console, TRUE); - return STATUS_INVALID_PARAMETER; + return Status; } +NTSTATUS NTAPI +ConDrvGetConsoleProcessList(IN PCONSOLE Console, + IN OUT PULONG ProcessIdsList, + IN ULONG MaxIdListItems, + OUT PULONG ProcessIdsTotal); CSR_API(SrvGetConsoleProcessList) { NTSTATUS Status; PCONSOLE_GETPROCESSLIST GetProcessListRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetProcessListRequest; - PDWORD Buffer; - // PCSR_PROCESS Process = CsrGetClientThread()->Process; PCONSOLE Console; - PCONSOLE_PROCESS_DATA current; - PLIST_ENTRY current_entry; - ULONG nItems = 0; if (!CsrValidateMessageBuffer(ApiMessage, (PVOID)&GetProcessListRequest->pProcessIds, @@ -1632,26 +625,16 @@ CSR_API(SrvGetConsoleProcessList) return STATUS_INVALID_PARAMETER; } - Buffer = GetProcessListRequest->pProcessIds; - Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE); if (!NT_SUCCESS(Status)) return Status; - for (current_entry = Console->ProcessList.Flink; - current_entry != &Console->ProcessList; - current_entry = current_entry->Flink) - { - current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink); - if (++nItems <= GetProcessListRequest->nMaxIds) - { - *Buffer++ = HandleToUlong(current->Process->ClientId.UniqueProcess); - } - } + Status = ConDrvGetConsoleProcessList(Console, + GetProcessListRequest->pProcessIds, + GetProcessListRequest->nMaxIds, + &GetProcessListRequest->nProcessIdsTotal); ConSrvReleaseConsole(Console, TRUE); - - GetProcessListRequest->nProcessIdsTotal = nItems; - return STATUS_SUCCESS; + return Status; } CSR_API(SrvGenerateConsoleCtrlEvent) @@ -1663,7 +646,7 @@ CSR_API(SrvGenerateConsoleCtrlEvent) Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE); if (!NT_SUCCESS(Status)) return Status; - Status = ConSrvConsoleProcessCtrlEvent(Console, + Status = ConDrvConsoleProcessCtrlEvent(Console, GenerateCtrlEventRequest->ProcessGroup, GenerateCtrlEventRequest->Event); @@ -1671,22 +654,4 @@ CSR_API(SrvGenerateConsoleCtrlEvent) return Status; } -CSR_API(SrvGetConsoleSelectionInfo) -{ - NTSTATUS Status; - PCONSOLE_GETSELECTIONINFO GetSelectionInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetSelectionInfoRequest; - PCONSOLE Console; - - Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE); - if (NT_SUCCESS(Status)) - { - memset(&GetSelectionInfoRequest->Info, 0, sizeof(CONSOLE_SELECTION_INFO)); - if (Console->Selection.dwFlags != 0) - GetSelectionInfoRequest->Info = Console->Selection; - ConSrvReleaseConsole(Console, TRUE); - } - - return Status; -} - /* EOF */ diff --git a/reactos/win32ss/user/consrv/console.h b/reactos/win32ss/user/consrv/console.h index 3a802671581..b471eef8731 100644 --- a/reactos/win32ss/user/consrv/console.h +++ b/reactos/win32ss/user/consrv/console.h @@ -8,16 +8,44 @@ #pragma once -VOID WINAPI ConSrvInitConsoleSupport(VOID); +VOID NTAPI +ConDrvInitConsoleSupport(VOID); -NTSTATUS WINAPI ConSrvInitConsole(OUT struct _CONSOLE** /* PCONSOLE* */ NewConsole, - IN OUT PCONSOLE_START_INFO ConsoleStartInfo, - IN PCSR_PROCESS ConsoleLeaderProcess); +NTSTATUS WINAPI +ConSrvInitConsole(OUT struct _CONSOLE** /* PCONSOLE* */ NewConsole, + IN OUT PCONSOLE_START_INFO ConsoleStartInfo, + IN ULONG ConsoleLeaderProcessId); VOID WINAPI ConSrvDeleteConsole(struct _CONSOLE* /* PCONSOLE */ Console); + NTSTATUS FASTCALL ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData, struct _CONSOLE** /* PCONSOLE* */ Console, BOOL LockConsole); VOID FASTCALL ConSrvReleaseConsole(struct _CONSOLE* /* PCONSOLE */ Console, BOOL WasConsoleLocked); +/******************************************************************************/ + +NTSTATUS NTAPI +ConDrvGrabConsole(IN struct _CONSOLE* /* PCONSOLE */ Console, + IN BOOLEAN LockConsole); +VOID NTAPI +ConDrvReleaseConsole(IN struct _CONSOLE* /* PCONSOLE */ Console, + IN BOOLEAN WasConsoleLocked); + +typedef struct _FRONTEND FRONTEND, *PFRONTEND; +typedef struct _CONSOLE_INFO CONSOLE_INFO, *PCONSOLE_INFO; + +NTSTATUS NTAPI +ConDrvInitConsole(OUT struct _CONSOLE** /* PCONSOLE* */ NewConsole, + // IN OUT PCONSOLE_START_INFO ConsoleStartInfo, + IN PCONSOLE_INFO ConsoleInfo, + IN ULONG ConsoleLeaderProcessId); +NTSTATUS NTAPI +ConDrvRegisterFrontEnd(IN struct _CONSOLE* /* PCONSOLE */ Console, + IN PFRONTEND FrontEnd); +NTSTATUS NTAPI +ConDrvDeregisterFrontEnd(IN struct _CONSOLE* /* PCONSOLE */ Console); +VOID NTAPI +ConDrvDeleteConsole(IN struct _CONSOLE* /* PCONSOLE */ Console); + /* EOF */ diff --git a/reactos/win32ss/user/consrv/frontendctl.c b/reactos/win32ss/user/consrv/frontendctl.c new file mode 100644 index 00000000000..454702f9900 --- /dev/null +++ b/reactos/win32ss/user/consrv/frontendctl.c @@ -0,0 +1,379 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Console Server DLL + * FILE: win32ss/user/consrv/frontendctl.c + * PURPOSE: Terminal Front-Ends Control + * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr) + */ + +/* INCLUDES *******************************************************************/ + +#include "consrv.h" +#include "include/conio.h" +#include "conio.h" +#include "conoutput.h" +#include "console.h" +#include "handle.h" + +#define NDEBUG +#include + + +/* PRIVATE FUNCTIONS **********************************************************/ + + +/* PUBLIC SERVER APIS *********************************************************/ + +/********************************************************************** + * HardwareStateProperty + * + * DESCRIPTION + * Set/Get the value of the HardwareState and switch + * between direct video buffer ouput and GDI windowed + * output. + * ARGUMENTS + * Client hands us a CONSOLE_GETSETHWSTATE object. + * We use the same object to Request. + * NOTE + * ConsoleHwState has the correct size to be compatible + * with NT's, but values are not. + */ +#if 0 +static NTSTATUS FASTCALL +SetConsoleHardwareState(PCONSOLE Console, ULONG ConsoleHwState) +{ + DPRINT1("Console Hardware State: %d\n", ConsoleHwState); + + if ((CONSOLE_HARDWARE_STATE_GDI_MANAGED == ConsoleHwState) + ||(CONSOLE_HARDWARE_STATE_DIRECT == ConsoleHwState)) + { + if (Console->HardwareState != ConsoleHwState) + { + /* TODO: implement switching from full screen to windowed mode */ + /* TODO: or back; now simply store the hardware state */ + Console->HardwareState = ConsoleHwState; + } + + return STATUS_SUCCESS; + } + + return STATUS_INVALID_PARAMETER_3; /* Client: (handle, set_get, [mode]) */ +} +#endif + +CSR_API(SrvGetConsoleHardwareState) +{ +#if 0 + NTSTATUS Status; + PCONSOLE_GETSETHWSTATE HardwareStateRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.HardwareStateRequest; + PCONSOLE_SCREEN_BUFFER Buff; + PCONSOLE Console; + + Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), + HardwareStateRequest->OutputHandle, + &Buff, + GENERIC_READ, + TRUE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to get console handle in SrvGetConsoleHardwareState\n"); + return Status; + } + + Console = Buff->Header.Console; + HardwareStateRequest->State = Console->HardwareState; + + ConSrvReleaseScreenBuffer(Buff, TRUE); + return Status; +#else + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +#endif +} + +CSR_API(SrvSetConsoleHardwareState) +{ +#if 0 + NTSTATUS Status; + PCONSOLE_GETSETHWSTATE HardwareStateRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.HardwareStateRequest; + PCONSOLE_SCREEN_BUFFER Buff; + PCONSOLE Console; + + Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), + HardwareStateRequest->OutputHandle, + &Buff, + GENERIC_WRITE, + TRUE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to get console handle in SrvSetConsoleHardwareState\n"); + return Status; + } + + DPRINT("Setting console hardware state.\n"); + Console = Buff->Header.Console; + Status = SetConsoleHardwareState(Console, HardwareStateRequest->State); + + ConSrvReleaseScreenBuffer(Buff, TRUE); + return Status; +#else + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +#endif +} + +CSR_API(SrvGetConsoleDisplayMode) +{ + NTSTATUS Status; + PCONSOLE_GETDISPLAYMODE GetDisplayModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetDisplayModeRequest; + PCONSOLE Console; + + Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), + &Console, TRUE); + if (!NT_SUCCESS(Status)) return Status; + + GetDisplayModeRequest->DisplayMode = ConioGetDisplayMode(Console); + + ConSrvReleaseConsole(Console, TRUE); + return STATUS_SUCCESS; +} + +CSR_API(SrvSetConsoleDisplayMode) +{ + NTSTATUS Status; + PCONSOLE_SETDISPLAYMODE SetDisplayModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetDisplayModeRequest; + PCONSOLE Console; + PCONSOLE_SCREEN_BUFFER Buff; + + Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), + SetDisplayModeRequest->OutputHandle, + &Buff, + GENERIC_WRITE, + TRUE); + if (!NT_SUCCESS(Status)) return Status; + + Console = Buff->Header.Console; + + if (ConioSetDisplayMode(Console, SetDisplayModeRequest->DisplayMode)) + { + SetDisplayModeRequest->NewSBDim = Buff->ScreenBufferSize; + Status = STATUS_SUCCESS; + } + else + { + Status = STATUS_INVALID_PARAMETER; + } + + ConSrvReleaseScreenBuffer(Buff, TRUE); + return Status; +} + +CSR_API(SrvGetLargestConsoleWindowSize) +{ + NTSTATUS Status; + PCONSOLE_GETLARGESTWINDOWSIZE GetLargestWindowSizeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetLargestWindowSizeRequest; + PCONSOLE_SCREEN_BUFFER Buff; + PCONSOLE Console; + + Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), + GetLargestWindowSizeRequest->OutputHandle, + &Buff, + GENERIC_READ, + TRUE); + if (!NT_SUCCESS(Status)) return Status; + + Console = Buff->Header.Console; + ConioGetLargestConsoleWindowSize(Console, &GetLargestWindowSizeRequest->Size); + + ConSrvReleaseScreenBuffer(Buff, TRUE); + return STATUS_SUCCESS; +} + +CSR_API(SrvShowConsoleCursor) +{ + NTSTATUS Status; + PCONSOLE_SHOWCURSOR ShowCursorRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ShowCursorRequest; + PCONSOLE Console; + PCONSOLE_SCREEN_BUFFER Buff; + + Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), + ShowCursorRequest->OutputHandle, + &Buff, + GENERIC_WRITE, + TRUE); + if (!NT_SUCCESS(Status)) return Status; + + Console = Buff->Header.Console; + + ShowCursorRequest->RefCount = ConioShowMouseCursor(Console, ShowCursorRequest->Show); + + ConSrvReleaseScreenBuffer(Buff, TRUE); + return STATUS_SUCCESS; +} + +CSR_API(SrvSetConsoleCursor) +{ + NTSTATUS Status; + BOOL Success; + PCONSOLE_SETCURSOR SetCursorRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetCursorRequest; + PCONSOLE Console; + PCONSOLE_SCREEN_BUFFER Buff; + + // FIXME: Tests show that this function is used only for graphics screen buffers + // and otherwise it returns false + set last error to invalid handle. + // NOTE: I find that behaviour is ridiculous but ok, let's accept that at the moment... + Status = ConSrvGetGraphicsBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), + SetCursorRequest->OutputHandle, + &Buff, + GENERIC_WRITE, + TRUE); + if (!NT_SUCCESS(Status)) return Status; + + Console = Buff->Header.Console; + + Success = ConioSetMouseCursor(Console, SetCursorRequest->hCursor); + + ConSrvReleaseScreenBuffer(Buff, TRUE); + return (Success ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL); +} + +CSR_API(SrvConsoleMenuControl) +{ + NTSTATUS Status; + PCONSOLE_MENUCONTROL MenuControlRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.MenuControlRequest; + PCONSOLE Console; + PCONSOLE_SCREEN_BUFFER Buff; + + Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), + MenuControlRequest->OutputHandle, + &Buff, + GENERIC_WRITE, + TRUE); + if (!NT_SUCCESS(Status)) return Status; + + Console = Buff->Header.Console; + + MenuControlRequest->hMenu = ConioMenuControl(Console, + MenuControlRequest->dwCmdIdLow, + MenuControlRequest->dwCmdIdHigh); + + ConSrvReleaseScreenBuffer(Buff, TRUE); + return STATUS_SUCCESS; +} + +CSR_API(SrvSetConsoleMenuClose) +{ + NTSTATUS Status; + BOOL Success; + PCONSOLE_SETMENUCLOSE SetMenuCloseRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetMenuCloseRequest; + PCONSOLE Console; + + Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), + &Console, TRUE); + if (!NT_SUCCESS(Status)) return Status; + + Success = ConioSetMenuClose(Console, SetMenuCloseRequest->Enable); + + ConSrvReleaseConsole(Console, TRUE); + return (Success ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL); +} + +CSR_API(SrvSetConsoleWindowInfo) +{ + NTSTATUS Status; + PCONSOLE_SETWINDOWINFO SetWindowInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetWindowInfoRequest; + PCONSOLE_SCREEN_BUFFER Buff; + SMALL_RECT WindowRect = SetWindowInfoRequest->WindowRect; + + DPRINT("SrvSetConsoleWindowInfo(0x%08x, %d, {L%d, T%d, R%d, B%d}) called\n", + SetWindowInfoRequest->OutputHandle, SetWindowInfoRequest->Absolute, + WindowRect.Left, WindowRect.Top, WindowRect.Right, WindowRect.Bottom); + + Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), + SetWindowInfoRequest->OutputHandle, + &Buff, + GENERIC_READ, + TRUE); + if (!NT_SUCCESS(Status)) return Status; + + if (SetWindowInfoRequest->Absolute == FALSE) + { + /* Relative positions given. Transform them to absolute ones */ + WindowRect.Left += Buff->ViewOrigin.X; + WindowRect.Top += Buff->ViewOrigin.Y; + WindowRect.Right += Buff->ViewOrigin.X + Buff->ViewSize.X - 1; + WindowRect.Bottom += Buff->ViewOrigin.Y + Buff->ViewSize.Y - 1; + } + + /* See MSDN documentation on SetConsoleWindowInfo about the performed checks */ + if ( (WindowRect.Left < 0) || (WindowRect.Top < 0) || + (WindowRect.Right >= Buff->ScreenBufferSize.X) || + (WindowRect.Bottom >= Buff->ScreenBufferSize.Y) || + (WindowRect.Right <= WindowRect.Left) || + (WindowRect.Bottom <= WindowRect.Top) ) + { + ConSrvReleaseScreenBuffer(Buff, TRUE); + return STATUS_INVALID_PARAMETER; + } + + Buff->ViewOrigin.X = WindowRect.Left; + Buff->ViewOrigin.Y = WindowRect.Top; + + Buff->ViewSize.X = WindowRect.Right - WindowRect.Left + 1; + Buff->ViewSize.Y = WindowRect.Bottom - WindowRect.Top + 1; + + ConSrvReleaseScreenBuffer(Buff, TRUE); + return STATUS_SUCCESS; +} + +CSR_API(SrvGetConsoleWindow) +{ + NTSTATUS Status; + PCONSOLE_GETWINDOW GetWindowRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetWindowRequest; + PCONSOLE Console; + + Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE); + if (!NT_SUCCESS(Status)) return Status; + + GetWindowRequest->WindowHandle = ConioGetConsoleWindowHandle(Console); + + ConSrvReleaseConsole(Console, TRUE); + return STATUS_SUCCESS; +} + +CSR_API(SrvSetConsoleIcon) +{ + NTSTATUS Status; + PCONSOLE_SETICON SetIconRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetIconRequest; + PCONSOLE Console; + + Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE); + if (!NT_SUCCESS(Status)) return Status; + + Status = (ConioChangeIcon(Console, SetIconRequest->WindowIcon) + ? STATUS_SUCCESS + : STATUS_UNSUCCESSFUL); + + ConSrvReleaseConsole(Console, TRUE); + return Status; +} + +CSR_API(SrvGetConsoleSelectionInfo) +{ + NTSTATUS Status; + PCONSOLE_GETSELECTIONINFO GetSelectionInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetSelectionInfoRequest; + PCONSOLE Console; + + Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE); + if (NT_SUCCESS(Status)) + { + memset(&GetSelectionInfoRequest->Info, 0, sizeof(CONSOLE_SELECTION_INFO)); + if (Console->Selection.dwFlags != 0) + GetSelectionInfoRequest->Info = Console->Selection; + ConSrvReleaseConsole(Console, TRUE); + } + + return Status; +} + +/* EOF */ diff --git a/reactos/win32ss/user/consrv/frontends/gui/guiterm.c b/reactos/win32ss/user/consrv/frontends/gui/guiterm.c index 53485d49d4a..07398eaddde 100644 --- a/reactos/win32ss/user/consrv/frontends/gui/guiterm.c +++ b/reactos/win32ss/user/consrv/frontends/gui/guiterm.c @@ -11,16 +11,23 @@ /* INCLUDES *******************************************************************/ +#define COBJMACROS +#define NONAMELESSUNION + #include "consrv.h" #include "include/conio.h" #include "include/console.h" #include "include/settings.h" +#include "conoutput.h" #include "guiterm.h" #include "guisettings.h" #include "resource.h" #include +#include +#include + #define NDEBUG #include @@ -49,6 +56,13 @@ PrivateCsrssManualGuiCheck(LONG Check) /* GLOBALS ********************************************************************/ +typedef struct _GUI_INIT_INFO +{ + PCONSOLE_INFO ConsoleInfo; + PCONSOLE_START_INFO ConsoleStartInfo; + ULONG ProcessId; +} GUI_INIT_INFO, *PGUI_INIT_INFO; + /**************************************************************\ \** Define the Console Leader Process for the console window **/ #define GWLP_CONSOLEWND_ALLOC (2 * sizeof(LONG_PTR)) @@ -212,7 +226,7 @@ GuiConsolePaste(PGUI_CONSOLE_DATA GuiData); static VOID GuiConsoleUpdateSelection(PCONSOLE Console, PCOORD coord); static VOID WINAPI -GuiDrawRegion(PCONSOLE Console, SMALL_RECT* Region); +GuiDrawRegion(IN OUT PFRONTEND This, SMALL_RECT* Region); static VOID GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData); @@ -224,12 +238,12 @@ GuiConsoleHandleSysMenuCommand(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM PCONSOLE Console = GuiData->Console; PCONSOLE_SCREEN_BUFFER ActiveBuffer; - if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) + if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) { Ret = FALSE; goto Quit; } - ActiveBuffer = Console->ActiveBuffer; + ActiveBuffer = ConDrvGetActiveScreenBuffer(Console); /* * In case the selected menu item belongs to the user-reserved menu id range, @@ -354,7 +368,7 @@ static VOID GuiConsoleResizeWindow(PGUI_CONSOLE_DATA GuiData) { PCONSOLE Console = GuiData->Console; - PCONSOLE_SCREEN_BUFFER Buff = Console->ActiveBuffer; + PCONSOLE_SCREEN_BUFFER Buff = ConDrvGetActiveScreenBuffer(Console); SCROLLINFO sInfo; DWORD Width, Height; @@ -421,7 +435,7 @@ GuiConsoleSwitchFullScreen(PGUI_CONSOLE_DATA GuiData) PCONSOLE Console = GuiData->Console; // DEVMODE dmScreenSettings; - if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return; + if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return; /* Switch to full-screen or to windowed mode */ GuiData->GuiInfo.FullScreen = !GuiData->GuiInfo.FullScreen; @@ -559,7 +573,7 @@ static VOID SmallRectToRect(PGUI_CONSOLE_DATA GuiData, PRECT Rect, PSMALL_RECT SmallRect) { PCONSOLE Console = GuiData->Console; - PCONSOLE_SCREEN_BUFFER Buffer = Console->ActiveBuffer; + PCONSOLE_SCREEN_BUFFER Buffer = ConDrvGetActiveScreenBuffer(Console); UINT WidthUnit, HeightUnit; if (GetType(Buffer) == TEXTMODE_BUFFER) @@ -661,12 +675,12 @@ GuiConsoleHandlePaint(PGUI_CONSOLE_DATA GuiData) HDC hDC; PAINTSTRUCT ps; - if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) + if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) { Success = FALSE; goto Quit; } - ActiveBuffer = Console->ActiveBuffer; + ActiveBuffer = ConDrvGetActiveScreenBuffer(Console); hDC = BeginPaint(GuiData->hWindow, &ps); if (hDC != NULL && @@ -745,9 +759,9 @@ GuiConsoleHandleKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM l PCONSOLE Console = GuiData->Console; PCONSOLE_SCREEN_BUFFER ActiveBuffer; - if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return; + if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return; - ActiveBuffer = Console->ActiveBuffer; + ActiveBuffer = ConDrvGetActiveScreenBuffer(Console); if (Console->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) { @@ -903,10 +917,10 @@ Quit: } static VOID -GuiInvalidateCell(PCONSOLE Console, SHORT x, SHORT y) +GuiInvalidateCell(IN OUT PFRONTEND This, SHORT x, SHORT y) { SMALL_RECT CellRect = { x, y, x, y }; - GuiDrawRegion(Console, &CellRect); + GuiDrawRegion(This, &CellRect); } static VOID @@ -917,13 +931,13 @@ GuiConsoleHandleTimer(PGUI_CONSOLE_DATA GuiData) SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CURSOR_BLINK_TIME, NULL); - if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return; + if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return; - Buff = Console->ActiveBuffer; + Buff = ConDrvGetActiveScreenBuffer(Console); if (GetType(Buff) == TEXTMODE_BUFFER) { - GuiInvalidateCell(Console, Buff->CursorPosition.X, Buff->CursorPosition.Y); + GuiInvalidateCell(&Console->TermIFace, Buff->CursorPosition.X, Buff->CursorPosition.Y); Buff->CursorBlinkOn = !Buff->CursorBlinkOn; if ((GuiData->OldCursor.x != Buff->CursorPosition.X) || (GuiData->OldCursor.y != Buff->CursorPosition.Y)) @@ -1006,35 +1020,36 @@ GuiConsoleHandleTimer(PGUI_CONSOLE_DATA GuiData) LeaveCriticalSection(&Console->Lock); } -static VOID +static BOOL GuiConsoleHandleClose(PGUI_CONSOLE_DATA GuiData) { PCONSOLE Console = GuiData->Console; - if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return; + + if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) + return TRUE; + + // TODO: Prompt for termination ? (Warn the user about possible apps running in this console) /* * FIXME: Windows will wait up to 5 seconds for the thread to exit. * We shouldn't wait here, though, since the console lock is entered. * A copy of the thread list probably needs to be made. */ - ConSrvConsoleProcessCtrlEvent(Console, 0, CTRL_CLOSE_EVENT); + ConDrvConsoleProcessCtrlEvent(Console, 0, CTRL_CLOSE_EVENT); LeaveCriticalSection(&Console->Lock); + return FALSE; } static LRESULT GuiConsoleHandleNcDestroy(HWND hWnd) { - // PGUI_CONSOLE_DATA GuiData; - KillTimer(hWnd, CONGUI_UPDATE_TIMER); GetSystemMenu(hWnd, TRUE); /* Free the GuiData registration */ SetWindowLongPtrW(hWnd, GWLP_USERDATA, (DWORD_PTR)NULL); - // GuiData->hWindow = NULL; - // return 0; return DefWindowProcW(hWnd, WM_NCDESTROY, 0, 0); } @@ -1042,7 +1057,7 @@ static COORD PointToCoord(PGUI_CONSOLE_DATA GuiData, LPARAM lParam) { PCONSOLE Console = GuiData->Console; - PCONSOLE_SCREEN_BUFFER Buffer = Console->ActiveBuffer; + PCONSOLE_SCREEN_BUFFER Buffer = ConDrvGetActiveScreenBuffer(Console); COORD Coord; UINT WidthUnit, HeightUnit; @@ -1103,7 +1118,7 @@ GuiConsoleHandleMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM goto Quit; } - if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) + if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) { Err = TRUE; goto Quit; @@ -1330,7 +1345,7 @@ GuiConsoleCopy(PGUI_CONSOLE_DATA GuiData) if (OpenClipboard(GuiData->hWindow) == TRUE) { PCONSOLE Console = GuiData->Console; - PCONSOLE_SCREEN_BUFFER Buffer = Console->ActiveBuffer; + PCONSOLE_SCREEN_BUFFER Buffer = ConDrvGetActiveScreenBuffer(Console); if (GetType(Buffer) == TEXTMODE_BUFFER) { @@ -1358,7 +1373,7 @@ GuiConsolePaste(PGUI_CONSOLE_DATA GuiData) if (OpenClipboard(GuiData->hWindow) == TRUE) { PCONSOLE Console = GuiData->Console; - PCONSOLE_SCREEN_BUFFER Buffer = Console->ActiveBuffer; + PCONSOLE_SCREEN_BUFFER Buffer = ConDrvGetActiveScreenBuffer(Console); if (GetType(Buffer) == TEXTMODE_BUFFER) { @@ -1381,9 +1396,9 @@ GuiConsoleGetMinMaxInfo(PGUI_CONSOLE_DATA GuiData, PMINMAXINFO minMaxInfo) DWORD windx, windy; UINT WidthUnit, HeightUnit; - if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return; + if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return; - ActiveBuffer = Console->ActiveBuffer; + ActiveBuffer = ConDrvGetActiveScreenBuffer(Console); if (GetType(ActiveBuffer) == TEXTMODE_BUFFER) { @@ -1419,12 +1434,12 @@ GuiConsoleResize(PGUI_CONSOLE_DATA GuiData, WPARAM wParam, LPARAM lParam) { PCONSOLE Console = GuiData->Console; - if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return; + if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return; if ((GuiData->WindowSizeLock == FALSE) && (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED || wParam == SIZE_MINIMIZED)) { - PCONSOLE_SCREEN_BUFFER Buff = Console->ActiveBuffer; + PCONSOLE_SCREEN_BUFFER Buff = ConDrvGetActiveScreenBuffer(Console); DWORD windx, windy, charx, chary; UINT WidthUnit, HeightUnit; @@ -1525,9 +1540,9 @@ GuiConsoleHandleScroll(PGUI_CONSOLE_DATA GuiData, UINT uMsg, WPARAM wParam) int old_pos, Maximum; PSHORT pShowXY; - if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return 0; + if (!ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) return 0; - Buff = Console->ActiveBuffer; + Buff = ConDrvGetActiveScreenBuffer(Console); if (uMsg == WM_HSCROLL) { @@ -1659,7 +1674,7 @@ GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) * If there is no data, just go away. */ GuiData = GuiGetGuiData(hWnd); - if (GuiData == NULL) return 0; + if (GuiData == NULL) return DefWindowProcW(hWnd, msg, wParam, lParam); /* * Just retrieve a pointer to the console in case somebody needs it. @@ -1678,7 +1693,7 @@ GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) } case WM_CLOSE: - GuiConsoleHandleClose(GuiData); + if (GuiConsoleHandleClose(GuiData)) goto Default; break; case WM_PAINT: @@ -1846,7 +1861,7 @@ GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) IsClipboardFormatAvailable(CF_UNICODETEXT) ? MF_ENABLED : MF_GRAYED)); } - if (ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) + if (ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) { GuiSendMenuEvent(Console, WM_INITMENU); LeaveCriticalSection(&Console->Lock); @@ -1858,7 +1873,7 @@ GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { if (HIWORD(wParam) == 0xFFFF) // Allow all the menu flags { - if (ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) + if (ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) { GuiSendMenuEvent(Console, WM_MENUSELECT); LeaveCriticalSection(&Console->Lock); @@ -1877,7 +1892,7 @@ GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_SETFOCUS: case WM_KILLFOCUS: { - if (ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) + if (ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) { INPUT_RECORD er; er.EventType = FOCUS_EVENT; @@ -1913,7 +1928,7 @@ GuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) case PM_APPLY_CONSOLE_INFO: { - if (ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) + if (ConDrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE)) { GuiApplyUserSettings(GuiData, (HANDLE)wParam, (BOOL)lParam); LeaveCriticalSection(&Console->Lock); @@ -2219,9 +2234,190 @@ GuiInit(VOID) ******************************************************************************/ static VOID WINAPI -GuiCleanupConsole(PCONSOLE Console) +GuiDeinitFrontEnd(IN OUT PFRONTEND This); + +NTSTATUS NTAPI +GuiInitFrontEnd(IN OUT PFRONTEND This, + IN PCONSOLE Console) { - PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data; + PGUI_INIT_INFO GuiInitInfo; + PCONSOLE_INFO ConsoleInfo; + PCONSOLE_START_INFO ConsoleStartInfo; + + PGUI_CONSOLE_DATA GuiData; + GUI_CONSOLE_INFO TermInfo; + + SIZE_T Length = 0; + LPWSTR IconPath = NULL; + INT IconIndex = 0; + + if (This == NULL || Console == NULL || This->OldData == NULL) + return STATUS_INVALID_PARAMETER; + + ASSERT(This->Console == Console); + + GuiInitInfo = This->OldData; + + if (GuiInitInfo->ConsoleInfo == NULL || GuiInitInfo->ConsoleStartInfo == NULL) + return STATUS_INVALID_PARAMETER; + + ConsoleInfo = GuiInitInfo->ConsoleInfo; + ConsoleStartInfo = GuiInitInfo->ConsoleStartInfo; + + IconPath = ConsoleStartInfo->IconPath; + IconIndex = ConsoleStartInfo->IconIndex; + + + /* Terminal data allocation */ + GuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(GUI_CONSOLE_DATA)); + if (!GuiData) + { + DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n"); + return STATUS_UNSUCCESSFUL; + } + /* HACK */ Console->TermIFace.Data = (PVOID)GuiData; /* HACK */ + GuiData->Console = Console; + GuiData->hWindow = NULL; + + /* The console can be resized */ + Console->FixedSize = FALSE; + + InitializeCriticalSection(&GuiData->Lock); + + + /* + * Load terminal settings + */ + + /* 1. Load the default settings */ + GuiConsoleGetDefaultSettings(&TermInfo, GuiInitInfo->ProcessId); + + /* 3. Load the remaining console settings via the registry. */ + if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0) + { + /* Load the terminal infos from the registry. */ + GuiConsoleReadUserSettings(&TermInfo, + ConsoleInfo->ConsoleTitle, + GuiInitInfo->ProcessId); + + /* + * Now, update them with the properties the user might gave to us + * via the STARTUPINFO structure before calling CreateProcess + * (and which was transmitted via the ConsoleStartInfo structure). + * We therefore overwrite the values read in the registry. + */ + if (ConsoleStartInfo->dwStartupFlags & STARTF_USESHOWWINDOW) + { + TermInfo.ShowWindow = ConsoleStartInfo->ShowWindow; + } + if (ConsoleStartInfo->dwStartupFlags & STARTF_USEPOSITION) + { + TermInfo.AutoPosition = FALSE; + TermInfo.WindowOrigin = ConsoleStartInfo->ConsoleWindowOrigin; + } + if (ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN) + { + TermInfo.FullScreen = TRUE; + } + } + + + /* + * Set up GUI data + */ + + Length = min(wcslen(TermInfo.FaceName) + 1, LF_FACESIZE); // wcsnlen + wcsncpy(GuiData->GuiInfo.FaceName, TermInfo.FaceName, LF_FACESIZE); + GuiData->GuiInfo.FaceName[Length] = L'\0'; + GuiData->GuiInfo.FontFamily = TermInfo.FontFamily; + GuiData->GuiInfo.FontSize = TermInfo.FontSize; + GuiData->GuiInfo.FontWeight = TermInfo.FontWeight; + GuiData->GuiInfo.UseRasterFonts = TermInfo.UseRasterFonts; + GuiData->GuiInfo.FullScreen = TermInfo.FullScreen; + GuiData->GuiInfo.ShowWindow = TermInfo.ShowWindow; + GuiData->GuiInfo.AutoPosition = TermInfo.AutoPosition; + GuiData->GuiInfo.WindowOrigin = TermInfo.WindowOrigin; + + /* Initialize the icon handles to their default values */ + GuiData->hIcon = ghDefaultIcon; + GuiData->hIconSm = ghDefaultIconSm; + + /* Get the associated icon, if any */ + if (IconPath == NULL || IconPath[0] == L'\0') + { + IconPath = ConsoleStartInfo->AppPath; + IconIndex = 0; + } + DPRINT("IconPath = %S ; IconIndex = %lu\n", (IconPath ? IconPath : L"n/a"), IconIndex); + if (IconPath && IconPath[0] != L'\0') + { + HICON hIcon = NULL, hIconSm = NULL; + PrivateExtractIconExW(IconPath, + IconIndex, + &hIcon, + &hIconSm, + 1); + DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon, hIconSm); + if (hIcon != NULL) + { + DPRINT("Effectively set the icons\n"); + GuiData->hIcon = hIcon; + GuiData->hIconSm = hIconSm; + } + } + + /* Mouse is shown by default with its default cursor shape */ + GuiData->hCursor = ghDefaultCursor; + GuiData->MouseCursorRefCount = 0; + + /* A priori don't ignore mouse signals */ + GuiData->IgnoreNextMouseSignal = FALSE; + + /* Close button and the corresponding system menu item are enabled by default */ + GuiData->IsCloseButtonEnabled = TRUE; + + /* There is no user-reserved menu id range by default */ + GuiData->cmdIdLow = GuiData->cmdIdHigh = 0; + + /* + * We need to wait until the GUI has been fully initialized + * to retrieve custom settings i.e. WindowSize etc... + * Ideally we could use SendNotifyMessage for this but its not + * yet implemented. + */ + GuiData->hGuiInitEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + + DPRINT("GUI - Checkpoint\n"); + + /* Create the terminal window */ + PostMessageW(NotifyWnd, PM_CREATE_CONSOLE, GuiData->GuiInfo.ShowWindow, (LPARAM)GuiData); + + /* Wait until initialization has finished */ + WaitForSingleObject(GuiData->hGuiInitEvent, INFINITE); + DPRINT("OK we created the console window\n"); + CloseHandle(GuiData->hGuiInitEvent); + GuiData->hGuiInitEvent = NULL; + + /* Check whether we really succeeded in initializing the terminal window */ + if (GuiData->hWindow == NULL) + { + DPRINT("GuiInitConsole - We failed at creating a new terminal window\n"); + GuiDeinitFrontEnd(This); + return STATUS_UNSUCCESSFUL; + } + + /* Finally, finish to initialize the frontend structure */ + This->Data = GuiData; + if (This->OldData) ConsoleFreeHeap(This->OldData); + This->OldData = NULL; + + return STATUS_SUCCESS; +} + +static VOID WINAPI +GuiDeinitFrontEnd(IN OUT PFRONTEND This) +{ + PGUI_CONSOLE_DATA GuiData = This->Data; SendMessageW(NotifyWnd, PM_DESTROY_CONSOLE, 0, (LPARAM)GuiData); @@ -2238,17 +2434,18 @@ GuiCleanupConsole(PCONSOLE Console) DestroyIcon(GuiData->hIconSm); } - Console->TermIFace.Data = NULL; + This->Data = NULL; DeleteCriticalSection(&GuiData->Lock); ConsoleFreeHeap(GuiData); - DPRINT("Quit GuiCleanupConsole\n"); + DPRINT("Quit GuiDeinitFrontEnd\n"); } static VOID WINAPI -GuiDrawRegion(PCONSOLE Console, SMALL_RECT* Region) +GuiDrawRegion(IN OUT PFRONTEND This, + SMALL_RECT* Region) { - PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data; + PGUI_CONSOLE_DATA GuiData = This->Data; RECT RegionRect; SmallRectToRect(GuiData, &RegionRect, Region); @@ -2257,15 +2454,22 @@ GuiDrawRegion(PCONSOLE Console, SMALL_RECT* Region) } static VOID WINAPI -GuiWriteStream(PCONSOLE Console, SMALL_RECT* Region, SHORT CursorStartX, SHORT CursorStartY, - UINT ScrolledLines, PWCHAR Buffer, UINT Length) +GuiWriteStream(IN OUT PFRONTEND This, + SMALL_RECT* Region, + SHORT CursorStartX, + SHORT CursorStartY, + UINT ScrolledLines, + PWCHAR Buffer, + UINT Length) { - PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data; - PCONSOLE_SCREEN_BUFFER Buff = Console->ActiveBuffer; + PGUI_CONSOLE_DATA GuiData = This->Data; + PCONSOLE_SCREEN_BUFFER Buff; SHORT CursorEndX, CursorEndY; RECT ScrollRect; if (NULL == GuiData || NULL == GuiData->hWindow) return; + + Buff = ConDrvGetActiveScreenBuffer(GuiData->Console); if (GetType(Buff) != TEXTMODE_BUFFER) return; if (0 != ScrolledLines) @@ -2285,12 +2489,12 @@ GuiWriteStream(PCONSOLE Console, SMALL_RECT* Region, SHORT CursorStartX, SHORT C SW_INVALIDATE); } - GuiDrawRegion(Console, Region); + GuiDrawRegion(This, Region); if (CursorStartX < Region->Left || Region->Right < CursorStartX || CursorStartY < Region->Top || Region->Bottom < CursorStartY) { - GuiInvalidateCell(Console, CursorStartX, CursorStartY); + GuiInvalidateCell(This, CursorStartX, CursorStartY); } CursorEndX = Buff->CursorPosition.X; @@ -2299,7 +2503,7 @@ GuiWriteStream(PCONSOLE Console, SMALL_RECT* Region, SHORT CursorStartX, SHORT C || CursorEndY < Region->Top || Region->Bottom < CursorEndY) && (CursorEndX != CursorStartX || CursorEndY != CursorStartY)) { - GuiInvalidateCell(Console, CursorEndX, CursorEndY); + GuiInvalidateCell(This, CursorEndX, CursorEndY); } // Set up the update timer (very short interval) - this is a "hack" for getting the OS to @@ -2309,34 +2513,42 @@ GuiWriteStream(PCONSOLE Console, SMALL_RECT* Region, SHORT CursorStartX, SHORT C } static BOOL WINAPI -GuiSetCursorInfo(PCONSOLE Console, PCONSOLE_SCREEN_BUFFER Buff) +GuiSetCursorInfo(IN OUT PFRONTEND This, + PCONSOLE_SCREEN_BUFFER Buff) { - if (Console->ActiveBuffer == Buff) + PGUI_CONSOLE_DATA GuiData = This->Data; + + if (ConDrvGetActiveScreenBuffer(GuiData->Console) == Buff) { - GuiInvalidateCell(Console, Buff->CursorPosition.X, Buff->CursorPosition.Y); + GuiInvalidateCell(This, Buff->CursorPosition.X, Buff->CursorPosition.Y); } return TRUE; } static BOOL WINAPI -GuiSetScreenInfo(PCONSOLE Console, PCONSOLE_SCREEN_BUFFER Buff, SHORT OldCursorX, SHORT OldCursorY) +GuiSetScreenInfo(IN OUT PFRONTEND This, + PCONSOLE_SCREEN_BUFFER Buff, + SHORT OldCursorX, + SHORT OldCursorY) { - if (Console->ActiveBuffer == Buff) + PGUI_CONSOLE_DATA GuiData = This->Data; + + if (ConDrvGetActiveScreenBuffer(GuiData->Console) == Buff) { /* Redraw char at old position (remove cursor) */ - GuiInvalidateCell(Console, OldCursorX, OldCursorY); + GuiInvalidateCell(This, OldCursorX, OldCursorY); /* Redraw char at new position (show cursor) */ - GuiInvalidateCell(Console, Buff->CursorPosition.X, Buff->CursorPosition.Y); + GuiInvalidateCell(This, Buff->CursorPosition.X, Buff->CursorPosition.Y); } return TRUE; } static VOID WINAPI -GuiResizeTerminal(PCONSOLE Console) +GuiResizeTerminal(IN OUT PFRONTEND This) { - PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data; + PGUI_CONSOLE_DATA GuiData = This->Data; /* Resize the window to the user's values */ // GuiData->WindowSizeLock = TRUE; @@ -2348,7 +2560,12 @@ GuiResizeTerminal(PCONSOLE Console) } static BOOL WINAPI -GuiProcessKeyCallback(PCONSOLE Console, MSG* msg, BYTE KeyStateMenu, DWORD ShiftState, UINT VirtualKeyCode, BOOL Down) +GuiProcessKeyCallback(IN OUT PFRONTEND This, + MSG* msg, + BYTE KeyStateMenu, + DWORD ShiftState, + UINT VirtualKeyCode, + BOOL Down) { if ((ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED) || KeyStateMenu & 0x80) && (VirtualKeyCode == VK_ESCAPE || VirtualKeyCode == VK_TAB || VirtualKeyCode == VK_SPACE)) @@ -2361,12 +2578,13 @@ GuiProcessKeyCallback(PCONSOLE Console, MSG* msg, BYTE KeyStateMenu, DWORD Shift } static BOOL WINAPI -GuiSetMouseCursor(PCONSOLE Console, HCURSOR hCursor); +GuiSetMouseCursor(IN OUT PFRONTEND This, + HCURSOR hCursor); static VOID WINAPI -GuiRefreshInternalInfo(PCONSOLE Console) +GuiRefreshInternalInfo(IN OUT PFRONTEND This) { - PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data; + PGUI_CONSOLE_DATA GuiData = This->Data; /* Update the console leader information held by the window */ SetConsoleWndConsoleLeaderCID(GuiData); @@ -2382,21 +2600,22 @@ GuiRefreshInternalInfo(PCONSOLE Console) /* Mouse is shown by default with its default cursor shape */ GuiData->MouseCursorRefCount = 0; // Reinitialize the reference counter - GuiSetMouseCursor(Console, NULL); + GuiSetMouseCursor(This, NULL); } static VOID WINAPI -GuiChangeTitle(PCONSOLE Console) +GuiChangeTitle(IN OUT PFRONTEND This) { - PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data; + PGUI_CONSOLE_DATA GuiData = This->Data; // PostMessageW(GuiData->hWindow, PM_CONSOLE_SET_TITLE, 0, 0); - SetWindowText(GuiData->hWindow, Console->Title.Buffer); + SetWindowText(GuiData->hWindow, GuiData->Console->Title.Buffer); } static BOOL WINAPI -GuiChangeIcon(PCONSOLE Console, HICON hWindowIcon) +GuiChangeIcon(IN OUT PFRONTEND This, + HICON hWindowIcon) { - PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data; + PGUI_CONSOLE_DATA GuiData = This->Data; HICON hIcon, hIconSm; if (hWindowIcon == NULL) @@ -2438,16 +2657,18 @@ GuiChangeIcon(PCONSOLE Console, HICON hWindowIcon) } static HWND WINAPI -GuiGetConsoleWindowHandle(PCONSOLE Console) +GuiGetConsoleWindowHandle(IN OUT PFRONTEND This) { - PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data; + PGUI_CONSOLE_DATA GuiData = This->Data; return GuiData->hWindow; } static VOID WINAPI -GuiGetLargestConsoleWindowSize(PCONSOLE Console, PCOORD pSize) +GuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This, + PCOORD pSize) { - PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data; + PGUI_CONSOLE_DATA GuiData = This->Data; + PCONSOLE_SCREEN_BUFFER ActiveBuffer; RECT WorkArea; LONG width, height; UINT WidthUnit, HeightUnit; @@ -2460,14 +2681,15 @@ GuiGetLargestConsoleWindowSize(PCONSOLE Console, PCOORD pSize) return; } - if (Console->ActiveBuffer) + ActiveBuffer = ConDrvGetActiveScreenBuffer(GuiData->Console); + if (ActiveBuffer) { - if (GetType(Console->ActiveBuffer) == TEXTMODE_BUFFER) + if (GetType(ActiveBuffer) == TEXTMODE_BUFFER) { WidthUnit = GuiData->CharWidth ; HeightUnit = GuiData->CharHeight; } - else /* if (GetType(Console->ActiveBuffer) == GRAPHICS_BUFFER) */ + else /* if (GetType(ActiveBuffer) == GRAPHICS_BUFFER) */ { WidthUnit = 1; HeightUnit = 1; @@ -2494,9 +2716,9 @@ GuiGetLargestConsoleWindowSize(PCONSOLE Console, PCOORD pSize) } static ULONG WINAPI -GuiGetDisplayMode(PCONSOLE Console) +GuiGetDisplayMode(IN OUT PFRONTEND This) { - PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data; + PGUI_CONSOLE_DATA GuiData = This->Data; ULONG DisplayMode = 0; if (GuiData->GuiInfo.FullScreen) @@ -2508,9 +2730,10 @@ GuiGetDisplayMode(PCONSOLE Console) } static BOOL WINAPI -GuiSetDisplayMode(PCONSOLE Console, ULONG NewMode) +GuiSetDisplayMode(IN OUT PFRONTEND This, + ULONG NewMode) { - PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data; + PGUI_CONSOLE_DATA GuiData = This->Data; if (NewMode & ~(CONSOLE_FULLSCREEN_MODE | CONSOLE_WINDOWED_MODE)) return FALSE; @@ -2521,9 +2744,10 @@ GuiSetDisplayMode(PCONSOLE Console, ULONG NewMode) } static INT WINAPI -GuiShowMouseCursor(PCONSOLE Console, BOOL Show) +GuiShowMouseCursor(IN OUT PFRONTEND This, + BOOL Show) { - PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data; + PGUI_CONSOLE_DATA GuiData = This->Data; /* Set the reference count */ if (Show) ++GuiData->MouseCursorRefCount; @@ -2536,9 +2760,10 @@ GuiShowMouseCursor(PCONSOLE Console, BOOL Show) } static BOOL WINAPI -GuiSetMouseCursor(PCONSOLE Console, HCURSOR hCursor) +GuiSetMouseCursor(IN OUT PFRONTEND This, + HCURSOR hCursor) { - PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data; + PGUI_CONSOLE_DATA GuiData = This->Data; /* * Set the cursor's handle. If the given handle is NULL, @@ -2553,9 +2778,11 @@ GuiSetMouseCursor(PCONSOLE Console, HCURSOR hCursor) } static HMENU WINAPI -GuiMenuControl(PCONSOLE Console, UINT cmdIdLow, UINT cmdIdHigh) +GuiMenuControl(IN OUT PFRONTEND This, + UINT cmdIdLow, + UINT cmdIdHigh) { - PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data; + PGUI_CONSOLE_DATA GuiData = This->Data; GuiData->cmdIdLow = cmdIdLow ; GuiData->cmdIdHigh = cmdIdHigh; @@ -2564,7 +2791,8 @@ GuiMenuControl(PCONSOLE Console, UINT cmdIdLow, UINT cmdIdHigh) } static BOOL WINAPI -GuiSetMenuClose(PCONSOLE Console, BOOL Enable) +GuiSetMenuClose(IN OUT PFRONTEND This, + BOOL Enable) { /* * NOTE: See http://www.mail-archive.com/harbour@harbour-project.org/msg27509.html @@ -2572,7 +2800,7 @@ GuiSetMenuClose(PCONSOLE Console, BOOL Enable) * for more information. */ - PGUI_CONSOLE_DATA GuiData = Console->TermIFace.Data; + PGUI_CONSOLE_DATA GuiData = This->Data; HMENU hSysMenu = GetSystemMenu(GuiData->hWindow, FALSE); if (hSysMenu == NULL) return FALSE; @@ -2585,7 +2813,8 @@ GuiSetMenuClose(PCONSOLE Console, BOOL Enable) static FRONTEND_VTBL GuiVtbl = { - GuiCleanupConsole, + GuiInitFrontEnd, + GuiDeinitFrontEnd, GuiDrawRegion, GuiWriteStream, GuiSetCursorInfo, @@ -2605,164 +2834,167 @@ static FRONTEND_VTBL GuiVtbl = GuiSetMenuClose, }; -NTSTATUS FASTCALL -GuiInitConsole(PCONSOLE Console, - /*IN*/ PCONSOLE_START_INFO ConsoleStartInfo, - PCONSOLE_INFO ConsoleInfo, - DWORD ProcessId, - LPCWSTR IconPath, - INT IconIndex) -{ - PGUI_CONSOLE_DATA GuiData; - GUI_CONSOLE_INFO TermInfo; - SIZE_T Length = 0; - if (Console == NULL || ConsoleInfo == NULL) +static BOOL +LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo, + IN OUT PCONSOLE_INFO ConsoleInfo) +{ +#define PATH_SEPARATOR L'\\' + + BOOL RetVal = FALSE; + HRESULT hRes = S_OK; + LPWSTR LinkName = NULL; + SIZE_T Length = 0; + + if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0) + return FALSE; + + ConsoleStartInfo->IconPath[0] = L'\0'; + ConsoleStartInfo->IconIndex = 0; + + /* 1- Find the last path separator if any */ + LinkName = wcsrchr(ConsoleStartInfo->ConsoleTitle, PATH_SEPARATOR); + if (LinkName == NULL) + { + LinkName = ConsoleStartInfo->ConsoleTitle; + } + else + { + /* Skip the path separator */ + ++LinkName; + } + + /* 2- Check for the link extension. The name ".lnk" is considered invalid. */ + Length = wcslen(LinkName); + if ( (Length <= 4) || (wcsicmp(LinkName + (Length - 4), L".lnk") != 0) ) + return FALSE; + + /* 3- It may be a link. Try to retrieve some properties */ + hRes = CoInitialize(NULL); + if (SUCCEEDED(hRes)) + { + /* Get a pointer to the IShellLink interface */ + IShellLinkW* pshl = NULL; + hRes = CoCreateInstance(&CLSID_ShellLink, + NULL, + CLSCTX_INPROC_SERVER, + &IID_IShellLinkW, + (LPVOID*)&pshl); + if (SUCCEEDED(hRes)) + { + /* Get a pointer to the IPersistFile interface */ + IPersistFile* ppf = NULL; + hRes = IPersistFile_QueryInterface(pshl, &IID_IPersistFile, (LPVOID*)&ppf); + if (SUCCEEDED(hRes)) + { + /* Load the shortcut */ + hRes = IPersistFile_Load(ppf, ConsoleStartInfo->ConsoleTitle, STGM_READ); + if (SUCCEEDED(hRes)) + { + /* + * Finally we can get the properties ! + * Update the old ones if needed. + */ + INT ShowCmd = 0; + // WORD HotKey = 0; + + /* Reset the name of the console with the name of the shortcut */ + Length = min(/*Length*/ Length - 4, // 4 == len(".lnk") + sizeof(ConsoleInfo->ConsoleTitle) / sizeof(ConsoleInfo->ConsoleTitle[0]) - 1); + wcsncpy(ConsoleInfo->ConsoleTitle, LinkName, Length); + ConsoleInfo->ConsoleTitle[Length] = L'\0'; + + /* Get the window showing command */ + hRes = IShellLinkW_GetShowCmd(pshl, &ShowCmd); + if (SUCCEEDED(hRes)) ConsoleStartInfo->ShowWindow = (WORD)ShowCmd; + + /* Get the hotkey */ + // hRes = pshl->GetHotkey(&ShowCmd); + // if (SUCCEEDED(hRes)) ConsoleStartInfo->HotKey = HotKey; + + /* Get the icon location, if any */ + + hRes = IShellLinkW_GetIconLocation(pshl, + ConsoleStartInfo->IconPath, + sizeof(ConsoleStartInfo->IconPath)/sizeof(ConsoleStartInfo->IconPath[0]) - 1, // == MAX_PATH + &ConsoleStartInfo->IconIndex); + if (!SUCCEEDED(hRes)) + { + ConsoleStartInfo->IconPath[0] = L'\0'; + ConsoleStartInfo->IconIndex = 0; + } + + // FIXME: Since we still don't load console properties from the shortcut, + // return false. When this will be done, we will return true instead. + RetVal = FALSE; + } + IPersistFile_Release(ppf); + } + IShellLinkW_Release(pshl); + } + } + CoUninitialize(); + + return RetVal; +} + +NTSTATUS NTAPI +GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd, + IN OUT PCONSOLE_INFO ConsoleInfo, + IN OUT PVOID ExtraConsoleInfo, + IN ULONG ProcessId) +{ + PCONSOLE_START_INFO ConsoleStartInfo = ExtraConsoleInfo; + PGUI_INIT_INFO GuiInitInfo; + + if (FrontEnd == NULL || ConsoleInfo == NULL || ConsoleStartInfo == NULL) return STATUS_INVALID_PARAMETER; - /* Initialize the GUI terminal emulator */ + /* Initialize GUI terminal emulator common functionalities */ if (!GuiInit()) return STATUS_UNSUCCESSFUL; - /* Initialize the console */ - Console->TermIFace.Vtbl = &GuiVtbl; - - GuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(GUI_CONSOLE_DATA)); - if (!GuiData) + /* + * Load per-application terminal settings. + * + * Check whether the process creating the console was launched via + * a shell-link. ConsoleInfo->ConsoleTitle may be updated with the + * name of the shortcut, and ConsoleStartInfo->Icon[Path|Index] too. + */ + if (ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) { - DPRINT1("CONSRV: Failed to create GUI_CONSOLE_DATA\n"); - return STATUS_UNSUCCESSFUL; + if (!LoadShellLinkConsoleInfo(ConsoleStartInfo, ConsoleInfo)) + { + ConsoleStartInfo->dwStartupFlags &= ~STARTF_TITLEISLINKNAME; + } } - Console->TermIFace.Data = (PVOID)GuiData; - GuiData->Console = Console; - GuiData->hWindow = NULL; - - /* The console can be resized */ - Console->FixedSize = FALSE; - - InitializeCriticalSection(&GuiData->Lock); - /* - * Load the terminal settings + * Initialize a private initialization info structure for later use. + * It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd. */ + GuiInitInfo = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(GUI_INIT_INFO)); + if (GuiInitInfo == NULL) return STATUS_NO_MEMORY; - /*********************************************** - * Adapted from ConSrvInitConsole in console.c * - ***********************************************/ + // HACK: We suppose that the pointers will be valid in GuiInitFrontEnd... + GuiInitInfo->ConsoleInfo = ConsoleInfo; + GuiInitInfo->ConsoleStartInfo = ConsoleStartInfo; + GuiInitInfo->ProcessId = ProcessId; - /* 1. Load the default settings */ - GuiConsoleGetDefaultSettings(&TermInfo, ProcessId); + /* Finally, initialize the frontend structure */ + FrontEnd->Vtbl = &GuiVtbl; + FrontEnd->Data = NULL; + FrontEnd->OldData = GuiInitInfo; - /* 2. Load the remaining console settings via the registry. */ - if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0) - { - /* Load the terminal infos from the registry. */ - GuiConsoleReadUserSettings(&TermInfo, ConsoleInfo->ConsoleTitle, ProcessId); + return STATUS_SUCCESS; +} - /* - * Now, update them with the properties the user might gave to us - * via the STARTUPINFO structure before calling CreateProcess - * (and which was transmitted via the ConsoleStartInfo structure). - * We therefore overwrite the values read in the registry. - */ - if (ConsoleStartInfo->dwStartupFlags & STARTF_USESHOWWINDOW) - { - TermInfo.ShowWindow = ConsoleStartInfo->ShowWindow; - } - if (ConsoleStartInfo->dwStartupFlags & STARTF_USEPOSITION) - { - TermInfo.AutoPosition = FALSE; - TermInfo.WindowOrigin = ConsoleStartInfo->ConsoleWindowOrigin; - } - if (ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN) - { - TermInfo.FullScreen = TRUE; - } - } +NTSTATUS NTAPI +GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd) +{ + if (FrontEnd == NULL) return STATUS_INVALID_PARAMETER; - - /* - * Set up the GUI data - */ - - Length = min(wcslen(TermInfo.FaceName) + 1, LF_FACESIZE); // wcsnlen - wcsncpy(GuiData->GuiInfo.FaceName, TermInfo.FaceName, LF_FACESIZE); - GuiData->GuiInfo.FaceName[Length] = L'\0'; - GuiData->GuiInfo.FontFamily = TermInfo.FontFamily; - GuiData->GuiInfo.FontSize = TermInfo.FontSize; - GuiData->GuiInfo.FontWeight = TermInfo.FontWeight; - GuiData->GuiInfo.UseRasterFonts = TermInfo.UseRasterFonts; - GuiData->GuiInfo.FullScreen = TermInfo.FullScreen; - GuiData->GuiInfo.ShowWindow = TermInfo.ShowWindow; - GuiData->GuiInfo.AutoPosition = TermInfo.AutoPosition; - GuiData->GuiInfo.WindowOrigin = TermInfo.WindowOrigin; - - /* Initialize the icon handles to their default values */ - GuiData->hIcon = ghDefaultIcon; - GuiData->hIconSm = ghDefaultIconSm; - - /* Get the associated icon, if any */ - if (IconPath == NULL || *IconPath == L'\0') - { - IconPath = ConsoleStartInfo->AppPath; - IconIndex = 0; - } - DPRINT("IconPath = %S ; IconIndex = %lu\n", (IconPath ? IconPath : L"n/a"), IconIndex); - if (IconPath) - { - HICON hIcon = NULL, hIconSm = NULL; - PrivateExtractIconExW(IconPath, - IconIndex, - &hIcon, - &hIconSm, - 1); - DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon, hIconSm); - if (hIcon != NULL) - { - DPRINT("Effectively set the icons\n"); - GuiData->hIcon = hIcon; - GuiData->hIconSm = hIconSm; - } - } - - /* Mouse is shown by default with its default cursor shape */ - GuiData->hCursor = ghDefaultCursor; - GuiData->MouseCursorRefCount = 0; - - /* A priori don't ignore mouse signals */ - GuiData->IgnoreNextMouseSignal = FALSE; - - /* Close button and the corresponding system menu item are enabled by default */ - GuiData->IsCloseButtonEnabled = TRUE; - - /* There is no user-reserved menu id range by default */ - GuiData->cmdIdLow = GuiData->cmdIdHigh = 0; - - /* - * We need to wait until the GUI has been fully initialized - * to retrieve custom settings i.e. WindowSize etc... - * Ideally we could use SendNotifyMessage for this but its not - * yet implemented. - */ - GuiData->hGuiInitEvent = CreateEventW(NULL, FALSE, FALSE, NULL); - - /* Create the terminal window */ - PostMessageW(NotifyWnd, PM_CREATE_CONSOLE, GuiData->GuiInfo.ShowWindow, (LPARAM)GuiData); - - /* Wait until initialization has finished */ - WaitForSingleObject(GuiData->hGuiInitEvent, INFINITE); - DPRINT("OK we created the console window\n"); - CloseHandle(GuiData->hGuiInitEvent); - GuiData->hGuiInitEvent = NULL; - - /* Check whether we really succeeded in initializing the terminal window */ - if (GuiData->hWindow == NULL) - { - DPRINT("GuiInitConsole - We failed at creating a new terminal window\n"); - // ConioCleanupConsole(Console); - GuiCleanupConsole(Console); - return STATUS_UNSUCCESSFUL; - } + if (FrontEnd->Data) GuiDeinitFrontEnd(FrontEnd); + if (FrontEnd->OldData) ConsoleFreeHeap(FrontEnd->OldData); return STATUS_SUCCESS; } diff --git a/reactos/win32ss/user/consrv/frontends/input.c b/reactos/win32ss/user/consrv/frontends/input.c new file mode 100644 index 00000000000..b457ce85733 --- /dev/null +++ b/reactos/win32ss/user/consrv/frontends/input.c @@ -0,0 +1,146 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Console Server DLL + * FILE: win32ss/user/consrv/frontends/input.c + * PURPOSE: Common Front-Ends Input functions + * PROGRAMMERS: Jeffrey Morlan + * Hermes Belusca-Maito (hermes.belusca@sfr.fr) + */ + +/* INCLUDES *******************************************************************/ + +#include "consrv.h" +#include "include/conio.h" +#include "conio.h" +#include "coninput.h" + +#define NDEBUG +#include + + +/* PRIVATE FUNCTIONS **********************************************************/ + +static DWORD FASTCALL +ConioGetShiftState(PBYTE KeyState, LPARAM lParam) +{ + DWORD ssOut = 0; + + if (KeyState[VK_CAPITAL] & 0x01) + ssOut |= CAPSLOCK_ON; + + if (KeyState[VK_NUMLOCK] & 0x01) + ssOut |= NUMLOCK_ON; + + if (KeyState[VK_SCROLL] & 0x01) + ssOut |= SCROLLLOCK_ON; + + if (KeyState[VK_SHIFT] & 0x80) + ssOut |= SHIFT_PRESSED; + + if (KeyState[VK_LCONTROL] & 0x80) + ssOut |= LEFT_CTRL_PRESSED; + if (KeyState[VK_RCONTROL] & 0x80) + ssOut |= RIGHT_CTRL_PRESSED; + + if (KeyState[VK_LMENU] & 0x80) + ssOut |= LEFT_ALT_PRESSED; + if (KeyState[VK_RMENU] & 0x80) + ssOut |= RIGHT_ALT_PRESSED; + + /* See WM_CHAR MSDN documentation for instance */ + if (lParam & 0x01000000) + ssOut |= ENHANCED_KEY; + + return ssOut; +} + +VOID WINAPI +ConioProcessKey(PCONSOLE Console, MSG* msg) +{ + static BYTE KeyState[256] = { 0 }; + /* MSDN mentions that you should use the last virtual key code received + * when putting a virtual key identity to a WM_CHAR message since multiple + * or translated keys may be involved. */ + static UINT LastVirtualKey = 0; + DWORD ShiftState; + WCHAR UnicodeChar; + UINT VirtualKeyCode; + UINT VirtualScanCode; + BOOL Down = FALSE; + BOOLEAN Fake; // synthesized, not a real event + BOOLEAN NotChar; // message should not be used to return a character + + if (NULL == Console) + { + DPRINT1("No Active Console!\n"); + return; + } + + VirtualScanCode = HIWORD(msg->lParam) & 0xFF; + Down = msg->message == WM_KEYDOWN || msg->message == WM_CHAR || + msg->message == WM_SYSKEYDOWN || msg->message == WM_SYSCHAR; + + GetKeyboardState(KeyState); + ShiftState = ConioGetShiftState(KeyState, msg->lParam); + + if (msg->message == WM_CHAR || msg->message == WM_SYSCHAR) + { + VirtualKeyCode = LastVirtualKey; + UnicodeChar = msg->wParam; + } + else + { + WCHAR Chars[2]; + INT RetChars = 0; + + VirtualKeyCode = msg->wParam; + RetChars = ToUnicodeEx(VirtualKeyCode, + VirtualScanCode, + KeyState, + Chars, + 2, + 0, + NULL); + UnicodeChar = (1 == RetChars ? Chars[0] : 0); + } + + if (ConioProcessKeyCallback(Console, + msg, + KeyState[VK_MENU], + ShiftState, + VirtualKeyCode, + Down)) + { + return; + } + + Fake = UnicodeChar && + (msg->message != WM_CHAR && msg->message != WM_SYSCHAR && + msg->message != WM_KEYUP && msg->message != WM_SYSKEYUP); + NotChar = (msg->message != WM_CHAR && msg->message != WM_SYSCHAR); + if (NotChar) LastVirtualKey = msg->wParam; + + DPRINT("CONSRV: %s %s %s %s %02x %02x '%lc' %04x\n", + Down ? "down" : "up ", + (msg->message == WM_CHAR || msg->message == WM_SYSCHAR) ? + "char" : "key ", + Fake ? "fake" : "real", + NotChar ? "notc" : "char", + VirtualScanCode, + VirtualKeyCode, + (UnicodeChar >= L' ') ? UnicodeChar : L'.', + ShiftState); + + if (Fake) return; + + /* Send the key press to the console driver */ + ConDrvProcessKey(Console, + Down, + VirtualKeyCode, + VirtualScanCode, + UnicodeChar, + ShiftState, + KeyState[VK_CONTROL]); +} + +/* EOF */ diff --git a/reactos/win32ss/user/consrv/frontends/tui/tuiterm.c b/reactos/win32ss/user/consrv/frontends/tui/tuiterm.c index 022c8442b3d..451ca9a3bd2 100644 --- a/reactos/win32ss/user/consrv/frontends/tui/tuiterm.c +++ b/reactos/win32ss/user/consrv/frontends/tui/tuiterm.c @@ -9,6 +9,8 @@ * Hermes Belusca-Maito (hermes.belusca@sfr.fr) */ +#ifdef TUITERM_COMPILE + #include "consrv.h" #include "include/conio.h" #include "include/console.h" @@ -274,7 +276,7 @@ TuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_KEYUP: case WM_SYSKEYUP: { - if (ConSrvValidateConsoleUnsafe(ActiveConsole->Console, CONSOLE_RUNNING, TRUE)) + if (ConDrvValidateConsoleUnsafe(ActiveConsole->Console, CONSOLE_RUNNING, TRUE)) { MSG Message; Message.hwnd = hWnd; @@ -290,7 +292,7 @@ TuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_ACTIVATE: { - if (ConSrvValidateConsoleUnsafe(ActiveConsole->Console, CONSOLE_RUNNING, TRUE)) + if (ConDrvValidateConsoleUnsafe(ActiveConsole->Console, CONSOLE_RUNNING, TRUE)) { if (LOWORD(wParam) != WA_INACTIVE) { @@ -440,9 +442,90 @@ Quit: ******************************************************************************/ static VOID WINAPI -TuiCleanupConsole(PCONSOLE Console) +TuiDeinitFrontEnd(IN OUT PFRONTEND This /*, + IN PCONSOLE Console */); + +NTSTATUS NTAPI +TuiInitFrontEnd(IN OUT PFRONTEND This, + IN PCONSOLE Console) { - PTUI_CONSOLE_DATA TuiData = Console->TermIFace.Data; + PTUI_CONSOLE_DATA TuiData; + HANDLE ThreadHandle; + + if (This == NULL || Console == NULL) + return STATUS_INVALID_PARAMETER; + + // if (GetType(Console->ActiveBuffer) != TEXTMODE_BUFFER) + // return STATUS_INVALID_PARAMETER; + + // /* Initialize the console */ + // Console->TermIFace.Vtbl = &TuiVtbl; + + TuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(TUI_CONSOLE_DATA)); + if (!TuiData) + { + DPRINT1("CONSRV: Failed to create TUI_CONSOLE_DATA\n"); + return STATUS_UNSUCCESSFUL; + } + // Console->TermIFace.Data = (PVOID)TuiData; + TuiData->Console = Console; + TuiData->hWindow = NULL; + + InitializeCriticalSection(&TuiData->Lock); + + /* + * HACK: Resize the console since we don't support for now changing + * the console size when we display it with the hardware. + */ + // Console->ConsoleSize = PhysicalConsoleSize; + // ConioResizeBuffer(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), PhysicalConsoleSize); + + // /* The console cannot be resized anymore */ + // Console->FixedSize = TRUE; // MUST be placed AFTER the call to ConioResizeBuffer !! + // // ConioResizeTerminal(Console); + + /* + * Contrary to what we do in the GUI front-end, here we create + * an input thread for each console. It will dispatch all the + * input messages to the proper console (on the GUI it is done + * via the default GUI dispatch thread). + */ + ThreadHandle = CreateThread(NULL, + 0, + TuiConsoleThread, + (PVOID)TuiData, + 0, + NULL); + if (NULL == ThreadHandle) + { + DPRINT1("CONSRV: Unable to create console thread\n"); + // TuiDeinitFrontEnd(Console); + TuiDeinitFrontEnd(This); + return STATUS_UNSUCCESSFUL; + } + CloseHandle(ThreadHandle); + + /* + * Insert the newly created console in the list of virtual consoles + * and activate it (give it the focus). + */ + EnterCriticalSection(&ActiveVirtConsLock); + InsertTailList(&VirtConsList, &TuiData->Entry); + ActiveConsole = TuiData; + LeaveCriticalSection(&ActiveVirtConsLock); + + /* Finally, initialize the frontend structure */ + This->Data = TuiData; + This->OldData = NULL; + + return STATUS_SUCCESS; +} + +static VOID WINAPI +TuiDeinitFrontEnd(IN OUT PFRONTEND This) +{ + // PCONSOLE Console = This->Console; + PTUI_CONSOLE_DATA TuiData = This->Data; // Console->TermIFace.Data; /* Close the notification window */ DestroyWindow(TuiData->hWindow); @@ -473,13 +556,15 @@ TuiCleanupConsole(PCONSOLE Console) /* Switch to the next console */ if (NULL != ActiveConsole) ConioDrawConsole(ActiveConsole->Console); - Console->TermIFace.Data = NULL; + // Console->TermIFace.Data = NULL; + This->Data = NULL; DeleteCriticalSection(&TuiData->Lock); ConsoleFreeHeap(TuiData); } static VOID WINAPI -TuiDrawRegion(PCONSOLE Console, SMALL_RECT* Region) +TuiDrawRegion(IN OUT PFRONTEND This, + SMALL_RECT* Region) { DWORD BytesReturned; PCONSOLE_SCREEN_BUFFER Buff = Console->ActiveBuffer; @@ -517,8 +602,13 @@ TuiDrawRegion(PCONSOLE Console, SMALL_RECT* Region) } static VOID WINAPI -TuiWriteStream(PCONSOLE Console, SMALL_RECT* Region, SHORT CursorStartX, SHORT CursorStartY, - UINT ScrolledLines, PWCHAR Buffer, UINT Length) +TuiWriteStream(IN OUT PFRONTEND This, + SMALL_RECT* Region, + SHORT CursorStartX, + SHORT CursorStartY, + UINT ScrolledLines, + PWCHAR Buffer, + UINT Length) { PCONSOLE_SCREEN_BUFFER Buff = Console->ActiveBuffer; PCHAR NewBuffer; @@ -546,7 +636,8 @@ TuiWriteStream(PCONSOLE Console, SMALL_RECT* Region, SHORT CursorStartX, SHORT C } static BOOL WINAPI -TuiSetCursorInfo(PCONSOLE Console, PCONSOLE_SCREEN_BUFFER Buff) +TuiSetCursorInfo(IN OUT PFRONTEND This, + PCONSOLE_SCREEN_BUFFER Buff) { CONSOLE_CURSOR_INFO Info; DWORD BytesReturned; @@ -567,7 +658,10 @@ TuiSetCursorInfo(PCONSOLE Console, PCONSOLE_SCREEN_BUFFER Buff) } static BOOL WINAPI -TuiSetScreenInfo(PCONSOLE Console, PCONSOLE_SCREEN_BUFFER Buff, SHORT OldCursorX, SHORT OldCursorY) +TuiSetScreenInfo(IN OUT PFRONTEND This, + PCONSOLE_SCREEN_BUFFER Buff, + SHORT OldCursorX, + SHORT OldCursorY) { CONSOLE_SCREEN_BUFFER_INFO Info; DWORD BytesReturned; @@ -590,12 +684,17 @@ TuiSetScreenInfo(PCONSOLE Console, PCONSOLE_SCREEN_BUFFER Buff, SHORT OldCursorX } static VOID WINAPI -TuiResizeTerminal(PCONSOLE Console) +TuiResizeTerminal(IN OUT PFRONTEND This) { } static BOOL WINAPI -TuiProcessKeyCallback(PCONSOLE Console, MSG* msg, BYTE KeyStateMenu, DWORD ShiftState, UINT VirtualKeyCode, BOOL Down) +TuiProcessKeyCallback(IN OUT PFRONTEND This, + MSG* msg, + BYTE KeyStateMenu, + DWORD ShiftState, + UINT VirtualKeyCode, + BOOL Down) { if (0 != (ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) && VK_TAB == VirtualKeyCode) @@ -616,43 +715,46 @@ TuiProcessKeyCallback(PCONSOLE Console, MSG* msg, BYTE KeyStateMenu, DWORD Shift } static VOID WINAPI -TuiRefreshInternalInfo(PCONSOLE Console) +TuiRefreshInternalInfo(IN OUT PFRONTEND This) { } static VOID WINAPI -TuiChangeTitle(PCONSOLE Console) +TuiChangeTitle(IN OUT PFRONTEND This) { } static BOOL WINAPI -TuiChangeIcon(PCONSOLE Console, HICON hWindowIcon) +TuiChangeIcon(IN OUT PFRONTEND This, + HICON hWindowIcon) { return TRUE; } static HWND WINAPI -TuiGetConsoleWindowHandle(PCONSOLE Console) +TuiGetConsoleWindowHandle(IN OUT PFRONTEND This) { - PTUI_CONSOLE_DATA TuiData = Console->TermIFace.Data; + PTUI_CONSOLE_DATA TuiData = This->Data; return TuiData->hWindow; } static VOID WINAPI -TuiGetLargestConsoleWindowSize(PCONSOLE Console, PCOORD pSize) +TuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This, + PCOORD pSize) { if (!pSize) return; *pSize = PhysicalConsoleSize; } static ULONG WINAPI -TuiGetDisplayMode(PCONSOLE Console) +TuiGetDisplayMode(IN OUT PFRONTEND This) { return CONSOLE_FULLSCREEN_HARDWARE; // CONSOLE_FULLSCREEN; } static BOOL WINAPI -TuiSetDisplayMode(PCONSOLE Console, ULONG NewMode) +TuiSetDisplayMode(IN OUT PFRONTEND This, + ULONG NewMode) { // if (NewMode & ~(CONSOLE_FULLSCREEN_MODE | CONSOLE_WINDOWED_MODE)) // return FALSE; @@ -660,32 +762,38 @@ TuiSetDisplayMode(PCONSOLE Console, ULONG NewMode) } static INT WINAPI -TuiShowMouseCursor(PCONSOLE Console, BOOL Show) +TuiShowMouseCursor(IN OUT PFRONTEND This, + BOOL Show) { return 0; } static BOOL WINAPI -TuiSetMouseCursor(PCONSOLE Console, HCURSOR hCursor) +TuiSetMouseCursor(IN OUT PFRONTEND This, + HCURSOR hCursor) { return TRUE; } static HMENU WINAPI -TuiMenuControl(PCONSOLE Console, UINT cmdIdLow, UINT cmdIdHigh) +TuiMenuControl(IN OUT PFRONTEND This, + UINT cmdIdLow, + UINT cmdIdHigh) { return NULL; } static BOOL WINAPI -TuiSetMenuClose(PCONSOLE Console, BOOL Enable) +TuiSetMenuClose(IN OUT PFRONTEND This, + BOOL Enable) { return TRUE; } static FRONTEND_VTBL TuiVtbl = { - TuiCleanupConsole, + TuiInitFrontEnd, + TuiDeinitFrontEnd, TuiDrawRegion, TuiWriteStream, TuiSetCursorInfo, @@ -705,80 +813,49 @@ static FRONTEND_VTBL TuiVtbl = TuiSetMenuClose, }; -NTSTATUS FASTCALL -TuiInitConsole(PCONSOLE Console, - /*IN*/ PCONSOLE_START_INFO ConsoleStartInfo, - PCONSOLE_INFO ConsoleInfo, - DWORD ProcessId) +// static BOOL +// DtbgIsDesktopVisible(VOID) +// { + // return !((BOOL)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE)); +// } +static BOOLEAN +IsConsoleMode(VOID) { - PTUI_CONSOLE_DATA TuiData; - HANDLE ThreadHandle; + return (BOOLEAN)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE); +} - if (Console == NULL || ConsoleInfo == NULL) +NTSTATUS NTAPI +TuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd, + IN OUT PCONSOLE_INFO ConsoleInfo, + IN OUT PVOID ExtraConsoleInfo, + IN ULONG ProcessId) +{ + if (FrontEnd == NULL || ConsoleInfo == NULL) return STATUS_INVALID_PARAMETER; - if (GetType(Console->ActiveBuffer) != TEXTMODE_BUFFER) - return STATUS_INVALID_PARAMETER; + /* We must be in console mode already */ + if (!IsConsoleMode()) return STATUS_UNSUCCESSFUL; /* Initialize the TUI terminal emulator */ - if (!TuiInit(Console->CodePage)) return STATUS_UNSUCCESSFUL; + if (!TuiInit(ConsoleInfo->CodePage)) return STATUS_UNSUCCESSFUL; - /* Initialize the console */ - Console->TermIFace.Vtbl = &TuiVtbl; - - TuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(TUI_CONSOLE_DATA)); - if (!TuiData) - { - DPRINT1("CONSRV: Failed to create TUI_CONSOLE_DATA\n"); - return STATUS_UNSUCCESSFUL; - } - Console->TermIFace.Data = (PVOID)TuiData; - TuiData->Console = Console; - TuiData->hWindow = NULL; - - InitializeCriticalSection(&TuiData->Lock); - - /* - * HACK: Resize the console since we don't support for now changing - * the console size when we display it with the hardware. - */ - Console->ConsoleSize = PhysicalConsoleSize; - ConioResizeBuffer(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), PhysicalConsoleSize); - - /* The console cannot be resized anymore */ - Console->FixedSize = TRUE; // MUST be placed AFTER the call to ConioResizeBuffer !! - // ConioResizeTerminal(Console); - - /* - * Contrary to what we do in the GUI front-end, here we create - * an input thread for each console. It will dispatch all the - * input messages to the proper console (on the GUI it is done - * via the default GUI dispatch thread). - */ - ThreadHandle = CreateThread(NULL, - 0, - TuiConsoleThread, - (PVOID)TuiData, - 0, - NULL); - if (NULL == ThreadHandle) - { - DPRINT1("CONSRV: Unable to create console thread\n"); - TuiCleanupConsole(Console); - return STATUS_UNSUCCESSFUL; - } - CloseHandle(ThreadHandle); - - /* - * Insert the newly created console in the list of virtual consoles - * and activate it (give it the focus). - */ - EnterCriticalSection(&ActiveVirtConsLock); - InsertTailList(&VirtConsList, &TuiData->Entry); - ActiveConsole = TuiData; - LeaveCriticalSection(&ActiveVirtConsLock); + /* Finally, initialize the frontend structure */ + FrontEnd->Vtbl = &TuiVtbl; + FrontEnd->Data = NULL; + FrontEnd->OldData = NULL; return STATUS_SUCCESS; } +NTSTATUS NTAPI +TuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd) +{ + if (FrontEnd == NULL) return STATUS_INVALID_PARAMETER; + if (FrontEnd->Data) TuiDeinitFrontEnd(FrontEnd); + + return STATUS_SUCCESS; +} + +#endif + /* EOF */ diff --git a/reactos/win32ss/user/consrv/handle.c b/reactos/win32ss/user/consrv/handle.c index 37c68685554..71889f27ea6 100644 --- a/reactos/win32ss/user/consrv/handle.c +++ b/reactos/win32ss/user/consrv/handle.c @@ -443,7 +443,7 @@ ConSrvGetObject(PCONSOLE_PROCESS_DATA ProcessData, RtlLeaveCriticalSection(&ProcessData->HandleTableLock); - if (ConSrvValidateConsole(ObjectEntry->Console, CONSOLE_RUNNING, LockConsole)) + if (ConDrvValidateConsole(ObjectEntry->Console, CONSOLE_RUNNING, LockConsole)) { _InterlockedIncrement(&ObjectEntry->Console->ReferenceCount); @@ -492,7 +492,9 @@ ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData, ConSrvFreeHandlesTable(ProcessData); /* Initialize a new Console owned by this process */ - Status = ConSrvInitConsole(&ProcessData->Console, ConsoleStartInfo, ProcessData->Process); + Status = ConSrvInitConsole(&ProcessData->Console, + ConsoleStartInfo, + HandleToUlong(ProcessData->Process->ClientId.UniqueProcess)); if (!NT_SUCCESS(Status)) { DPRINT1("Console initialization failed\n"); @@ -551,7 +553,7 @@ ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData, NTSTATUS Status = STATUS_SUCCESS; /* Validate and lock the console */ - if (!ConSrvValidateConsole(Console, CONSOLE_RUNNING, TRUE)) + if (!ConDrvValidateConsole(Console, CONSOLE_RUNNING, TRUE)) { // FIXME: Find another status code return STATUS_UNSUCCESSFUL; @@ -629,7 +631,7 @@ ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData) // RtlEnterCriticalSection(&ProcessData->HandleTableLock); /* Validate and lock the console */ - if (ConSrvValidateConsole(Console, CONSOLE_RUNNING, TRUE)) + if (ConDrvValidateConsole(Console, CONSOLE_RUNNING, TRUE)) { DPRINT("ConSrvRemoveConsole - Locking OK\n"); diff --git a/reactos/win32ss/user/consrv/include/conio.h b/reactos/win32ss/user/consrv/include/conio.h index bcada388584..d254e45bae8 100644 --- a/reactos/win32ss/user/consrv/include/conio.h +++ b/reactos/win32ss/user/consrv/include/conio.h @@ -70,7 +70,7 @@ struct _CONSOLE_SCREEN_BUFFER COORD OldScreenBufferSize; /* Old size of this screen buffer */ COORD OldViewSize; /* Old associated view size */ - COORD ViewOrigin; /* Beginning offset for the actual display area */ + COORD ViewOrigin; /* Beginning offset for the actual display area */ /***** Put that VV in TEXTMODE_SCREEN_BUFFER ?? *****/ USHORT VirtualY; /* Top row of buffer being displayed, reported to callers */ @@ -173,79 +173,85 @@ typedef struct _CONSOLE_INPUT_BUFFER USHORT Mode; /* Input buffer modes */ } CONSOLE_INPUT_BUFFER, *PCONSOLE_INPUT_BUFFER; + +typedef struct _FRONTEND FRONTEND, *PFRONTEND; +/* HACK: */ typedef struct _CONSOLE_INFO *PCONSOLE_INFO; typedef struct _FRONTEND_VTBL { /* * Internal interface (functions called by the console server only) */ - // BOOL (WINAPI *Init)(); - VOID (WINAPI *CleanupConsole)(struct _CONSOLE* Console); + NTSTATUS (WINAPI *InitFrontEnd)(IN OUT PFRONTEND This, + IN struct _CONSOLE* Console); + VOID (WINAPI *DeinitFrontEnd)(IN OUT PFRONTEND This); + /* Interface used for both text-mode and graphics screen buffers */ - VOID (WINAPI *DrawRegion)(struct _CONSOLE* Console, + VOID (WINAPI *DrawRegion)(IN OUT PFRONTEND This, SMALL_RECT* Region); /* Interface used only for text-mode screen buffers */ - VOID (WINAPI *WriteStream)(struct _CONSOLE* Console, + VOID (WINAPI *WriteStream)(IN OUT PFRONTEND This, SMALL_RECT* Block, SHORT CursorStartX, SHORT CursorStartY, UINT ScrolledLines, PWCHAR Buffer, UINT Length); - BOOL (WINAPI *SetCursorInfo)(struct _CONSOLE* Console, + BOOL (WINAPI *SetCursorInfo)(IN OUT PFRONTEND This, PCONSOLE_SCREEN_BUFFER ScreenBuffer); - BOOL (WINAPI *SetScreenInfo)(struct _CONSOLE* Console, + BOOL (WINAPI *SetScreenInfo)(IN OUT PFRONTEND This, PCONSOLE_SCREEN_BUFFER ScreenBuffer, SHORT OldCursorX, SHORT OldCursorY); - VOID (WINAPI *ResizeTerminal)(struct _CONSOLE* Console); - BOOL (WINAPI *ProcessKeyCallback)(struct _CONSOLE* Console, + VOID (WINAPI *ResizeTerminal)(IN OUT PFRONTEND This); + BOOL (WINAPI *ProcessKeyCallback)(IN OUT PFRONTEND This, MSG* msg, BYTE KeyStateMenu, DWORD ShiftState, UINT VirtualKeyCode, BOOL Down); - VOID (WINAPI *RefreshInternalInfo)(struct _CONSOLE* Console); + VOID (WINAPI *RefreshInternalInfo)(IN OUT PFRONTEND This); /* * External interface (functions corresponding to the Console API) */ - VOID (WINAPI *ChangeTitle)(struct _CONSOLE* Console); - BOOL (WINAPI *ChangeIcon)(struct _CONSOLE* Console, + VOID (WINAPI *ChangeTitle)(IN OUT PFRONTEND This); + BOOL (WINAPI *ChangeIcon)(IN OUT PFRONTEND This, HICON hWindowIcon); - HWND (WINAPI *GetConsoleWindowHandle)(struct _CONSOLE* Console); - VOID (WINAPI *GetLargestConsoleWindowSize)(struct _CONSOLE* Console, + HWND (WINAPI *GetConsoleWindowHandle)(IN OUT PFRONTEND This); + VOID (WINAPI *GetLargestConsoleWindowSize)(IN OUT PFRONTEND This, PCOORD pSize); - ULONG (WINAPI *GetDisplayMode)(struct _CONSOLE* Console); - BOOL (WINAPI *SetDisplayMode)(struct _CONSOLE* Console, + ULONG (WINAPI *GetDisplayMode)(IN OUT PFRONTEND This); + BOOL (WINAPI *SetDisplayMode)(IN OUT PFRONTEND This, ULONG NewMode); - INT (WINAPI *ShowMouseCursor)(struct _CONSOLE* Console, + INT (WINAPI *ShowMouseCursor)(IN OUT PFRONTEND This, BOOL Show); - BOOL (WINAPI *SetMouseCursor)(struct _CONSOLE* Console, + BOOL (WINAPI *SetMouseCursor)(IN OUT PFRONTEND This, HCURSOR hCursor); - HMENU (WINAPI *MenuControl)(struct _CONSOLE* Console, + HMENU (WINAPI *MenuControl)(IN OUT PFRONTEND This, UINT cmdIdLow, UINT cmdIdHigh); - BOOL (WINAPI *SetMenuClose)(struct _CONSOLE* Console, + BOOL (WINAPI *SetMenuClose)(IN OUT PFRONTEND This, BOOL Enable); #if 0 // Possible future front-end interface - BOOL (WINAPI *GetFrontEndProperty)(struct _CONSOLE* Console, + BOOL (WINAPI *GetFrontEndProperty)(IN OUT PFRONTEND This, ULONG Flag, PVOID Info, ULONG Size); - BOOL (WINAPI *SetFrontEndProperty)(struct _CONSOLE* Console, + BOOL (WINAPI *SetFrontEndProperty)(IN OUT PFRONTEND This, ULONG Flag, PVOID Info /*, ULONG Size */); #endif } FRONTEND_VTBL, *PFRONTEND_VTBL; -typedef struct _FRONTEND_IFACE +struct _FRONTEND { - PFRONTEND_VTBL Vtbl; /* Virtual table */ - PVOID Data; /* Private data */ - PVOID OldData; /* Reserved */ -} FRONTEND_IFACE, *PFRONTEND_IFACE; + PFRONTEND_VTBL Vtbl; /* Virtual table */ + struct _CONSOLE* Console; /* Console to which the frontend is attached to */ + PVOID Data; /* Private data */ + PVOID OldData; /* Reserved */ +}; /* * WARNING: Change the state of the console ONLY when the console is locked ! @@ -267,7 +273,7 @@ typedef struct _CONSOLE LIST_ENTRY Entry; /* Entry in the list of consoles */ LIST_ENTRY ProcessList; /* List of processes owning the console. The first one is the so-called "Console Leader Process" */ - FRONTEND_IFACE TermIFace; /* Frontend-specific interface */ + FRONTEND TermIFace; /* Frontend-specific interface */ /**************************** Input buffer and data ***************************/ CONSOLE_INPUT_BUFFER InputBuffer; /* Input buffer of the console */ @@ -324,9 +330,11 @@ typedef struct _CONSOLE /* console.c */ VOID FASTCALL ConioPause(PCONSOLE Console, UINT Flags); VOID FASTCALL ConioUnpause(PCONSOLE Console, UINT Flags); -ULONG FASTCALL ConSrvConsoleProcessCtrlEvent(PCONSOLE Console, - ULONG ProcessGroupId, - DWORD Event); + +NTSTATUS NTAPI +ConDrvConsoleProcessCtrlEvent(IN PCONSOLE Console, + IN ULONG ProcessGroupId, + IN ULONG Event); /* coninput.c */ VOID WINAPI ConioProcessKey(PCONSOLE Console, MSG* msg); diff --git a/reactos/win32ss/user/consrv/include/console.h b/reactos/win32ss/user/consrv/include/console.h index 09e4b338168..5a12ecd9062 100644 --- a/reactos/win32ss/user/consrv/include/console.h +++ b/reactos/win32ss/user/consrv/include/console.h @@ -8,14 +8,21 @@ #pragma once -BOOL FASTCALL ConSrvValidateConsolePointer(PCONSOLE Console); -BOOL FASTCALL ConSrvValidateConsoleState(PCONSOLE Console, - CONSOLE_STATE ExpectedState); -BOOL FASTCALL ConSrvValidateConsoleUnsafe(PCONSOLE Console, - CONSOLE_STATE ExpectedState, - BOOL LockConsole); -BOOL FASTCALL ConSrvValidateConsole(PCONSOLE Console, - CONSOLE_STATE ExpectedState, - BOOL LockConsole); +BOOLEAN NTAPI +ConDrvValidateConsolePointer(IN PCONSOLE Console); + +BOOLEAN NTAPI +ConDrvValidateConsoleState(IN PCONSOLE Console, + IN CONSOLE_STATE ExpectedState); + +BOOLEAN NTAPI +ConDrvValidateConsoleUnsafe(IN PCONSOLE Console, + IN CONSOLE_STATE ExpectedState, + IN BOOLEAN LockConsole); + +BOOLEAN NTAPI +ConDrvValidateConsole(IN PCONSOLE Console, + IN CONSOLE_STATE ExpectedState, + IN BOOLEAN LockConsole); /* EOF */ diff --git a/reactos/win32ss/user/consrv/init.c b/reactos/win32ss/user/consrv/init.c index fd598501053..6791837ed03 100644 --- a/reactos/win32ss/user/consrv/init.c +++ b/reactos/win32ss/user/consrv/init.c @@ -365,7 +365,7 @@ ConSrvNewProcess(PCSR_PROCESS SourceProcess, PCONSOLE_PROCESS_DATA SourceProcessData = ConsoleGetPerProcessData(SourceProcess); /* Validate and lock the parent's console */ - if (ConSrvValidateConsole(SourceProcessData->Console, CONSOLE_RUNNING, TRUE)) + if (ConDrvValidateConsole(SourceProcessData->Console, CONSOLE_RUNNING, TRUE)) { /* Inherit the parent's handles table */ Status = ConSrvInheritHandlesTable(SourceProcessData, TargetProcessData); @@ -508,7 +508,7 @@ CSR_SERVER_DLL_INIT(ConServerDllInitialization) if (!ConSrvHeap) return STATUS_NO_MEMORY; */ - ConSrvInitConsoleSupport(); + ConDrvInitConsoleSupport(); /* Setup the DLL Object */ LoadedServerDll->ApiBase = CONSRV_FIRST_API_NUMBER;