* 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 ******************************************************************/
+/* INCLUDES *******************************************************************/
#define COBJMACROS
#define NONAMELESSUNION
#include "consrv.h"
-#include "settings.h"
-#include "guiconsole.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 "frontends/gui/guiterm.h"
#ifdef TUI_CONSOLE
- #include "tuiconsole.h"
+ #include "frontends/tui/tuiterm.h"
#endif
+#include "include/console.h"
+#include "console.h"
+#include "resource.h"
+
#include <shlwapi.h>
#include <shlobj.h>
-//#define NDEBUG
+#define NDEBUG
#include <debug.h>
+/* GLOBALS ********************************************************************/
-/* FUNCTIONS *****************************************************************/
+static LIST_ENTRY ConsoleList; /* The list of all the allocated consoles */
+static RTL_RESOURCE ListLock;
-BOOL FASTCALL
+#define ConSrvLockConsoleListExclusive() \
+ RtlAcquireResourceExclusive(&ListLock, TRUE)
+
+#define ConSrvLockConsoleListShared() \
+ RtlAcquireResourceShared(&ListLock, TRUE)
+
+#define ConSrvUnlockConsoleList() \
+ RtlReleaseResource(&ListLock)
+
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+#ifdef TUI_CONSOLE
+static BOOL
DtbgIsDesktopVisible(VOID)
{
return !((BOOL)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE));
}
+#endif
-VOID FASTCALL
+static ULONG
ConSrvConsoleCtrlEventTimeout(DWORD Event,
PCONSOLE_PROCESS_DATA ProcessData,
DWORD Timeout)
{
- HANDLE Thread;
+ ULONG Status = ERROR_SUCCESS;
- DPRINT("ConSrvConsoleCtrlEvent Parent ProcessId = %x\n", ProcessData->Process->ClientId.UniqueProcess);
+ DPRINT("ConSrvConsoleCtrlEventTimeout Parent ProcessId = %x\n", ProcessData->Process->ClientId.UniqueProcess);
if (ProcessData->CtrlDispatcher)
{
- Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0,
- ProcessData->CtrlDispatcher,
- UlongToPtr(Event), 0, NULL);
- if (NULL == Thread)
+ _SEH2_TRY
{
- DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
- return;
- }
+ HANDLE Thread = NULL;
- DPRINT1("We succeeded at creating ProcessData->CtrlDispatcher remote thread, ProcessId = %x, Process = 0x%p\n", ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process);
- WaitForSingleObject(Thread, Timeout);
- CloseHandle(Thread);
+ _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;
}
-VOID FASTCALL
-ConSrvConsoleCtrlEvent(DWORD Event, PCONSOLE_PROCESS_DATA ProcessData)
+static ULONG
+ConSrvConsoleCtrlEvent(DWORD Event,
+ PCONSOLE_PROCESS_DATA ProcessData)
+{
+ return ConSrvConsoleCtrlEventTimeout(Event, ProcessData, 0);
+}
+
+ULONG FASTCALL
+ConSrvConsoleProcessCtrlEvent(PCONSOLE Console,
+ ULONG ProcessGroupId,
+ DWORD Event)
{
- ConSrvConsoleCtrlEventTimeout(Event, ProcessData, 0);
+ 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;
}
VOID FASTCALL
}
}
+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)
+{
+ 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,
- OUT PCONSOLE_INFO ConsoleInfo,
+ IN OUT PCONSOLE_INFO ConsoleInfo,
OUT LPWSTR IconPath,
IN SIZE_T IconPathLength,
OUT PINT piIcon)
INT ShowCmd = 0;
// WORD HotKey = 0;
- /* Get the name of the shortcut */
- Length = min(Length - 4,
- sizeof(ConsoleStartInfo->ConsoleTitle) / sizeof(ConsoleStartInfo->ConsoleTitle[0]) - 1);
- wcsncpy(ConsoleStartInfo->ConsoleTitle, LinkName, Length);
- ConsoleStartInfo->ConsoleTitle[Length] = L'\0';
-
- // HACK: Copy also the name of the shortcut
- Length = min(Length,
+ /* 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';
NTSTATUS WINAPI
ConSrvInitConsole(OUT PCONSOLE* NewConsole,
- IN LPCWSTR AppPath,
IN OUT PCONSOLE_START_INFO ConsoleStartInfo,
IN PCSR_PROCESS ConsoleLeaderProcess)
{
ConsoleInfo.ConsoleTitle[Length] = L'\0';
/*
- * 3. Check whether the process creating the
- * console was launched via a shell-link
- * (ConsoleInfo.ConsoleTitle may be updated).
+ * 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.
*/
if (ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME)
{
* 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.ScreenBufferSize = ConsoleStartInfo->ScreenBufferSize;
}
- if (ConsoleStartInfo->dwStartupFlags & STARTF_USESHOWWINDOW)
- {
- ConsoleInfo.u.GuiInfo.ShowWindow = ConsoleStartInfo->ShowWindow;
- }
- if (ConsoleStartInfo->dwStartupFlags & STARTF_USEPOSITION)
- {
- ConsoleInfo.u.GuiInfo.AutoPosition = FALSE;
- ConsoleInfo.u.GuiInfo.WindowOrigin = ConsoleStartInfo->ConsoleWindowOrigin;
- }
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;
}
/*
if (ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN)
{
+ ConsoleInfo.FullScreen = TRUE;
}
*/
}
/*
* Initialize the console
*/
+ Console->State = CONSOLE_INITIALIZING;
InitializeCriticalSection(&Console->Lock);
Console->ReferenceCount = 0;
InitializeListHead(&Console->ProcessList);
memcpy(Console->Colors, ConsoleInfo.Colors, sizeof(ConsoleInfo.Colors));
- Console->Size = ConsoleInfo.ConsoleSize;
+ Console->ConsoleSize = ConsoleInfo.ConsoleSize;
/*
* 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);
return STATUS_UNSUCCESSFUL;
}
- // TODO: Use the values from ConsoleInfo.
- Console->InputBuffer.Mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT |
- ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT;
+ Console->InputBuffer.Mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
+ ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
Console->QuickEdit = ConsoleInfo.QuickEdit;
Console->InsertMode = ConsoleInfo.InsertMode;
InitializeListHead(&Console->InputBuffer.ReadWaitQueue);
ConsoleInfo.ScreenBufferSize,
ConsoleInfo.ScreenAttrib,
ConsoleInfo.PopupAttrib,
+ (ConsoleInfo.FullScreen ? CONSOLE_FULLSCREEN_MODE
+ : CONSOLE_WINDOWED_MODE),
TRUE,
ConsoleInfo.CursorSize);
if (!NT_SUCCESS(Status))
}
/* Make the new screen buffer active */
Console->ActiveBuffer = NewBuffer;
- Console->FullScreen = ConsoleInfo.FullScreen;
InitializeListHead(&Console->WriteWaitQueue);
/*
Console->HistoryNoDup = ConsoleInfo.HistoryNoDup;
/* Initialize the console title */
- RtlCreateUnicodeString(&Console->OriginalTitle, ConsoleStartInfo->ConsoleTitle);
- if (ConsoleStartInfo->ConsoleTitle[0] == L'\0')
+ RtlCreateUnicodeString(&Console->OriginalTitle, ConsoleInfo.ConsoleTitle);
+ if (ConsoleInfo.ConsoleTitle[0] == L'\0')
{
if (LoadStringW(ConSrvDllInstance, IDS_CONSOLE_TITLE, Title, sizeof(Title) / sizeof(Title[0])))
{
}
else
{
- RtlCreateUnicodeString(&Console->Title, ConsoleStartInfo->ConsoleTitle);
+ RtlCreateUnicodeString(&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.
if (!GuiMode)
{
DPRINT1("CONSRV: Opening text-mode terminal emulator\n");
- Status = TuiInitConsole(Console, &ConsoleInfo);
+ 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);
* - 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,
+ * terminal emulator (Win32k will automatically switch to graphical mode,
* therefore no additional code is needed).
*/
if (GuiMode)
{
DPRINT1("CONSRV: Opening GUI-mode terminal emulator\n");
Status = GuiInitConsole(Console,
- AppPath,
+ ConsoleStartInfo,
&ConsoleInfo,
+ ProcessId,
IconPath,
iIcon);
if (!NT_SUCCESS(Status))
RtlFreeUnicodeString(&Console->OriginalTitle);
ConioDeleteScreenBuffer(NewBuffer);
CloseHandle(Console->InputBuffer.ActiveEvent);
+ // LeaveCriticalSection(&Console->Lock);
DeleteCriticalSection(&Console->Lock);
RtlFreeHeap(ConSrvHeap, 0, 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");
/* Return the newly created console to the caller and a success code too */
*NewConsole = Console;
return STATUS_SUCCESS;
}
-VOID WINAPI
-ConSrvInitConsoleSupport(VOID)
-{
- DPRINT("CONSRV: ConSrvInitConsoleSupport()\n");
-
- /* Should call LoadKeyboardLayout */
-}
-
VOID WINAPI
ConSrvDeleteConsole(PCONSOLE Console)
{
- ConsoleInput *Event;
-
DPRINT("ConSrvDeleteConsole\n");
- /* Drain input event queue */
- while (Console->InputBuffer.InputEvents.Flink != &Console->InputBuffer.InputEvents)
+ /*
+ * 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))
{
- Event = (ConsoleInput *) Console->InputBuffer.InputEvents.Flink;
- Console->InputBuffer.InputEvents.Flink = Console->InputBuffer.InputEvents.Flink->Flink;
- Console->InputBuffer.InputEvents.Flink->Flink->Blink = &Console->InputBuffer.InputEvents;
- RtlFreeHeap(ConSrvHeap, 0, Event);
+ /* Unlock the console list and return */
+ ConSrvUnlockConsoleList();
+ return;
}
- ConioCleanupConsole(Console);
- if (Console->LineBuffer)
- RtlFreeHeap(ConSrvHeap, 0, Console->LineBuffer);
- while (!IsListEmpty(&Console->HistoryBuffers))
- HistoryDeleteBuffer((struct _HISTORY_BUFFER *)Console->HistoryBuffers.Flink);
-
- ConioDeleteScreenBuffer(Console->ActiveBuffer);
- if (!IsListEmpty(&Console->BufferList))
+ /*
+ * If the console is already being destroyed
+ * (thus not running), just return.
+ */
+ if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
{
- DPRINT1("BUG: screen buffer list not empty\n");
+ /* Unlock the console list and return */
+ ConSrvUnlockConsoleList();
+ return;
}
- CloseHandle(Console->InputBuffer.ActiveEvent);
- if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent);
- DeleteCriticalSection(&Console->Lock);
+ /*
+ * 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;
- RtlFreeUnicodeString(&Console->OriginalTitle);
- RtlFreeUnicodeString(&Console->Title);
- IntDeleteAllAliases(Console->Aliases);
- RtlFreeHeap(ConSrvHeap, 0, Console);
-}
+ /*
+ * 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();
-CSR_API(SrvOpenConsole)
-{
- NTSTATUS Status = STATUS_SUCCESS;
- PCONSOLE_OPENCONSOLE OpenConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.OpenConsoleRequest;
- PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
+ /* FIXME: Send a terminate message to all the processes owning this console */
- DPRINT("SrvOpenConsole\n");
+ /* Cleanup the UI-oriented part */
+ ConioCleanupConsole(Console);
- OpenConsoleRequest->ConsoleHandle = INVALID_HANDLE_VALUE;
+ /***
+ * 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 ?).
+ ***/
- RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+ ConSrvLockConsoleListExclusive();
- DPRINT1("ProcessData = 0x%p ; ProcessData->Console = 0x%p\n", ProcessData, ProcessData->Console);
+ /* 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 (ProcessData->Console)
+ if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_TERMINATING, TRUE))
{
- DWORD DesiredAccess = OpenConsoleRequest->Access;
- DWORD ShareMode = OpenConsoleRequest->ShareMode;
+ ConSrvUnlockConsoleList();
+ return;
+ }
- PCONSOLE Console = ProcessData->Console;
- Object_t *Object;
+ /* We are in destruction */
+ Console->State = CONSOLE_IN_DESTRUCTION;
- DPRINT1("SrvOpenConsole - Checkpoint 1\n");
- EnterCriticalSection(&Console->Lock);
- DPRINT1("SrvOpenConsole - Checkpoint 2\n");
+ /* Remove the console from the list */
+ RemoveEntryList(&Console->Entry);
- if (OpenConsoleRequest->HandleType == HANDLE_OUTPUT)
- {
- Object = &Console->ActiveBuffer->Header;
- }
- else // HANDLE_INPUT
- {
- Object = &Console->InputBuffer.Header;
- }
+ /* Reset the count to be sure */
+ Console->ReferenceCount = 0;
- 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);
- }
+ /* Discard all entries in the input event queue */
+ PurgeInputBuffer(Console);
+
+ if (Console->LineBuffer) RtlFreeHeap(ConSrvHeap, 0, Console->LineBuffer);
+
+ IntDeleteAllAliases(Console);
+ HistoryDeleteBuffers(Console);
- LeaveCriticalSection(&Console->Lock);
+ ConioDeleteScreenBuffer(Console->ActiveBuffer);
+ if (!IsListEmpty(&Console->BufferList))
+ {
+ DPRINT1("BUG: screen buffer list not empty\n");
}
- RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+ // CloseHandle(Console->InputBuffer.ActiveEvent);
+ if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent);
- return Status;
+ RtlFreeUnicodeString(&Console->OriginalTitle);
+ RtlFreeUnicodeString(&Console->Title);
+
+ DPRINT("ConSrvDeleteConsole - Unlocking\n");
+ LeaveCriticalSection(&Console->Lock);
+ DPRINT("ConSrvDeleteConsole - Destroying lock\n");
+ DeleteCriticalSection(&Console->Lock);
+ DPRINT("ConSrvDeleteConsole - Lock destroyed ; freeing console\n");
+
+ RtlFreeHeap(ConSrvHeap, 0, Console);
+ DPRINT("ConSrvDeleteConsole - Console freed\n");
+
+ /* Unlock the console list and return */
+ ConSrvUnlockConsoleList();
}
+
+/* PUBLIC SERVER APIS *********************************************************/
+
CSR_API(SrvAllocConsole)
{
NTSTATUS Status = STATUS_SUCCESS;
PCSR_PROCESS CsrProcess = CsrGetClientThread()->Process;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
- DPRINT("SrvAllocConsole\n");
-
if (ProcessData->Console != NULL)
{
DPRINT1("Process already has a console\n");
return STATUS_ACCESS_DENIED;
}
- if ( !CsrValidateMessageBuffer(ApiMessage,
- (PVOID*)&AllocConsoleRequest->ConsoleStartInfo,
- 1,
- sizeof(CONSOLE_START_INFO)) ||
- !CsrValidateMessageBuffer(ApiMessage,
- (PVOID*)&AllocConsoleRequest->AppPath,
- MAX_PATH + 1,
- sizeof(WCHAR)) )
+ if (!CsrValidateMessageBuffer(ApiMessage,
+ (PVOID*)&AllocConsoleRequest->ConsoleStartInfo,
+ 1,
+ sizeof(CONSOLE_START_INFO)))
{
return STATUS_INVALID_PARAMETER;
}
* and recreate a new one later on.
*/
ConSrvRemoveConsole(ProcessData);
- // ConSrvFreeHandlesTable(ProcessData);
/* Initialize a new Console owned by the Console Leader Process */
Status = ConSrvAllocateConsole(ProcessData,
- AllocConsoleRequest->AppPath,
&AllocConsoleRequest->InputHandle,
&AllocConsoleRequest->OutputHandle,
&AllocConsoleRequest->ErrorHandle,
/* Set the Ctrl Dispatcher */
ProcessData->CtrlDispatcher = AllocConsoleRequest->CtrlDispatcher;
- DPRINT("CONSRV: CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher);
return STATUS_SUCCESS;
}
HANDLE ProcessId = ULongToHandle(AttachConsoleRequest->ProcessId);
PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData;
- DPRINT("SrvAttachConsole\n");
-
TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
if (TargetProcessData->Console != NULL)
return Status;
}
- DPRINT("We, process (ID) %lu;%lu\n", TargetProcess->ClientId.UniqueProcess, TargetProcess->ClientId.UniqueThread);
ProcessId = ULongToHandle(ProcessInfo.InheritedFromUniqueProcessId);
- DPRINT("Parent process ID = %lu\n", ProcessId);
}
/* Lock the source process via its PID */
Status = CsrLockProcessByClientId(ProcessId, &SourceProcess);
- DPRINT1("Lock process Id %lu - Status %lu\n", ProcessId, Status);
if (!NT_SUCCESS(Status)) return Status;
SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
- DPRINT1("SourceProcessData->Console = 0x%p\n", SourceProcessData->Console);
if (SourceProcessData->Console == NULL)
{
Status = STATUS_INVALID_HANDLE;
* and recreate a new one later on.
*/
ConSrvRemoveConsole(TargetProcessData);
- // ConSrvFreeHandlesTable(TargetProcessData);
/*
* Inherit the console from the parent,
/* Set the Ctrl Dispatcher */
TargetProcessData->CtrlDispatcher = AttachConsoleRequest->CtrlDispatcher;
- DPRINT("CONSRV: CtrlDispatcher address: %x\n", TargetProcessData->CtrlDispatcher);
Status = STATUS_SUCCESS;
CSR_API(SrvFreeConsole)
{
- DPRINT1("SrvFreeConsole\n");
ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process));
return STATUS_SUCCESS;
}
-CSR_API(SrvSetConsoleMode)
+CSR_API(SrvGetConsoleMode)
{
-#define CONSOLE_INPUT_MODE_VALID ( ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | \
- ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT | \
- ENABLE_MOUSE_INPUT | \
- ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS )
-#define CONSOLE_OUTPUT_MODE_VALID ( ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT )
-
NTSTATUS Status;
PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
- Object_t* Object = NULL;
-
- DPRINT("SrvSetConsoleMode\n");
+ PCONSOLE_IO_OBJECT Object = NULL;
Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
- ConsoleModeRequest->ConsoleHandle,
- &Object, NULL, GENERIC_WRITE, TRUE, 0);
+ ConsoleModeRequest->ConsoleHandle,
+ &Object, NULL, GENERIC_READ, TRUE, 0);
if (!NT_SUCCESS(Status)) return Status;
Status = STATUS_SUCCESS;
- if (CONIO_INPUT_BUFFER_MAGIC == Object->Type)
+ if (INPUT_BUFFER == Object->Type)
{
PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
- InputBuffer->Mode = ConsoleModeRequest->ConsoleMode & CONSOLE_INPUT_MODE_VALID;
+ 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 (CONIO_SCREEN_BUFFER_MAGIC == Object->Type)
+ else if (SCREEN_BUFFER == Object->Type)
{
PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
- Buffer->Mode = ConsoleModeRequest->ConsoleMode & CONSOLE_OUTPUT_MODE_VALID;
+ ConsoleModeRequest->ConsoleMode = Buffer->Mode;
}
else
{
}
ConSrvReleaseObject(Object, TRUE);
-
return Status;
}
-CSR_API(SrvGetConsoleMode)
+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;
- Object_t* Object = NULL;
-
- DPRINT("SrvGetConsoleMode\n");
+ DWORD ConsoleMode = ConsoleModeRequest->ConsoleMode;
+ PCONSOLE_IO_OBJECT Object = NULL;
Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
- ConsoleModeRequest->ConsoleHandle,
- &Object, NULL, GENERIC_READ, TRUE, 0);
+ ConsoleModeRequest->ConsoleHandle,
+ &Object, NULL, GENERIC_WRITE, TRUE, 0);
if (!NT_SUCCESS(Status)) return Status;
Status = STATUS_SUCCESS;
- if (CONIO_INPUT_BUFFER_MAGIC == Object->Type)
+ if (INPUT_BUFFER == Object->Type)
{
PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
- ConsoleModeRequest->ConsoleMode = InputBuffer->Mode;
+ 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 (CONIO_SCREEN_BUFFER_MAGIC == Object->Type)
+ else if (SCREEN_BUFFER == Object->Type)
{
PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
- ConsoleModeRequest->ConsoleMode = Buffer->Mode;
+
+ 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;
}
-CSR_API(SrvSetConsoleTitle)
+CSR_API(SrvGetConsoleTitle)
{
NTSTATUS Status;
PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
// PCSR_PROCESS Process = CsrGetClientThread()->Process;
PCONSOLE Console;
- PWCHAR Buffer;
-
- DPRINT("SrvSetConsoleTitle\n");
+ DWORD Length;
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID)&TitleRequest->Title,
return Status;
}
- /* Allocate a new buffer to hold the new title (NULL-terminated) */
- Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, TitleRequest->Length + sizeof(WCHAR));
- if (Buffer)
- {
- /* Free the old title */
- RtlFreeUnicodeString(&Console->Title);
-
- /* 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
+ /* Copy title of the console to the user title buffer */
+ if (TitleRequest->Length >= sizeof(WCHAR))
{
- Status = STATUS_NO_MEMORY;
+ 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;
+ return STATUS_SUCCESS;
}
-CSR_API(SrvGetConsoleTitle)
+CSR_API(SrvSetConsoleTitle)
{
NTSTATUS Status;
PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
// PCSR_PROCESS Process = CsrGetClientThread()->Process;
PCONSOLE Console;
- DWORD Length;
-
- DPRINT("SrvGetConsoleTitle\n");
+ PWCHAR Buffer;
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID)&TitleRequest->Title,
return Status;
}
- /* Copy title of the console to the user title buffer */
- if (TitleRequest->Length >= sizeof(WCHAR))
+ /* Allocate a new buffer to hold the new title (NULL-terminated) */
+ Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, TitleRequest->Length + sizeof(WCHAR));
+ if (Buffer)
{
- Length = min(TitleRequest->Length - sizeof(WCHAR), Console->Title.Length);
- memcpy(TitleRequest->Title, Console->Title.Buffer, Length);
- TitleRequest->Title[Length / sizeof(WCHAR)] = L'\0';
- }
+ /* Free the old title */
+ RtlFreeUnicodeString(&Console->Title);
- TitleRequest->Length = Console->Title.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_SUCCESS;
+ return Status;
}
/**********************************************************************
* with NT's, but values are not.
*/
static NTSTATUS FASTCALL
-SetConsoleHardwareState(PCONSOLE Console, DWORD ConsoleHwState)
+SetConsoleHardwareState(PCONSOLE Console, ULONG ConsoleHwState)
{
DPRINT1("Console Hardware State: %d\n", ConsoleHwState);
PCONSOLE_SCREEN_BUFFER Buff;
PCONSOLE Console;
- DPRINT("SrvGetConsoleHardwareState\n");
-
Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
HardwareStateRequest->OutputHandle,
&Buff,
HardwareStateRequest->State = Console->HardwareState;
ConSrvReleaseScreenBuffer(Buff, TRUE);
-
return Status;
}
PCONSOLE_SCREEN_BUFFER Buff;
PCONSOLE Console;
- DPRINT("SrvSetConsoleHardwareState\n");
-
Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
HardwareStateRequest->OutputHandle,
&Buff,
- GENERIC_READ,
+ GENERIC_WRITE,
TRUE);
if (!NT_SUCCESS(Status))
{
Status = SetConsoleHardwareState(Console, HardwareStateRequest->State);
ConSrvReleaseScreenBuffer(Buff, TRUE);
+ return Status;
+}
+CSR_API(SrvGetConsoleDisplayMode)
+{
+ NTSTATUS Status;
+ PCONSOLE_GETDISPLAYMODE GetDisplayModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetDisplayModeRequest;
+ PCONSOLE Console;
+ ULONG DisplayMode = 0;
+
+ Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
+ &Console, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to get console handle in SrvGetConsoleDisplayMode\n");
+ return Status;
+ }
+
+ if (Console->ActiveBuffer->DisplayMode & CONSOLE_FULLSCREEN_MODE)
+ DisplayMode |= CONSOLE_FULLSCREEN_HARDWARE; // CONSOLE_FULLSCREEN
+ else if (Console->ActiveBuffer->DisplayMode & CONSOLE_WINDOWED_MODE)
+ DisplayMode |= CONSOLE_WINDOWED;
+
+ GetDisplayModeRequest->DisplayMode = DisplayMode;
+ Status = STATUS_SUCCESS;
+
+ ConSrvReleaseConsole(Console, TRUE);
+ return Status;
+}
+
+CSR_API(SrvSetConsoleDisplayMode)
+{
+ NTSTATUS Status;
+ PCONSOLE_SETDISPLAYMODE SetDisplayModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetDisplayModeRequest;
+ PCONSOLE_SCREEN_BUFFER Buff;
+
+ Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
+ SetDisplayModeRequest->OutputHandle,
+ &Buff,
+ GENERIC_WRITE,
+ TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to get console handle in SrvSetConsoleDisplayMode\n");
+ return Status;
+ }
+
+ if (SetDisplayModeRequest->DisplayMode & ~(CONSOLE_FULLSCREEN_MODE | CONSOLE_WINDOWED_MODE))
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ Buff->DisplayMode = SetDisplayModeRequest->DisplayMode;
+ // TODO: Change the display mode
+ SetDisplayModeRequest->NewSBDim = Buff->ScreenBufferSize;
+
+ Status = STATUS_SUCCESS;
+ }
+
+ ConSrvReleaseScreenBuffer(Buff, TRUE);
return Status;
}
PCONSOLE_GETWINDOW GetWindowRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetWindowRequest;
PCONSOLE Console;
- DPRINT("SrvGetConsoleWindow\n");
-
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (!NT_SUCCESS(Status)) return Status;
- GetWindowRequest->WindowHandle = Console->TermIFace.Vtbl->GetConsoleWindowHandle(Console);
+ GetWindowRequest->WindowHandle = ConioGetConsoleWindowHandle(Console);
ConSrvReleaseConsole(Console, TRUE);
return STATUS_SUCCESS;
PCONSOLE_SETICON SetIconRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetIconRequest;
PCONSOLE Console;
- DPRINT("SrvSetConsoleIcon\n");
-
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (!NT_SUCCESS(Status)) return Status;
PLIST_ENTRY current_entry;
ULONG nItems = 0;
- DPRINT("SrvGetConsoleProcessList\n");
-
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID)&GetProcessListRequest->pProcessIds,
GetProcessListRequest->nMaxIds,
NTSTATUS Status;
PCONSOLE_GENERATECTRLEVENT GenerateCtrlEventRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GenerateCtrlEventRequest;
PCONSOLE Console;
- PCONSOLE_PROCESS_DATA current;
- PLIST_ENTRY current_entry;
- DWORD Group;
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (!NT_SUCCESS(Status)) return Status;
- Group = GenerateCtrlEventRequest->ProcessGroup;
- Status = STATUS_INVALID_PARAMETER;
- 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 (Group == 0 || current->Process->ProcessGroupId == Group)
- {
- ConSrvConsoleCtrlEvent(GenerateCtrlEventRequest->Event, current);
- Status = STATUS_SUCCESS;
- }
- }
+ Status = ConSrvConsoleProcessCtrlEvent(Console,
+ GenerateCtrlEventRequest->ProcessGroup,
+ GenerateCtrlEventRequest->Event);
ConSrvReleaseConsole(Console, TRUE);
-
return Status;
}