* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/consrv/console.c
- * PURPOSE: Console I/O functions
- * PROGRAMMERS:
+ * PURPOSE: Console Management Functions
+ * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
*/
/* INCLUDES *******************************************************************/
#define NONAMELESSUNION
#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 "settings.h"
+#include "include/settings.h"
#include "frontends/gui/guiterm.h"
#include "frontends/tui/tuiterm.h"
#endif
+#include "include/console.h"
#include "console.h"
#include "resource.h"
}
}
+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
+ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData,
+ PCONSOLE* Console,
+ BOOL LockConsole)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PCONSOLE ProcessConsole;
+
+ RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+ ProcessConsole = ProcessData->Console;
+
+ if (ConSrvValidateConsole(ProcessConsole, CONSOLE_RUNNING, LockConsole))
+ {
+ InterlockedIncrement(&ProcessConsole->ReferenceCount);
+ *Console = ProcessConsole;
+ }
+ else
+ {
+ *Console = NULL;
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+ return Status;
+}
+
+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);
+}
+
VOID WINAPI
ConSrvInitConsoleSupport(VOID)
{
/*
* Initialize the input buffer
*/
- Console->InputBuffer.Header.Type = CONIO_INPUT_BUFFER_MAGIC;
+ Console->InputBuffer.Header.Type = INPUT_BUFFER;
Console->InputBuffer.Header.Console = Console;
SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
VOID WINAPI
ConSrvDeleteConsole(PCONSOLE Console)
{
- PLIST_ENTRY CurrentEntry;
- ConsoleInput* Event;
-
DPRINT("ConSrvDeleteConsole\n");
/*
Console->ReferenceCount = 0;
/* Discard all entries in the input event queue */
- while (!IsListEmpty(&Console->InputBuffer.InputEvents))
- {
- CurrentEntry = RemoveHeadList(&Console->InputBuffer.InputEvents);
- Event = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
- RtlFreeHeap(ConSrvHeap, 0, Event);
- }
+ PurgeInputBuffer(Console);
- if (Console->LineBuffer)
- RtlFreeHeap(ConSrvHeap, 0, Console->LineBuffer);
+ if (Console->LineBuffer) RtlFreeHeap(ConSrvHeap, 0, Console->LineBuffer);
+ IntDeleteAllAliases(Console);
HistoryDeleteBuffers(Console);
ConioDeleteScreenBuffer(Console->ActiveBuffer);
DPRINT1("BUG: screen buffer list not empty\n");
}
- CloseHandle(Console->InputBuffer.ActiveEvent);
+ // CloseHandle(Console->InputBuffer.ActiveEvent);
if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent);
RtlFreeUnicodeString(&Console->OriginalTitle);
RtlFreeUnicodeString(&Console->Title);
- IntDeleteAllAliases(Console->Aliases);
DPRINT("ConSrvDeleteConsole - Unlocking\n");
LeaveCriticalSection(&Console->Lock);
ConSrvUnlockConsoleList();
}
-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;
-}
-
/* PUBLIC SERVER APIS *********************************************************/
-CSR_API(SrvOpenConsole)
-{
- NTSTATUS Status;
- PCONSOLE_OPENCONSOLE OpenConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.OpenConsoleRequest;
- PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
- PCONSOLE Console;
-
- DWORD DesiredAccess = OpenConsoleRequest->Access;
- DWORD ShareMode = OpenConsoleRequest->ShareMode;
- Object_t *Object;
-
- OpenConsoleRequest->ConsoleHandle = INVALID_HANDLE_VALUE;
-
- Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("Can't get console\n");
- return Status;
- }
-
- RtlEnterCriticalSection(&ProcessData->HandleTableLock);
-
- /*
- * Open a handle to either the active screen buffer or the input buffer.
- */
- if (OpenConsoleRequest->HandleType == HANDLE_OUTPUT)
- {
- Object = &Console->ActiveBuffer->Header;
- }
- else // HANDLE_INPUT
- {
- Object = &Console->InputBuffer.Header;
- }
-
- if (((DesiredAccess & GENERIC_READ) && Object->ExclusiveRead != 0) ||
- ((DesiredAccess & GENERIC_WRITE) && Object->ExclusiveWrite != 0) ||
- (!(ShareMode & FILE_SHARE_READ) && Object->AccessRead != 0) ||
- (!(ShareMode & FILE_SHARE_WRITE) && Object->AccessWrite != 0))
- {
- DPRINT1("Sharing violation\n");
- Status = STATUS_SHARING_VIOLATION;
- }
- else
- {
- Status = ConSrvInsertObject(ProcessData,
- &OpenConsoleRequest->ConsoleHandle,
- Object,
- DesiredAccess,
- OpenConsoleRequest->Inheritable,
- ShareMode);
- }
-
- RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-
- ConSrvReleaseConsole(Console, TRUE);
- return Status;
-}
-
CSR_API(SrvAllocConsole)
{
NTSTATUS Status = STATUS_SUCCESS;
return STATUS_SUCCESS;
}
+CSR_API(SrvGetConsoleMode)
+{
+ NTSTATUS Status;
+ PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
+ PCONSOLE_IO_OBJECT Object = NULL;
+
+ 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 (SCREEN_BUFFER == Object->Type)
+ {
+ PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
+ ConsoleModeRequest->ConsoleMode = Buffer->Mode;
+ }
+ else
+ {
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ ConSrvReleaseObject(Object, TRUE);
+ return Status;
+}
+
CSR_API(SrvSetConsoleMode)
{
#define CONSOLE_VALID_CONTROL_MODES ( ENABLE_EXTENDED_FLAGS | ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE )
NTSTATUS Status;
PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
DWORD ConsoleMode = ConsoleModeRequest->ConsoleMode;
- Object_t* Object = NULL;
+ PCONSOLE_IO_OBJECT Object = NULL;
Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
ConsoleModeRequest->ConsoleHandle,
Status = STATUS_SUCCESS;
- if (CONIO_INPUT_BUFFER_MAGIC == Object->Type)
+ if (INPUT_BUFFER == Object->Type)
{
PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
PCONSOLE Console = InputBuffer->Header.Console;
}
InputBuffer->Mode = (ConsoleMode & CONSOLE_VALID_INPUT_MODES);
}
- else if (CONIO_SCREEN_BUFFER_MAGIC == Object->Type)
+ else if (SCREEN_BUFFER == Object->Type)
{
PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
return Status;
}
-CSR_API(SrvGetConsoleMode)
+CSR_API(SrvGetConsoleTitle)
{
NTSTATUS Status;
- PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
- Object_t* Object = NULL;
-
- Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
- ConsoleModeRequest->ConsoleHandle,
- &Object, NULL, GENERIC_READ, TRUE, 0);
- if (!NT_SUCCESS(Status)) return Status;
-
- Status = STATUS_SUCCESS;
+ PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
+ // PCSR_PROCESS Process = CsrGetClientThread()->Process;
+ PCONSOLE Console;
+ DWORD Length;
- if (CONIO_INPUT_BUFFER_MAGIC == Object->Type)
+ if (!CsrValidateMessageBuffer(ApiMessage,
+ (PVOID)&TitleRequest->Title,
+ TitleRequest->Length,
+ sizeof(BYTE)))
{
- 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;
+ return STATUS_INVALID_PARAMETER;
}
- else if (CONIO_SCREEN_BUFFER_MAGIC == Object->Type)
+
+ Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
+ if (!NT_SUCCESS(Status))
{
- PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
- ConsoleModeRequest->ConsoleMode = Buffer->Mode;
+ DPRINT1("Can't get console\n");
+ return Status;
}
- else
+
+ /* Copy title of the console to the user title buffer */
+ if (TitleRequest->Length >= sizeof(WCHAR))
{
- Status = STATUS_INVALID_HANDLE;
+ Length = min(TitleRequest->Length - sizeof(WCHAR), Console->Title.Length);
+ memcpy(TitleRequest->Title, Console->Title.Buffer, Length);
+ TitleRequest->Title[Length / sizeof(WCHAR)] = L'\0';
}
- ConSrvReleaseObject(Object, TRUE);
- return Status;
+ TitleRequest->Length = Console->Title.Length;
+
+ ConSrvReleaseConsole(Console, TRUE);
+ return STATUS_SUCCESS;
}
CSR_API(SrvSetConsoleTitle)
return Status;
}
-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,
- TitleRequest->Length,
- sizeof(BYTE)))
- {
- return STATUS_INVALID_PARAMETER;
- }
-
- Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("Can't get console\n");
- 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;
-
- ConSrvReleaseConsole(Console, TRUE);
- return STATUS_SUCCESS;
-}
-
/**********************************************************************
* HardwareStateProperty
*