2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/consrv/console.c
5 * PURPOSE: Console Management Functions
6 * PROGRAMMERS: Gé van Geldorp
8 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
11 /* INCLUDES *******************************************************************/
14 #define NONAMELESSUNION
17 #include "include/conio.h"
23 #include "conoutput.h"
24 #include "lineinput.h"
25 #include "include/settings.h"
27 #include "frontends/gui/guiterm.h"
28 #include "frontends/tui/tuiterm.h"
30 #include "include/console.h"
40 /* GLOBALS ********************************************************************/
42 static LIST_ENTRY ConsoleList
; /* The list of all the allocated consoles */
43 static RTL_RESOURCE ListLock
;
45 #define ConSrvLockConsoleListExclusive() \
46 RtlAcquireResourceExclusive(&ListLock, TRUE)
48 #define ConSrvLockConsoleListShared() \
49 RtlAcquireResourceShared(&ListLock, TRUE)
51 #define ConSrvUnlockConsoleList() \
52 RtlReleaseResource(&ListLock)
54 // Adapted from reactos/lib/rtl/unicode.c, RtlCreateUnicodeString line 2180
56 ConsoleCreateUnicodeString(IN OUT PUNICODE_STRING UniDest
,
59 SIZE_T Size
= (wcslen(Source
) + 1) * sizeof(WCHAR
);
60 if (Size
> MAXUSHORT
) return FALSE
;
62 UniDest
->Buffer
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, Size
);
63 if (UniDest
->Buffer
== NULL
) return FALSE
;
65 RtlCopyMemory(UniDest
->Buffer
, Source
, Size
);
66 UniDest
->MaximumLength
= (USHORT
)Size
;
67 UniDest
->Length
= (USHORT
)Size
- sizeof(WCHAR
);
72 // Adapted from reactos/lib/rtl/unicode.c, RtlFreeUnicodeString line 431
74 ConsoleFreeUnicodeString(IN PUNICODE_STRING UnicodeString
)
76 if (UnicodeString
->Buffer
)
78 ConsoleFreeHeap(UnicodeString
->Buffer
);
79 RtlZeroMemory(UnicodeString
, sizeof(UNICODE_STRING
));
84 /* PRIVATE FUNCTIONS **********************************************************/
87 DtbgIsDesktopVisible(VOID
)
89 return !((BOOL
)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE
));
93 ConSrvConsoleCtrlEventTimeout(DWORD Event
,
94 PCONSOLE_PROCESS_DATA ProcessData
,
97 ULONG Status
= ERROR_SUCCESS
;
99 DPRINT("ConSrvConsoleCtrlEventTimeout Parent ProcessId = %x\n", ProcessData
->Process
->ClientId
.UniqueProcess
);
101 if (ProcessData
->CtrlDispatcher
)
105 HANDLE Thread
= NULL
;
109 Thread
= CreateRemoteThread(ProcessData
->Process
->ProcessHandle
, NULL
, 0,
110 ProcessData
->CtrlDispatcher
,
111 UlongToPtr(Event
), 0, NULL
);
114 Status
= GetLastError();
115 DPRINT1("Failed thread creation (Error: 0x%x)\n", Status
);
119 DPRINT("ProcessData->CtrlDispatcher remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n", ProcessData
->Process
->ClientId
.UniqueProcess
, ProcessData
->Process
);
120 WaitForSingleObject(Thread
, Timeout
);
129 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
131 Status
= RtlNtStatusToDosError(_SEH2_GetExceptionCode());
132 DPRINT1("ConSrvConsoleCtrlEventTimeout - Caught an exception, Status = %08X\n", Status
);
141 ConSrvConsoleCtrlEvent(DWORD Event
,
142 PCONSOLE_PROCESS_DATA ProcessData
)
144 return ConSrvConsoleCtrlEventTimeout(Event
, ProcessData
, 0);
148 ConSrvConsoleProcessCtrlEvent(PCONSOLE Console
,
149 ULONG ProcessGroupId
,
152 ULONG Status
= ERROR_SUCCESS
;
153 PLIST_ENTRY current_entry
;
154 PCONSOLE_PROCESS_DATA current
;
156 /* If the console is already being destroyed, just return */
157 if (!ConSrvValidateConsole(Console
, CONSOLE_RUNNING
, FALSE
))
158 return STATUS_UNSUCCESSFUL
;
161 * Loop through the process list, from the most recent process
162 * (the active one) to the oldest one (the first created, i.e.
163 * the console leader process), and for each, send an event
164 * (new processes are inserted at the head of the console process list).
166 current_entry
= Console
->ProcessList
.Flink
;
167 while (current_entry
!= &Console
->ProcessList
)
169 current
= CONTAINING_RECORD(current_entry
, CONSOLE_PROCESS_DATA
, ConsoleLink
);
170 current_entry
= current_entry
->Flink
;
173 * Only processes belonging to the same process group are signaled.
174 * If the process group ID is zero, then all the processes are signaled.
176 if (ProcessGroupId
== 0 || current
->Process
->ProcessGroupId
== ProcessGroupId
)
178 Status
= ConSrvConsoleCtrlEvent(Event
, current
);
186 ConioPause(PCONSOLE Console
, UINT Flags
)
188 Console
->PauseFlags
|= Flags
;
189 if (!Console
->UnpauseEvent
)
190 Console
->UnpauseEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
194 ConioUnpause(PCONSOLE Console
, UINT Flags
)
196 Console
->PauseFlags
&= ~Flags
;
198 // if ((Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION)) == 0)
199 if (Console
->PauseFlags
== 0 && Console
->UnpauseEvent
)
201 SetEvent(Console
->UnpauseEvent
);
202 CloseHandle(Console
->UnpauseEvent
);
203 Console
->UnpauseEvent
= NULL
;
205 CsrNotifyWait(&Console
->WriteWaitQueue
,
209 if (!IsListEmpty(&Console
->WriteWaitQueue
))
211 CsrDereferenceWait(&Console
->WriteWaitQueue
);
217 ConSrvValidateConsolePointer(PCONSOLE Console
)
219 PLIST_ENTRY ConsoleEntry
;
220 PCONSOLE CurrentConsole
= NULL
;
222 if (!Console
) return FALSE
;
224 /* The console list must be locked */
225 // ASSERT(Console_list_locked);
227 ConsoleEntry
= ConsoleList
.Flink
;
228 while (ConsoleEntry
!= &ConsoleList
)
230 CurrentConsole
= CONTAINING_RECORD(ConsoleEntry
, CONSOLE
, Entry
);
231 ConsoleEntry
= ConsoleEntry
->Flink
;
232 if (CurrentConsole
== Console
) return TRUE
;
239 ConSrvValidateConsoleState(PCONSOLE Console
,
240 CONSOLE_STATE ExpectedState
)
242 // if (!Console) return FALSE;
244 /* The console must be locked */
245 // ASSERT(Console_locked);
247 return (Console
->State
== ExpectedState
);
251 ConSrvValidateConsoleUnsafe(PCONSOLE Console
,
252 CONSOLE_STATE ExpectedState
,
255 if (!Console
) return FALSE
;
258 * Lock the console to forbid possible console's state changes
259 * (which must be done when the console is already locked).
260 * If we don't want to lock it, it's because the lock is already
261 * held. So there must be no problems.
263 if (LockConsole
) EnterCriticalSection(&Console
->Lock
);
265 // ASSERT(Console_locked);
267 /* Check whether the console's state is what we expect */
268 if (!ConSrvValidateConsoleState(Console
, ExpectedState
))
270 if (LockConsole
) LeaveCriticalSection(&Console
->Lock
);
278 ConSrvValidateConsole(PCONSOLE Console
,
279 CONSOLE_STATE ExpectedState
,
284 if (!Console
) return FALSE
;
287 * Forbid creation or deletion of consoles when
288 * checking for the existence of a console.
290 ConSrvLockConsoleListShared();
292 if (ConSrvValidateConsolePointer(Console
))
294 RetVal
= ConSrvValidateConsoleUnsafe(Console
,
299 /* Unlock the console list and return */
300 ConSrvUnlockConsoleList();
306 ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData
,
310 NTSTATUS Status
= STATUS_SUCCESS
;
311 PCONSOLE ProcessConsole
;
313 // RtlEnterCriticalSection(&ProcessData->HandleTableLock);
314 ProcessConsole
= ProcessData
->Console
;
316 if (ConSrvValidateConsole(ProcessConsole
, CONSOLE_RUNNING
, LockConsole
))
318 InterlockedIncrement(&ProcessConsole
->ReferenceCount
);
319 *Console
= ProcessConsole
;
324 Status
= STATUS_INVALID_HANDLE
;
327 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
332 ConSrvReleaseConsole(PCONSOLE Console
,
333 BOOL WasConsoleLocked
)
337 if (!Console
) return;
338 // if (Console->ReferenceCount == 0) return; // This shouldn't happen
339 ASSERT(Console
->ReferenceCount
> 0);
341 /* The console must be locked */
342 // ASSERT(Console_locked);
345 * Decrement the reference count. Save the new value too,
346 * because Console->ReferenceCount might be modified after
347 * the console gets unlocked but before we check whether we
350 RefCount
= _InterlockedDecrement(&Console
->ReferenceCount
);
352 /* Unlock the console if needed */
353 if (WasConsoleLocked
) LeaveCriticalSection(&Console
->Lock
);
355 /* Delete the console if needed */
356 if (RefCount
<= 0) ConSrvDeleteConsole(Console
);
360 ConSrvInitConsoleSupport(VOID
)
362 DPRINT("CONSRV: ConSrvInitConsoleSupport()\n");
364 /* Initialize the console list and its lock */
365 InitializeListHead(&ConsoleList
);
366 RtlInitializeResource(&ListLock
);
368 /* Should call LoadKeyboardLayout */
372 LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo
,
373 IN OUT PCONSOLE_INFO ConsoleInfo
,
375 IN SIZE_T IconPathLength
,
378 #define PATH_SEPARATOR L'\\'
382 LPWSTR LinkName
= NULL
;
385 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
388 if (IconPath
== NULL
|| piIcon
== NULL
)
394 /* 1- Find the last path separator if any */
395 LinkName
= wcsrchr(ConsoleStartInfo
->ConsoleTitle
, PATH_SEPARATOR
);
396 if (LinkName
== NULL
)
398 LinkName
= ConsoleStartInfo
->ConsoleTitle
;
402 /* Skip the path separator */
406 /* 2- Check for the link extension. The name ".lnk" is considered invalid. */
407 Length
= wcslen(LinkName
);
408 if ( (Length
<= 4) || (wcsicmp(LinkName
+ (Length
- 4), L
".lnk") != 0) )
411 /* 3- It may be a link. Try to retrieve some properties */
412 hRes
= CoInitialize(NULL
);
415 /* Get a pointer to the IShellLink interface */
416 IShellLinkW
* pshl
= NULL
;
417 hRes
= CoCreateInstance(&CLSID_ShellLink
,
419 CLSCTX_INPROC_SERVER
,
424 /* Get a pointer to the IPersistFile interface */
425 IPersistFile
* ppf
= NULL
;
426 hRes
= IPersistFile_QueryInterface(pshl
, &IID_IPersistFile
, (LPVOID
*)&ppf
);
429 /* Load the shortcut */
430 hRes
= IPersistFile_Load(ppf
, ConsoleStartInfo
->ConsoleTitle
, STGM_READ
);
434 * Finally we can get the properties !
435 * Update the old ones if needed.
440 /* Reset the name of the console with the name of the shortcut */
441 Length
= min(/*Length*/ Length
- 4, // 4 == len(".lnk")
442 sizeof(ConsoleInfo
->ConsoleTitle
) / sizeof(ConsoleInfo
->ConsoleTitle
[0]) - 1);
443 wcsncpy(ConsoleInfo
->ConsoleTitle
, LinkName
, Length
);
444 ConsoleInfo
->ConsoleTitle
[Length
] = L
'\0';
446 /* Get the window showing command */
447 hRes
= IShellLinkW_GetShowCmd(pshl
, &ShowCmd
);
448 if (SUCCEEDED(hRes
)) ConsoleStartInfo
->ShowWindow
= (WORD
)ShowCmd
;
451 // hRes = pshl->GetHotkey(&ShowCmd);
452 // if (SUCCEEDED(hRes)) ConsoleStartInfo->HotKey = HotKey;
454 /* Get the icon location, if any */
455 hRes
= IShellLinkW_GetIconLocation(pshl
, IconPath
, IconPathLength
, piIcon
);
456 if (!SUCCEEDED(hRes
))
461 // FIXME: Since we still don't load console properties from the shortcut,
462 // return false. When this will be done, we will return true instead.
465 IPersistFile_Release(ppf
);
467 IShellLinkW_Release(pshl
);
476 ConSrvInitConsole(OUT PCONSOLE
* NewConsole
,
477 IN OUT PCONSOLE_START_INFO ConsoleStartInfo
,
478 IN PCSR_PROCESS ConsoleLeaderProcess
)
481 SECURITY_ATTRIBUTES SecurityAttributes
;
483 DWORD ProcessId
= HandleToUlong(ConsoleLeaderProcess
->ClientId
.UniqueProcess
);
484 CONSOLE_INFO ConsoleInfo
;
485 TEXTMODE_BUFFER_INFO ScreenBufferInfo
;
487 PCONSOLE_SCREEN_BUFFER NewBuffer
;
489 WCHAR DefaultTitle
[128];
490 WCHAR IconPath
[MAX_PATH
+ 1] = L
"";
493 if (NewConsole
== NULL
) return STATUS_INVALID_PARAMETER
;
497 * Allocate a console structure
499 Console
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(CONSOLE
));
502 DPRINT1("Not enough memory for console creation.\n");
503 return STATUS_NO_MEMORY
;
507 * Load the console settings
510 /* 1. Load the default settings */
511 ConSrvGetDefaultSettings(&ConsoleInfo
, ProcessId
);
513 /* 2. Get the title of the console (initialize ConsoleInfo.ConsoleTitle) */
514 Length
= min(wcslen(ConsoleStartInfo
->ConsoleTitle
),
515 sizeof(ConsoleInfo
.ConsoleTitle
) / sizeof(ConsoleInfo
.ConsoleTitle
[0]) - 1);
516 wcsncpy(ConsoleInfo
.ConsoleTitle
, ConsoleStartInfo
->ConsoleTitle
, Length
);
517 ConsoleInfo
.ConsoleTitle
[Length
] = L
'\0';
520 * 3. Check whether the process creating the console was launched
521 * via a shell-link. ConsoleInfo.ConsoleTitle may be updated by
522 * the name of the shortcut.
524 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
)
526 if (!LoadShellLinkConsoleInfo(ConsoleStartInfo
,
532 ConsoleStartInfo
->dwStartupFlags
&= ~STARTF_TITLEISLINKNAME
;
537 * 4. Load the remaining console settings via the registry.
539 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
542 * Either we weren't created by an app launched via a shell-link,
543 * or we failed to load shell-link console properties.
544 * Therefore, load the console infos for the application from the registry.
546 ConSrvReadUserSettings(&ConsoleInfo
, ProcessId
);
549 * Now, update them with the properties the user might gave to us
550 * via the STARTUPINFO structure before calling CreateProcess
551 * (and which was transmitted via the ConsoleStartInfo structure).
552 * We therefore overwrite the values read in the registry.
554 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USEFILLATTRIBUTE
)
556 ConsoleInfo
.ScreenAttrib
= (USHORT
)ConsoleStartInfo
->FillAttribute
;
558 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USECOUNTCHARS
)
560 ConsoleInfo
.ScreenBufferSize
= ConsoleStartInfo
->ScreenBufferSize
;
562 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USESIZE
)
564 // ConsoleInfo->ConsoleSize = ConsoleStartInfo->ConsoleWindowSize;
565 ConsoleInfo
.ConsoleSize
.X
= (SHORT
)ConsoleStartInfo
->ConsoleWindowSize
.cx
;
566 ConsoleInfo
.ConsoleSize
.Y
= (SHORT
)ConsoleStartInfo
->ConsoleWindowSize
.cy
;
571 * Fix the screen buffer size if needed. The rule is:
572 * ScreenBufferSize >= ConsoleSize
574 if (ConsoleInfo
.ScreenBufferSize
.X
< ConsoleInfo
.ConsoleSize
.X
)
575 ConsoleInfo
.ScreenBufferSize
.X
= ConsoleInfo
.ConsoleSize
.X
;
576 if (ConsoleInfo
.ScreenBufferSize
.Y
< ConsoleInfo
.ConsoleSize
.Y
)
577 ConsoleInfo
.ScreenBufferSize
.Y
= ConsoleInfo
.ConsoleSize
.Y
;
580 * Initialize the console
582 Console
->State
= CONSOLE_INITIALIZING
;
583 Console
->ReferenceCount
= 0;
584 InitializeCriticalSection(&Console
->Lock
);
585 InitializeListHead(&Console
->ProcessList
);
586 RtlZeroMemory(&Console
->TermIFace
, sizeof(Console
->TermIFace
));
588 memcpy(Console
->Colors
, ConsoleInfo
.Colors
, sizeof(ConsoleInfo
.Colors
));
589 Console
->ConsoleSize
= ConsoleInfo
.ConsoleSize
;
590 Console
->FixedSize
= FALSE
; // Value by default; is reseted by the front-ends if needed.
593 * Initialize the input buffer
595 ConSrvInitObject(&Console
->InputBuffer
.Header
, INPUT_BUFFER
, Console
);
597 SecurityAttributes
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
598 SecurityAttributes
.lpSecurityDescriptor
= NULL
;
599 SecurityAttributes
.bInheritHandle
= TRUE
;
600 Console
->InputBuffer
.ActiveEvent
= CreateEventW(&SecurityAttributes
, TRUE
, FALSE
, NULL
);
601 if (NULL
== Console
->InputBuffer
.ActiveEvent
)
603 DeleteCriticalSection(&Console
->Lock
);
604 ConsoleFreeHeap(Console
);
605 return STATUS_UNSUCCESSFUL
;
608 Console
->InputBuffer
.InputBufferSize
= 0; // FIXME!
609 InitializeListHead(&Console
->InputBuffer
.InputEvents
);
610 InitializeListHead(&Console
->InputBuffer
.ReadWaitQueue
);
611 Console
->InputBuffer
.Mode
= ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
|
612 ENABLE_ECHO_INPUT
| ENABLE_MOUSE_INPUT
;
614 Console
->QuickEdit
= ConsoleInfo
.QuickEdit
;
615 Console
->InsertMode
= ConsoleInfo
.InsertMode
;
616 Console
->LineBuffer
= NULL
;
617 Console
->LineMaxSize
= Console
->LineSize
= Console
->LinePos
= 0;
618 Console
->LineComplete
= Console
->LineUpPressed
= Console
->LineInsertToggle
= FALSE
;
623 Console
->CodePage
= GetOEMCP();
624 Console
->OutputCodePage
= GetOEMCP();
626 /* Initialize a new text-mode screen buffer with default settings */
627 ScreenBufferInfo
.ScreenBufferSize
= ConsoleInfo
.ScreenBufferSize
;
628 ScreenBufferInfo
.ScreenAttrib
= ConsoleInfo
.ScreenAttrib
;
629 ScreenBufferInfo
.PopupAttrib
= ConsoleInfo
.PopupAttrib
;
630 ScreenBufferInfo
.IsCursorVisible
= TRUE
;
631 ScreenBufferInfo
.CursorSize
= ConsoleInfo
.CursorSize
;
633 InitializeListHead(&Console
->BufferList
);
634 Status
= ConSrvCreateScreenBuffer(&NewBuffer
,
636 CONSOLE_TEXTMODE_BUFFER
,
638 if (!NT_SUCCESS(Status
))
640 DPRINT1("ConSrvCreateScreenBuffer: failed, Status = 0x%08lx\n", Status
);
641 CloseHandle(Console
->InputBuffer
.ActiveEvent
);
642 DeleteCriticalSection(&Console
->Lock
);
643 ConsoleFreeHeap(Console
);
646 /* Make the new screen buffer active */
647 Console
->ActiveBuffer
= NewBuffer
;
648 InitializeListHead(&Console
->WriteWaitQueue
);
649 Console
->PauseFlags
= 0;
650 Console
->UnpauseEvent
= NULL
;
653 * Initialize the alias and history buffers
655 Console
->Aliases
= NULL
;
656 InitializeListHead(&Console
->HistoryBuffers
);
657 Console
->HistoryBufferSize
= ConsoleInfo
.HistoryBufferSize
;
658 Console
->NumberOfHistoryBuffers
= ConsoleInfo
.NumberOfHistoryBuffers
;
659 Console
->HistoryNoDup
= ConsoleInfo
.HistoryNoDup
;
661 /* Initialize the console title */
662 ConsoleCreateUnicodeString(&Console
->OriginalTitle
, ConsoleInfo
.ConsoleTitle
);
663 if (ConsoleInfo
.ConsoleTitle
[0] == L
'\0')
665 if (LoadStringW(ConSrvDllInstance
, IDS_CONSOLE_TITLE
, DefaultTitle
, sizeof(DefaultTitle
) / sizeof(DefaultTitle
[0])))
667 ConsoleCreateUnicodeString(&Console
->Title
, DefaultTitle
);
671 ConsoleCreateUnicodeString(&Console
->Title
, L
"ReactOS Console");
676 ConsoleCreateUnicodeString(&Console
->Title
, ConsoleInfo
.ConsoleTitle
);
679 /* Lock the console until its initialization is finished */
680 // EnterCriticalSection(&Console->Lock);
683 * If we are not in GUI-mode, start the text-mode terminal emulator.
684 * If we fail, try to start the GUI-mode terminal emulator.
686 GuiMode
= DtbgIsDesktopVisible();
690 DPRINT("CONSRV: Opening text-mode terminal emulator\n");
691 Status
= TuiInitConsole(Console
,
695 if (!NT_SUCCESS(Status
))
697 DPRINT1("Failed to open text-mode terminal emulator, switching to gui-mode, Status = 0x%08lx\n", Status
);
703 * Try to open the GUI-mode terminal emulator. Two cases are possible:
704 * - We are in GUI-mode, therefore GuiMode == TRUE, the previous test-case
705 * failed and we start GUI-mode terminal emulator.
706 * - We are in text-mode, therefore GuiMode == FALSE, the previous test-case
707 * succeeded BUT we failed at starting text-mode terminal emulator.
708 * Then GuiMode was switched to TRUE in order to try to open the GUI-mode
709 * terminal emulator (Win32k will automatically switch to graphical mode,
710 * therefore no additional code is needed).
714 DPRINT("CONSRV: Opening GUI-mode terminal emulator\n");
715 Status
= GuiInitConsole(Console
,
721 if (!NT_SUCCESS(Status
))
723 DPRINT1("GuiInitConsole: failed, Status = 0x%08lx\n", Status
);
724 ConsoleFreeUnicodeString(&Console
->OriginalTitle
);
725 ConsoleFreeUnicodeString(&Console
->Title
);
726 ConioDeleteScreenBuffer(NewBuffer
);
727 CloseHandle(Console
->InputBuffer
.ActiveEvent
);
728 // LeaveCriticalSection(&Console->Lock);
729 DeleteCriticalSection(&Console
->Lock
);
730 ConsoleFreeHeap(Console
);
735 DPRINT("Terminal initialized\n");
737 /* All went right, so add the console to the list */
738 ConSrvLockConsoleListExclusive();
739 DPRINT("Insert in the list\n");
740 InsertTailList(&ConsoleList
, &Console
->Entry
);
742 /* The initialization is finished */
743 DPRINT("Change state\n");
744 Console
->State
= CONSOLE_RUNNING
;
746 /* Unlock the console */
747 // LeaveCriticalSection(&Console->Lock);
749 /* Unlock the console list */
750 ConSrvUnlockConsoleList();
752 /* Copy buffer contents to screen */
753 ConioDrawConsole(Console
);
754 DPRINT("Console drawn\n");
756 /* Return the newly created console to the caller and a success code too */
757 *NewConsole
= Console
;
758 return STATUS_SUCCESS
;
762 ConSrvDeleteConsole(PCONSOLE Console
)
764 DPRINT("ConSrvDeleteConsole\n");
767 * Forbid validation of any console by other threads
768 * during the deletion of this console.
770 ConSrvLockConsoleListExclusive();
772 /* Check the existence of the console, and if it's ok, continue */
773 if (!ConSrvValidateConsolePointer(Console
))
775 /* Unlock the console list and return */
776 ConSrvUnlockConsoleList();
781 * If the console is already being destroyed
782 * (thus not running), just return.
784 if (!ConSrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
786 /* Unlock the console list and return */
787 ConSrvUnlockConsoleList();
792 * We are about to be destroyed. Signal it to other people
793 * so that they can terminate what they are doing, and that
794 * they cannot longer validate the console.
796 Console
->State
= CONSOLE_TERMINATING
;
799 * Allow other threads to finish their job: basically, unlock
800 * all other calls to EnterCriticalSection(&Console->Lock); by
801 * ConSrvValidateConsole(Unsafe) functions so that they just see
802 * that we are not in CONSOLE_RUNNING state anymore, or unlock
803 * other concurrent calls to ConSrvDeleteConsole so that they
804 * can see that we are in fact already deleting the console.
806 LeaveCriticalSection(&Console
->Lock
);
807 ConSrvUnlockConsoleList();
809 /* FIXME: Send a terminate message to all the processes owning this console */
811 /* Cleanup the UI-oriented part */
812 ConioCleanupConsole(Console
);
815 * Check that the console is in terminating state before continuing
816 * (the cleanup code must not change the state of the console...
817 * ...unless to cancel console deletion ?).
820 ConSrvLockConsoleListExclusive();
822 /* Re-check the existence of the console, and if it's ok, continue */
823 if (!ConSrvValidateConsolePointer(Console
))
825 /* Unlock the console list and return */
826 ConSrvUnlockConsoleList();
830 if (!ConSrvValidateConsoleUnsafe(Console
, CONSOLE_TERMINATING
, TRUE
))
832 ConSrvUnlockConsoleList();
836 /* We are in destruction */
837 Console
->State
= CONSOLE_IN_DESTRUCTION
;
839 /* Remove the console from the list */
840 RemoveEntryList(&Console
->Entry
);
842 /* Reset the count to be sure */
843 Console
->ReferenceCount
= 0;
845 /* Discard all entries in the input event queue */
846 PurgeInputBuffer(Console
);
848 if (Console
->LineBuffer
) ConsoleFreeHeap(Console
->LineBuffer
);
850 IntDeleteAllAliases(Console
);
851 HistoryDeleteBuffers(Console
);
853 ConioDeleteScreenBuffer(Console
->ActiveBuffer
);
854 if (!IsListEmpty(&Console
->BufferList
))
856 DPRINT1("BUG: screen buffer list not empty\n");
859 // CloseHandle(Console->InputBuffer.ActiveEvent);
860 if (Console
->UnpauseEvent
) CloseHandle(Console
->UnpauseEvent
);
862 ConsoleFreeUnicodeString(&Console
->OriginalTitle
);
863 ConsoleFreeUnicodeString(&Console
->Title
);
865 DPRINT("ConSrvDeleteConsole - Unlocking\n");
866 LeaveCriticalSection(&Console
->Lock
);
867 DPRINT("ConSrvDeleteConsole - Destroying lock\n");
868 DeleteCriticalSection(&Console
->Lock
);
869 DPRINT("ConSrvDeleteConsole - Lock destroyed ; freeing console\n");
871 ConsoleFreeHeap(Console
);
872 DPRINT("ConSrvDeleteConsole - Console freed\n");
874 /* Unlock the console list and return */
875 ConSrvUnlockConsoleList();
879 /* PUBLIC SERVER APIS *********************************************************/
881 CSR_API(SrvAllocConsole
)
883 NTSTATUS Status
= STATUS_SUCCESS
;
884 PCONSOLE_ALLOCCONSOLE AllocConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.AllocConsoleRequest
;
885 PCSR_PROCESS CsrProcess
= CsrGetClientThread()->Process
;
886 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrProcess
);
888 if (ProcessData
->Console
!= NULL
)
890 DPRINT1("Process already has a console\n");
891 return STATUS_ACCESS_DENIED
;
894 if (!CsrValidateMessageBuffer(ApiMessage
,
895 (PVOID
*)&AllocConsoleRequest
->ConsoleStartInfo
,
897 sizeof(CONSOLE_START_INFO
)))
899 return STATUS_INVALID_PARAMETER
;
902 /* Initialize a new Console owned by the Console Leader Process */
903 Status
= ConSrvAllocateConsole(ProcessData
,
904 &AllocConsoleRequest
->InputHandle
,
905 &AllocConsoleRequest
->OutputHandle
,
906 &AllocConsoleRequest
->ErrorHandle
,
907 AllocConsoleRequest
->ConsoleStartInfo
);
908 if (!NT_SUCCESS(Status
))
910 DPRINT1("Console allocation failed\n");
914 /* Return it to the caller */
915 AllocConsoleRequest
->Console
= ProcessData
->Console
;
917 /* Input Wait Handle */
918 AllocConsoleRequest
->InputWaitHandle
= ProcessData
->ConsoleEvent
;
920 /* Set the Property Dialog Handler */
921 ProcessData
->PropDispatcher
= AllocConsoleRequest
->PropDispatcher
;
923 /* Set the Ctrl Dispatcher */
924 ProcessData
->CtrlDispatcher
= AllocConsoleRequest
->CtrlDispatcher
;
926 return STATUS_SUCCESS
;
929 CSR_API(SrvAttachConsole
)
931 NTSTATUS Status
= STATUS_SUCCESS
;
932 PCONSOLE_ATTACHCONSOLE AttachConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.AttachConsoleRequest
;
933 PCSR_PROCESS SourceProcess
= NULL
; // The parent process.
934 PCSR_PROCESS TargetProcess
= CsrGetClientThread()->Process
; // Ourselves.
935 HANDLE ProcessId
= ULongToHandle(AttachConsoleRequest
->ProcessId
);
936 PCONSOLE_PROCESS_DATA SourceProcessData
, TargetProcessData
;
938 TargetProcessData
= ConsoleGetPerProcessData(TargetProcess
);
940 if (TargetProcessData
->Console
!= NULL
)
942 DPRINT1("Process already has a console\n");
943 return STATUS_ACCESS_DENIED
;
946 /* Check whether we try to attach to the parent's console */
947 if (ProcessId
== ULongToHandle(ATTACH_PARENT_PROCESS
))
949 PROCESS_BASIC_INFORMATION ProcessInfo
;
950 ULONG Length
= sizeof(ProcessInfo
);
952 /* Get the real parent's ID */
954 Status
= NtQueryInformationProcess(TargetProcess
->ProcessHandle
,
955 ProcessBasicInformation
,
958 if (!NT_SUCCESS(Status
))
960 DPRINT1("SrvAttachConsole - Cannot retrieve basic process info, Status = %lu\n", Status
);
964 ProcessId
= ULongToHandle(ProcessInfo
.InheritedFromUniqueProcessId
);
967 /* Lock the source process via its PID */
968 Status
= CsrLockProcessByClientId(ProcessId
, &SourceProcess
);
969 if (!NT_SUCCESS(Status
)) return Status
;
971 SourceProcessData
= ConsoleGetPerProcessData(SourceProcess
);
973 if (SourceProcessData
->Console
== NULL
)
975 Status
= STATUS_INVALID_HANDLE
;
980 * Inherit the console from the parent,
981 * if any, otherwise return an error.
983 Status
= ConSrvInheritConsole(TargetProcessData
,
984 SourceProcessData
->Console
,
986 &AttachConsoleRequest
->InputHandle
,
987 &AttachConsoleRequest
->OutputHandle
,
988 &AttachConsoleRequest
->ErrorHandle
);
989 if (!NT_SUCCESS(Status
))
991 DPRINT1("Console inheritance failed\n");
995 /* Return it to the caller */
996 AttachConsoleRequest
->Console
= TargetProcessData
->Console
;
998 /* Input Wait Handle */
999 AttachConsoleRequest
->InputWaitHandle
= TargetProcessData
->ConsoleEvent
;
1001 /* Set the Property Dialog Handler */
1002 TargetProcessData
->PropDispatcher
= AttachConsoleRequest
->PropDispatcher
;
1004 /* Set the Ctrl Dispatcher */
1005 TargetProcessData
->CtrlDispatcher
= AttachConsoleRequest
->CtrlDispatcher
;
1007 Status
= STATUS_SUCCESS
;
1010 /* Unlock the "source" process and exit */
1011 CsrUnlockProcess(SourceProcess
);
1015 CSR_API(SrvFreeConsole
)
1017 ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
));
1018 return STATUS_SUCCESS
;
1021 CSR_API(SrvGetConsoleMode
)
1024 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleModeRequest
;
1025 PCONSOLE_IO_OBJECT Object
= NULL
;
1027 Status
= ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
1028 ConsoleModeRequest
->ConsoleHandle
,
1029 &Object
, NULL
, GENERIC_READ
, TRUE
, 0);
1030 if (!NT_SUCCESS(Status
)) return Status
;
1032 Status
= STATUS_SUCCESS
;
1034 if (INPUT_BUFFER
== Object
->Type
)
1036 PCONSOLE_INPUT_BUFFER InputBuffer
= (PCONSOLE_INPUT_BUFFER
)Object
;
1037 PCONSOLE Console
= InputBuffer
->Header
.Console
;
1038 DWORD ConsoleMode
= InputBuffer
->Mode
;
1040 if (Console
->QuickEdit
|| Console
->InsertMode
)
1042 // Windows does this, even if it's not documented on MSDN
1043 ConsoleMode
|= ENABLE_EXTENDED_FLAGS
;
1045 if (Console
->QuickEdit
) ConsoleMode
|= ENABLE_QUICK_EDIT_MODE
;
1046 if (Console
->InsertMode
) ConsoleMode
|= ENABLE_INSERT_MODE
;
1049 ConsoleModeRequest
->ConsoleMode
= ConsoleMode
;
1051 else if (TEXTMODE_BUFFER
== Object
->Type
|| GRAPHICS_BUFFER
== Object
->Type
)
1053 PCONSOLE_SCREEN_BUFFER Buffer
= (PCONSOLE_SCREEN_BUFFER
)Object
;
1054 ConsoleModeRequest
->ConsoleMode
= Buffer
->Mode
;
1058 Status
= STATUS_INVALID_HANDLE
;
1061 ConSrvReleaseObject(Object
, TRUE
);
1065 CSR_API(SrvSetConsoleMode
)
1067 #define CONSOLE_VALID_CONTROL_MODES ( ENABLE_EXTENDED_FLAGS | ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE )
1068 #define CONSOLE_VALID_INPUT_MODES ( ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | \
1069 ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT | \
1070 ENABLE_MOUSE_INPUT )
1071 #define CONSOLE_VALID_OUTPUT_MODES ( ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT )
1074 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleModeRequest
;
1075 DWORD ConsoleMode
= ConsoleModeRequest
->ConsoleMode
;
1076 PCONSOLE_IO_OBJECT Object
= NULL
;
1078 Status
= ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
1079 ConsoleModeRequest
->ConsoleHandle
,
1080 &Object
, NULL
, GENERIC_WRITE
, TRUE
, 0);
1081 if (!NT_SUCCESS(Status
)) return Status
;
1083 Status
= STATUS_SUCCESS
;
1085 if (INPUT_BUFFER
== Object
->Type
)
1087 PCONSOLE_INPUT_BUFFER InputBuffer
= (PCONSOLE_INPUT_BUFFER
)Object
;
1088 PCONSOLE Console
= InputBuffer
->Header
.Console
;
1090 DPRINT("SetConsoleMode(Input, %d)\n", ConsoleMode
);
1093 * 1. Only the presence of valid mode flags is allowed.
1095 if (ConsoleMode
& ~(CONSOLE_VALID_INPUT_MODES
| CONSOLE_VALID_CONTROL_MODES
))
1097 Status
= STATUS_INVALID_PARAMETER
;
1102 * 2. If we use control mode flags without ENABLE_EXTENDED_FLAGS,
1103 * then consider the flags invalid.
1105 if ( (ConsoleMode & CONSOLE_VALID_CONTROL_MODES) &&
1106 (ConsoleMode & ENABLE_EXTENDED_FLAGS) == 0 )
1108 Status = STATUS_INVALID_PARAMETER;
1114 * 3. Now we can continue.
1116 if (ConsoleMode
& CONSOLE_VALID_CONTROL_MODES
)
1118 Console
->QuickEdit
= !!(ConsoleMode
& ENABLE_QUICK_EDIT_MODE
);
1119 Console
->InsertMode
= !!(ConsoleMode
& ENABLE_INSERT_MODE
);
1121 InputBuffer
->Mode
= (ConsoleMode
& CONSOLE_VALID_INPUT_MODES
);
1123 else if (TEXTMODE_BUFFER
== Object
->Type
|| GRAPHICS_BUFFER
== Object
->Type
)
1125 PCONSOLE_SCREEN_BUFFER Buffer
= (PCONSOLE_SCREEN_BUFFER
)Object
;
1127 DPRINT("SetConsoleMode(Output, %d)\n", ConsoleMode
);
1129 if (ConsoleMode
& ~CONSOLE_VALID_OUTPUT_MODES
)
1131 Status
= STATUS_INVALID_PARAMETER
;
1135 Buffer
->Mode
= (ConsoleMode
& CONSOLE_VALID_OUTPUT_MODES
);
1140 Status
= STATUS_INVALID_HANDLE
;
1144 ConSrvReleaseObject(Object
, TRUE
);
1148 CSR_API(SrvGetConsoleTitle
)
1151 PCONSOLE_GETSETCONSOLETITLE TitleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.TitleRequest
;
1152 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
1156 if (!CsrValidateMessageBuffer(ApiMessage
,
1157 (PVOID
)&TitleRequest
->Title
,
1158 TitleRequest
->Length
,
1161 return STATUS_INVALID_PARAMETER
;
1164 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1165 if (!NT_SUCCESS(Status
))
1167 DPRINT1("Can't get console\n");
1171 /* Copy title of the console to the user title buffer */
1172 if (TitleRequest
->Length
>= sizeof(WCHAR
))
1174 Length
= min(TitleRequest
->Length
- sizeof(WCHAR
), Console
->Title
.Length
);
1175 memcpy(TitleRequest
->Title
, Console
->Title
.Buffer
, Length
);
1176 TitleRequest
->Title
[Length
/ sizeof(WCHAR
)] = L
'\0';
1179 TitleRequest
->Length
= Console
->Title
.Length
;
1181 ConSrvReleaseConsole(Console
, TRUE
);
1182 return STATUS_SUCCESS
;
1185 CSR_API(SrvSetConsoleTitle
)
1188 PCONSOLE_GETSETCONSOLETITLE TitleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.TitleRequest
;
1189 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
1193 if (!CsrValidateMessageBuffer(ApiMessage
,
1194 (PVOID
)&TitleRequest
->Title
,
1195 TitleRequest
->Length
,
1198 return STATUS_INVALID_PARAMETER
;
1201 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1202 if (!NT_SUCCESS(Status
))
1204 DPRINT1("Can't get console\n");
1208 /* Allocate a new buffer to hold the new title (NULL-terminated) */
1209 Buffer
= ConsoleAllocHeap(0, TitleRequest
->Length
+ sizeof(WCHAR
));
1212 /* Free the old title */
1213 ConsoleFreeUnicodeString(&Console
->Title
);
1215 /* Copy title to console */
1216 Console
->Title
.Buffer
= Buffer
;
1217 Console
->Title
.Length
= TitleRequest
->Length
;
1218 Console
->Title
.MaximumLength
= Console
->Title
.Length
+ sizeof(WCHAR
);
1219 RtlCopyMemory(Console
->Title
.Buffer
,
1220 TitleRequest
->Title
,
1221 Console
->Title
.Length
);
1222 Console
->Title
.Buffer
[Console
->Title
.Length
/ sizeof(WCHAR
)] = L
'\0';
1224 ConioChangeTitle(Console
);
1225 Status
= STATUS_SUCCESS
;
1229 Status
= STATUS_NO_MEMORY
;
1232 ConSrvReleaseConsole(Console
, TRUE
);
1236 /**********************************************************************
1237 * HardwareStateProperty
1240 * Set/Get the value of the HardwareState and switch
1241 * between direct video buffer ouput and GDI windowed
1244 * Client hands us a CONSOLE_GETSETHWSTATE object.
1245 * We use the same object to Request.
1247 * ConsoleHwState has the correct size to be compatible
1248 * with NT's, but values are not.
1251 static NTSTATUS FASTCALL
1252 SetConsoleHardwareState(PCONSOLE Console
, ULONG ConsoleHwState
)
1254 DPRINT1("Console Hardware State: %d\n", ConsoleHwState
);
1256 if ((CONSOLE_HARDWARE_STATE_GDI_MANAGED
== ConsoleHwState
)
1257 ||(CONSOLE_HARDWARE_STATE_DIRECT
== ConsoleHwState
))
1259 if (Console
->HardwareState
!= ConsoleHwState
)
1261 /* TODO: implement switching from full screen to windowed mode */
1262 /* TODO: or back; now simply store the hardware state */
1263 Console
->HardwareState
= ConsoleHwState
;
1266 return STATUS_SUCCESS
;
1269 return STATUS_INVALID_PARAMETER_3
; /* Client: (handle, set_get, [mode]) */
1273 CSR_API(SrvGetConsoleHardwareState
)
1277 PCONSOLE_GETSETHWSTATE HardwareStateRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.HardwareStateRequest
;
1278 PCONSOLE_SCREEN_BUFFER Buff
;
1281 Status
= ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
1282 HardwareStateRequest
->OutputHandle
,
1286 if (!NT_SUCCESS(Status
))
1288 DPRINT1("Failed to get console handle in SrvGetConsoleHardwareState\n");
1292 Console
= Buff
->Header
.Console
;
1293 HardwareStateRequest
->State
= Console
->HardwareState
;
1295 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1299 return STATUS_NOT_IMPLEMENTED
;
1303 CSR_API(SrvSetConsoleHardwareState
)
1307 PCONSOLE_GETSETHWSTATE HardwareStateRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.HardwareStateRequest
;
1308 PCONSOLE_SCREEN_BUFFER Buff
;
1311 Status
= ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
1312 HardwareStateRequest
->OutputHandle
,
1316 if (!NT_SUCCESS(Status
))
1318 DPRINT1("Failed to get console handle in SrvSetConsoleHardwareState\n");
1322 DPRINT("Setting console hardware state.\n");
1323 Console
= Buff
->Header
.Console
;
1324 Status
= SetConsoleHardwareState(Console
, HardwareStateRequest
->State
);
1326 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1330 return STATUS_NOT_IMPLEMENTED
;
1334 CSR_API(SrvGetConsoleDisplayMode
)
1337 PCONSOLE_GETDISPLAYMODE GetDisplayModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetDisplayModeRequest
;
1340 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
1342 if (!NT_SUCCESS(Status
))
1344 DPRINT1("Failed to get console handle in SrvGetConsoleDisplayMode\n");
1348 GetDisplayModeRequest
->DisplayMode
= ConioGetDisplayMode(Console
);
1350 ConSrvReleaseConsole(Console
, TRUE
);
1351 return STATUS_SUCCESS
;
1354 CSR_API(SrvSetConsoleDisplayMode
)
1357 PCONSOLE_SETDISPLAYMODE SetDisplayModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetDisplayModeRequest
;
1359 PCONSOLE_SCREEN_BUFFER Buff
;
1361 Status
= ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
1362 SetDisplayModeRequest
->OutputHandle
,
1366 if (!NT_SUCCESS(Status
))
1368 DPRINT1("Failed to get console handle in SrvSetConsoleDisplayMode\n");
1372 Console
= Buff
->Header
.Console
;
1374 if (ConioSetDisplayMode(Console
, SetDisplayModeRequest
->DisplayMode
))
1376 SetDisplayModeRequest
->NewSBDim
= Buff
->ScreenBufferSize
;
1377 Status
= STATUS_SUCCESS
;
1381 Status
= STATUS_INVALID_PARAMETER
;
1384 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1388 CSR_API(SrvGetLargestConsoleWindowSize
)
1391 PCONSOLE_GETLARGESTWINDOWSIZE GetLargestWindowSizeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetLargestWindowSizeRequest
;
1392 PCONSOLE_SCREEN_BUFFER Buff
;
1395 Status
= ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
1396 GetLargestWindowSizeRequest
->OutputHandle
,
1400 if (!NT_SUCCESS(Status
)) return Status
;
1402 Console
= Buff
->Header
.Console
;
1403 ConioGetLargestConsoleWindowSize(Console
, &GetLargestWindowSizeRequest
->Size
);
1405 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1406 return STATUS_SUCCESS
;
1409 CSR_API(SrvSetConsoleWindowInfo
)
1412 PCONSOLE_SETWINDOWINFO SetWindowInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetWindowInfoRequest
;
1413 PCONSOLE_SCREEN_BUFFER Buff
;
1414 SMALL_RECT WindowRect
= SetWindowInfoRequest
->WindowRect
;
1416 DPRINT("SrvSetConsoleWindowInfo(0x%08x, %d, {L%d, T%d, R%d, B%d}) called\n",
1417 SetWindowInfoRequest
->OutputHandle
, SetWindowInfoRequest
->Absolute
,
1418 WindowRect
.Left
, WindowRect
.Top
, WindowRect
.Right
, WindowRect
.Bottom
);
1420 Status
= ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
1421 SetWindowInfoRequest
->OutputHandle
,
1425 if (!NT_SUCCESS(Status
)) return Status
;
1427 if (SetWindowInfoRequest
->Absolute
== FALSE
)
1429 /* Relative positions given. Transform them to absolute ones */
1430 WindowRect
.Left
+= Buff
->ViewOrigin
.X
;
1431 WindowRect
.Top
+= Buff
->ViewOrigin
.Y
;
1432 WindowRect
.Right
+= Buff
->ViewOrigin
.X
+ Buff
->ViewSize
.X
- 1;
1433 WindowRect
.Bottom
+= Buff
->ViewOrigin
.Y
+ Buff
->ViewSize
.Y
- 1;
1436 /* See MSDN documentation on SetConsoleWindowInfo about the performed checks */
1437 if ( (WindowRect
.Left
< 0) || (WindowRect
.Top
< 0) ||
1438 (WindowRect
.Right
>= Buff
->ScreenBufferSize
.X
) ||
1439 (WindowRect
.Bottom
>= Buff
->ScreenBufferSize
.Y
) ||
1440 (WindowRect
.Right
<= WindowRect
.Left
) ||
1441 (WindowRect
.Bottom
<= WindowRect
.Top
) )
1443 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1444 return STATUS_INVALID_PARAMETER
;
1447 Buff
->ViewOrigin
.X
= WindowRect
.Left
;
1448 Buff
->ViewOrigin
.Y
= WindowRect
.Top
;
1450 Buff
->ViewSize
.X
= WindowRect
.Right
- WindowRect
.Left
+ 1;
1451 Buff
->ViewSize
.Y
= WindowRect
.Bottom
- WindowRect
.Top
+ 1;
1453 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1454 return STATUS_SUCCESS
;
1457 CSR_API(SrvGetConsoleWindow
)
1460 PCONSOLE_GETWINDOW GetWindowRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetWindowRequest
;
1463 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1464 if (!NT_SUCCESS(Status
)) return Status
;
1466 GetWindowRequest
->WindowHandle
= ConioGetConsoleWindowHandle(Console
);
1468 ConSrvReleaseConsole(Console
, TRUE
);
1469 return STATUS_SUCCESS
;
1472 CSR_API(SrvSetConsoleIcon
)
1475 PCONSOLE_SETICON SetIconRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetIconRequest
;
1478 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1479 if (!NT_SUCCESS(Status
)) return Status
;
1481 Status
= (ConioChangeIcon(Console
, SetIconRequest
->WindowIcon
)
1483 : STATUS_UNSUCCESSFUL
);
1485 ConSrvReleaseConsole(Console
, TRUE
);
1489 CSR_API(SrvGetConsoleCP
)
1492 PCONSOLE_GETSETINPUTOUTPUTCP ConsoleCPRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleCPRequest
;
1495 DPRINT("SrvGetConsoleCP, getting %s Code Page\n",
1496 ConsoleCPRequest
->InputCP
? "Input" : "Output");
1498 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1499 if (!NT_SUCCESS(Status
)) return Status
;
1501 ConsoleCPRequest
->CodePage
= (ConsoleCPRequest
->InputCP
? Console
->CodePage
1502 : Console
->OutputCodePage
);
1503 ConSrvReleaseConsole(Console
, TRUE
);
1504 return STATUS_SUCCESS
;
1507 CSR_API(SrvSetConsoleCP
)
1510 PCONSOLE_GETSETINPUTOUTPUTCP ConsoleCPRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleCPRequest
;
1513 DPRINT("SrvSetConsoleCP, setting %s Code Page\n",
1514 ConsoleCPRequest
->InputCP
? "Input" : "Output");
1516 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1517 if (!NT_SUCCESS(Status
)) return Status
;
1519 if (IsValidCodePage(ConsoleCPRequest
->CodePage
))
1521 if (ConsoleCPRequest
->InputCP
)
1522 Console
->CodePage
= ConsoleCPRequest
->CodePage
;
1524 Console
->OutputCodePage
= ConsoleCPRequest
->CodePage
;
1526 ConSrvReleaseConsole(Console
, TRUE
);
1527 return STATUS_SUCCESS
;
1530 ConSrvReleaseConsole(Console
, TRUE
);
1531 return STATUS_INVALID_PARAMETER
;
1534 CSR_API(SrvGetConsoleProcessList
)
1537 PCONSOLE_GETPROCESSLIST GetProcessListRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetProcessListRequest
;
1539 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
1541 PCONSOLE_PROCESS_DATA current
;
1542 PLIST_ENTRY current_entry
;
1545 if (!CsrValidateMessageBuffer(ApiMessage
,
1546 (PVOID
)&GetProcessListRequest
->pProcessIds
,
1547 GetProcessListRequest
->nMaxIds
,
1550 return STATUS_INVALID_PARAMETER
;
1553 Buffer
= GetProcessListRequest
->pProcessIds
;
1555 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1556 if (!NT_SUCCESS(Status
)) return Status
;
1558 for (current_entry
= Console
->ProcessList
.Flink
;
1559 current_entry
!= &Console
->ProcessList
;
1560 current_entry
= current_entry
->Flink
)
1562 current
= CONTAINING_RECORD(current_entry
, CONSOLE_PROCESS_DATA
, ConsoleLink
);
1563 if (++nItems
<= GetProcessListRequest
->nMaxIds
)
1565 *Buffer
++ = HandleToUlong(current
->Process
->ClientId
.UniqueProcess
);
1569 ConSrvReleaseConsole(Console
, TRUE
);
1571 GetProcessListRequest
->nProcessIdsTotal
= nItems
;
1572 return STATUS_SUCCESS
;
1575 CSR_API(SrvGenerateConsoleCtrlEvent
)
1578 PCONSOLE_GENERATECTRLEVENT GenerateCtrlEventRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GenerateCtrlEventRequest
;
1581 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1582 if (!NT_SUCCESS(Status
)) return Status
;
1584 Status
= ConSrvConsoleProcessCtrlEvent(Console
,
1585 GenerateCtrlEventRequest
->ProcessGroup
,
1586 GenerateCtrlEventRequest
->Event
);
1588 ConSrvReleaseConsole(Console
, TRUE
);
1592 CSR_API(SrvGetConsoleSelectionInfo
)
1595 PCONSOLE_GETSELECTIONINFO GetSelectionInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetSelectionInfoRequest
;
1598 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1599 if (NT_SUCCESS(Status
))
1601 memset(&GetSelectionInfoRequest
->Info
, 0, sizeof(CONSOLE_SELECTION_INFO
));
1602 if (Console
->Selection
.dwFlags
!= 0)
1603 GetSelectionInfoRequest
->Info
= Console
->Selection
;
1604 ConSrvReleaseConsole(Console
, TRUE
);