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: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
9 /* INCLUDES *******************************************************************/
12 #define NONAMELESSUNION
15 #include "include/conio.h"
21 #include "conoutput.h"
22 #include "lineinput.h"
23 #include "include/settings.h"
25 #include "frontends/gui/guiterm.h"
28 #include "frontends/tui/tuiterm.h"
31 #include "include/console.h"
41 /* GLOBALS ********************************************************************/
43 static LIST_ENTRY ConsoleList
; /* The list of all the allocated consoles */
44 static RTL_RESOURCE ListLock
;
46 #define ConSrvLockConsoleListExclusive() \
47 RtlAcquireResourceExclusive(&ListLock, TRUE)
49 #define ConSrvLockConsoleListShared() \
50 RtlAcquireResourceShared(&ListLock, TRUE)
52 #define ConSrvUnlockConsoleList() \
53 RtlReleaseResource(&ListLock)
56 /* PRIVATE FUNCTIONS **********************************************************/
60 DtbgIsDesktopVisible(VOID
)
62 return !((BOOL
)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE
));
67 ConSrvConsoleCtrlEventTimeout(DWORD Event
,
68 PCONSOLE_PROCESS_DATA ProcessData
,
71 ULONG Status
= ERROR_SUCCESS
;
73 DPRINT("ConSrvConsoleCtrlEventTimeout Parent ProcessId = %x\n", ProcessData
->Process
->ClientId
.UniqueProcess
);
75 if (ProcessData
->CtrlDispatcher
)
83 Thread
= CreateRemoteThread(ProcessData
->Process
->ProcessHandle
, NULL
, 0,
84 ProcessData
->CtrlDispatcher
,
85 UlongToPtr(Event
), 0, NULL
);
88 Status
= GetLastError();
89 DPRINT1("Failed thread creation (Error: 0x%x)\n", Status
);
93 DPRINT("ProcessData->CtrlDispatcher remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n", ProcessData
->Process
->ClientId
.UniqueProcess
, ProcessData
->Process
);
94 WaitForSingleObject(Thread
, Timeout
);
103 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
105 Status
= RtlNtStatusToDosError(_SEH2_GetExceptionCode());
106 DPRINT1("ConSrvConsoleCtrlEventTimeout - Caught an exception, Status = %08X\n", Status
);
115 ConSrvConsoleCtrlEvent(DWORD Event
,
116 PCONSOLE_PROCESS_DATA ProcessData
)
118 return ConSrvConsoleCtrlEventTimeout(Event
, ProcessData
, 0);
122 ConSrvConsoleProcessCtrlEvent(PCONSOLE Console
,
123 ULONG ProcessGroupId
,
126 ULONG Status
= ERROR_SUCCESS
;
127 PLIST_ENTRY current_entry
;
128 PCONSOLE_PROCESS_DATA current
;
130 /* If the console is already being destroyed, just return */
131 if (!ConSrvValidateConsole(Console
, CONSOLE_RUNNING
, FALSE
))
132 return STATUS_UNSUCCESSFUL
;
135 * Loop through the process list, from the most recent process
136 * (the active one) to the oldest one (the first created, i.e.
137 * the console leader process), and for each, send an event
138 * (new processes are inserted at the head of the console process list).
140 current_entry
= Console
->ProcessList
.Flink
;
141 while (current_entry
!= &Console
->ProcessList
)
143 current
= CONTAINING_RECORD(current_entry
, CONSOLE_PROCESS_DATA
, ConsoleLink
);
144 current_entry
= current_entry
->Flink
;
147 * Only processes belonging to the same process group are signaled.
148 * If the process group ID is zero, then all the processes are signaled.
150 if (ProcessGroupId
== 0 || current
->Process
->ProcessGroupId
== ProcessGroupId
)
152 Status
= ConSrvConsoleCtrlEvent(Event
, current
);
160 ConioPause(PCONSOLE Console
, UINT Flags
)
162 Console
->PauseFlags
|= Flags
;
163 if (!Console
->UnpauseEvent
)
164 Console
->UnpauseEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
168 ConioUnpause(PCONSOLE Console
, UINT Flags
)
170 Console
->PauseFlags
&= ~Flags
;
172 // if ((Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION)) == 0)
173 if (Console
->PauseFlags
== 0 && Console
->UnpauseEvent
)
175 SetEvent(Console
->UnpauseEvent
);
176 CloseHandle(Console
->UnpauseEvent
);
177 Console
->UnpauseEvent
= NULL
;
179 CsrNotifyWait(&Console
->WriteWaitQueue
,
183 if (!IsListEmpty(&Console
->WriteWaitQueue
))
185 CsrDereferenceWait(&Console
->WriteWaitQueue
);
191 ConSrvValidateConsolePointer(PCONSOLE Console
)
193 PLIST_ENTRY ConsoleEntry
;
194 PCONSOLE CurrentConsole
= NULL
;
196 if (!Console
) return FALSE
;
198 /* The console list must be locked */
199 // ASSERT(Console_list_locked);
201 ConsoleEntry
= ConsoleList
.Flink
;
202 while (ConsoleEntry
!= &ConsoleList
)
204 CurrentConsole
= CONTAINING_RECORD(ConsoleEntry
, CONSOLE
, Entry
);
205 ConsoleEntry
= ConsoleEntry
->Flink
;
206 if (CurrentConsole
== Console
) return TRUE
;
213 ConSrvValidateConsoleState(PCONSOLE Console
,
214 CONSOLE_STATE ExpectedState
)
216 // if (!Console) return FALSE;
218 /* The console must be locked */
219 // ASSERT(Console_locked);
221 return (Console
->State
== ExpectedState
);
225 ConSrvValidateConsoleUnsafe(PCONSOLE Console
,
226 CONSOLE_STATE ExpectedState
,
229 if (!Console
) return FALSE
;
232 * Lock the console to forbid possible console's state changes
233 * (which must be done when the console is already locked).
234 * If we don't want to lock it, it's because the lock is already
235 * held. So there must be no problems.
237 if (LockConsole
) EnterCriticalSection(&Console
->Lock
);
239 // ASSERT(Console_locked);
241 /* Check whether the console's state is what we expect */
242 if (!ConSrvValidateConsoleState(Console
, ExpectedState
))
244 if (LockConsole
) LeaveCriticalSection(&Console
->Lock
);
252 ConSrvValidateConsole(PCONSOLE Console
,
253 CONSOLE_STATE ExpectedState
,
258 if (!Console
) return FALSE
;
261 * Forbid creation or deletion of consoles when
262 * checking for the existence of a console.
264 ConSrvLockConsoleListShared();
266 if (ConSrvValidateConsolePointer(Console
))
268 RetVal
= ConSrvValidateConsoleUnsafe(Console
,
273 /* Unlock the console list and return */
274 ConSrvUnlockConsoleList();
280 ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData
,
284 NTSTATUS Status
= STATUS_SUCCESS
;
285 PCONSOLE ProcessConsole
;
287 RtlEnterCriticalSection(&ProcessData
->HandleTableLock
);
288 ProcessConsole
= ProcessData
->Console
;
290 if (ConSrvValidateConsole(ProcessConsole
, CONSOLE_RUNNING
, LockConsole
))
292 InterlockedIncrement(&ProcessConsole
->ReferenceCount
);
293 *Console
= ProcessConsole
;
298 Status
= STATUS_INVALID_HANDLE
;
301 RtlLeaveCriticalSection(&ProcessData
->HandleTableLock
);
306 ConSrvReleaseConsole(PCONSOLE Console
,
307 BOOL WasConsoleLocked
)
311 if (!Console
) return;
312 // if (Console->ReferenceCount == 0) return; // This shouldn't happen
313 ASSERT(Console
->ReferenceCount
> 0);
315 /* The console must be locked */
316 // ASSERT(Console_locked);
319 * Decrement the reference count. Save the new value too,
320 * because Console->ReferenceCount might be modified after
321 * the console gets unlocked but before we check whether we
324 RefCount
= _InterlockedDecrement(&Console
->ReferenceCount
);
326 /* Unlock the console if needed */
327 if (WasConsoleLocked
) LeaveCriticalSection(&Console
->Lock
);
329 /* Delete the console if needed */
330 if (RefCount
<= 0) ConSrvDeleteConsole(Console
);
334 ConSrvInitConsoleSupport(VOID
)
336 DPRINT("CONSRV: ConSrvInitConsoleSupport()\n");
338 /* Initialize the console list and its lock */
339 InitializeListHead(&ConsoleList
);
340 RtlInitializeResource(&ListLock
);
342 /* Should call LoadKeyboardLayout */
346 LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo
,
347 IN OUT PCONSOLE_INFO ConsoleInfo
,
349 IN SIZE_T IconPathLength
,
352 #define PATH_SEPARATOR L'\\'
355 LPWSTR LinkName
= NULL
;
358 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
361 if (IconPath
== NULL
|| piIcon
== NULL
)
367 /* 1- Find the last path separator if any */
368 LinkName
= wcsrchr(ConsoleStartInfo
->ConsoleTitle
, PATH_SEPARATOR
);
369 if (LinkName
== NULL
)
371 LinkName
= ConsoleStartInfo
->ConsoleTitle
;
375 /* Skip the path separator */
379 /* 2- Check for the link extension. The name ".lnk" is considered invalid. */
380 Length
= wcslen(LinkName
);
381 if ( (Length
<= 4) || (wcsicmp(LinkName
+ (Length
- 4), L
".lnk") != 0) )
384 /* 3- It may be a link. Try to retrieve some properties */
385 HRESULT hRes
= CoInitialize(NULL
);
388 /* Get a pointer to the IShellLink interface */
389 IShellLinkW
* pshl
= NULL
;
390 hRes
= CoCreateInstance(&CLSID_ShellLink
,
392 CLSCTX_INPROC_SERVER
,
397 /* Get a pointer to the IPersistFile interface */
398 IPersistFile
* ppf
= NULL
;
399 hRes
= IPersistFile_QueryInterface(pshl
, &IID_IPersistFile
, (LPVOID
*)&ppf
);
402 /* Load the shortcut */
403 hRes
= IPersistFile_Load(ppf
, ConsoleStartInfo
->ConsoleTitle
, STGM_READ
);
407 * Finally we can get the properties !
408 * Update the old ones if needed.
413 /* Reset the name of the console with the name of the shortcut */
414 Length
= min(/*Length*/ Length
- 4, // 4 == len(".lnk")
415 sizeof(ConsoleInfo
->ConsoleTitle
) / sizeof(ConsoleInfo
->ConsoleTitle
[0]) - 1);
416 wcsncpy(ConsoleInfo
->ConsoleTitle
, LinkName
, Length
);
417 ConsoleInfo
->ConsoleTitle
[Length
] = L
'\0';
419 /* Get the window showing command */
420 hRes
= IShellLinkW_GetShowCmd(pshl
, &ShowCmd
);
421 if (SUCCEEDED(hRes
)) ConsoleStartInfo
->ShowWindow
= (WORD
)ShowCmd
;
424 // hRes = pshl->GetHotkey(&ShowCmd);
425 // if (SUCCEEDED(hRes)) ConsoleStartInfo->HotKey = HotKey;
427 /* Get the icon location, if any */
428 hRes
= IShellLinkW_GetIconLocation(pshl
, IconPath
, IconPathLength
, piIcon
);
429 if (!SUCCEEDED(hRes
))
434 // FIXME: Since we still don't load console properties from the shortcut,
435 // return false. When this will be done, we will return true instead.
438 IPersistFile_Release(ppf
);
440 IShellLinkW_Release(pshl
);
449 ConSrvInitConsole(OUT PCONSOLE
* NewConsole
,
450 IN OUT PCONSOLE_START_INFO ConsoleStartInfo
,
451 IN PCSR_PROCESS ConsoleLeaderProcess
)
454 SECURITY_ATTRIBUTES SecurityAttributes
;
455 CONSOLE_INFO ConsoleInfo
;
457 DWORD ProcessId
= HandleToUlong(ConsoleLeaderProcess
->ClientId
.UniqueProcess
);
459 PCONSOLE_SCREEN_BUFFER NewBuffer
;
462 WCHAR IconPath
[MAX_PATH
+ 1] = L
"";
465 if (NewConsole
== NULL
) return STATUS_INVALID_PARAMETER
;
469 * Allocate a console structure
471 Console
= RtlAllocateHeap(ConSrvHeap
, HEAP_ZERO_MEMORY
, sizeof(CONSOLE
));
474 DPRINT1("Not enough memory for console creation.\n");
475 return STATUS_NO_MEMORY
;
479 * Load the console settings
482 /* 1. Load the default settings */
483 ConSrvGetDefaultSettings(&ConsoleInfo
, ProcessId
);
485 /* 2. Get the title of the console (initialize ConsoleInfo.ConsoleTitle) */
486 Length
= min(wcslen(ConsoleStartInfo
->ConsoleTitle
),
487 sizeof(ConsoleInfo
.ConsoleTitle
) / sizeof(ConsoleInfo
.ConsoleTitle
[0]) - 1);
488 wcsncpy(ConsoleInfo
.ConsoleTitle
, ConsoleStartInfo
->ConsoleTitle
, Length
);
489 ConsoleInfo
.ConsoleTitle
[Length
] = L
'\0';
492 * 3. Check whether the process creating the console was launched
493 * via a shell-link. ConsoleInfo.ConsoleTitle may be updated by
494 * the name of the shortcut.
496 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
)
498 if (!LoadShellLinkConsoleInfo(ConsoleStartInfo
,
504 ConsoleStartInfo
->dwStartupFlags
&= ~STARTF_TITLEISLINKNAME
;
509 * 4. Load the remaining console settings via the registry.
511 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
514 * Either we weren't created by an app launched via a shell-link,
515 * or we failed to load shell-link console properties.
516 * Therefore, load the console infos for the application from the registry.
518 ConSrvReadUserSettings(&ConsoleInfo
, ProcessId
);
521 * Now, update them with the properties the user might gave to us
522 * via the STARTUPINFO structure before calling CreateProcess
523 * (and which was transmitted via the ConsoleStartInfo structure).
524 * We therefore overwrite the values read in the registry.
526 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USEFILLATTRIBUTE
)
528 ConsoleInfo
.ScreenAttrib
= ConsoleStartInfo
->FillAttribute
;
530 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USECOUNTCHARS
)
532 ConsoleInfo
.ScreenBufferSize
= ConsoleStartInfo
->ScreenBufferSize
;
534 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USESIZE
)
536 // ConsoleInfo->ConsoleSize = ConsoleStartInfo->ConsoleWindowSize;
537 ConsoleInfo
.ConsoleSize
.X
= (SHORT
)ConsoleStartInfo
->ConsoleWindowSize
.cx
;
538 ConsoleInfo
.ConsoleSize
.Y
= (SHORT
)ConsoleStartInfo
->ConsoleWindowSize
.cy
;
541 if (ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN)
543 ConsoleInfo.FullScreen = TRUE;
549 * Initialize the console
551 Console
->State
= CONSOLE_INITIALIZING
;
552 InitializeCriticalSection(&Console
->Lock
);
553 Console
->ReferenceCount
= 0;
554 InitializeListHead(&Console
->ProcessList
);
555 memcpy(Console
->Colors
, ConsoleInfo
.Colors
, sizeof(ConsoleInfo
.Colors
));
556 Console
->ConsoleSize
= ConsoleInfo
.ConsoleSize
;
559 * Initialize the input buffer
561 Console
->InputBuffer
.Header
.Type
= INPUT_BUFFER
;
562 Console
->InputBuffer
.Header
.Console
= Console
;
564 SecurityAttributes
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
565 SecurityAttributes
.lpSecurityDescriptor
= NULL
;
566 SecurityAttributes
.bInheritHandle
= TRUE
;
567 Console
->InputBuffer
.ActiveEvent
= CreateEventW(&SecurityAttributes
, TRUE
, FALSE
, NULL
);
568 if (NULL
== Console
->InputBuffer
.ActiveEvent
)
570 DeleteCriticalSection(&Console
->Lock
);
571 RtlFreeHeap(ConSrvHeap
, 0, Console
);
572 return STATUS_UNSUCCESSFUL
;
575 Console
->InputBuffer
.Mode
= ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
|
576 ENABLE_ECHO_INPUT
| ENABLE_MOUSE_INPUT
;
577 Console
->QuickEdit
= ConsoleInfo
.QuickEdit
;
578 Console
->InsertMode
= ConsoleInfo
.InsertMode
;
579 InitializeListHead(&Console
->InputBuffer
.ReadWaitQueue
);
580 InitializeListHead(&Console
->InputBuffer
.InputEvents
);
581 Console
->LineBuffer
= NULL
;
582 Console
->CodePage
= GetOEMCP();
583 Console
->OutputCodePage
= GetOEMCP();
585 /* Initialize a new screen buffer with default settings */
586 InitializeListHead(&Console
->BufferList
);
587 Status
= ConSrvCreateScreenBuffer(Console
,
589 ConsoleInfo
.ScreenBufferSize
,
590 ConsoleInfo
.ScreenAttrib
,
591 ConsoleInfo
.PopupAttrib
,
592 (ConsoleInfo
.FullScreen
? CONSOLE_FULLSCREEN_MODE
593 : CONSOLE_WINDOWED_MODE
),
595 ConsoleInfo
.CursorSize
);
596 if (!NT_SUCCESS(Status
))
598 DPRINT1("ConSrvCreateScreenBuffer: failed, Status = 0x%08lx\n", Status
);
599 CloseHandle(Console
->InputBuffer
.ActiveEvent
);
600 DeleteCriticalSection(&Console
->Lock
);
601 RtlFreeHeap(ConSrvHeap
, 0, Console
);
604 /* Make the new screen buffer active */
605 Console
->ActiveBuffer
= NewBuffer
;
606 InitializeListHead(&Console
->WriteWaitQueue
);
609 * Initialize the history buffers
611 InitializeListHead(&Console
->HistoryBuffers
);
612 Console
->HistoryBufferSize
= ConsoleInfo
.HistoryBufferSize
;
613 Console
->NumberOfHistoryBuffers
= ConsoleInfo
.NumberOfHistoryBuffers
;
614 Console
->HistoryNoDup
= ConsoleInfo
.HistoryNoDup
;
616 /* Initialize the console title */
617 RtlCreateUnicodeString(&Console
->OriginalTitle
, ConsoleInfo
.ConsoleTitle
);
618 if (ConsoleInfo
.ConsoleTitle
[0] == L
'\0')
620 if (LoadStringW(ConSrvDllInstance
, IDS_CONSOLE_TITLE
, Title
, sizeof(Title
) / sizeof(Title
[0])))
622 RtlCreateUnicodeString(&Console
->Title
, Title
);
626 RtlCreateUnicodeString(&Console
->Title
, L
"ReactOS Console");
631 RtlCreateUnicodeString(&Console
->Title
, ConsoleInfo
.ConsoleTitle
);
634 /* Lock the console until its initialization is finished */
635 // EnterCriticalSection(&Console->Lock);
638 * If we are not in GUI-mode, start the text-mode terminal emulator.
639 * If we fail, try to start the GUI-mode terminal emulator.
642 GuiMode
= DtbgIsDesktopVisible();
650 DPRINT1("CONSRV: Opening text-mode terminal emulator\n");
651 Status
= TuiInitConsole(Console
,
655 if (!NT_SUCCESS(Status
))
657 DPRINT1("Failed to open text-mode terminal emulator, switching to gui-mode, Status = 0x%08lx\n", Status
);
664 * Try to open the GUI-mode terminal emulator. Two cases are possible:
665 * - We are in GUI-mode, therefore GuiMode == TRUE, the previous test-case
666 * failed and we start GUI-mode terminal emulator.
667 * - We are in text-mode, therefore GuiMode == FALSE, the previous test-case
668 * succeeded BUT we failed at starting text-mode terminal emulator.
669 * Then GuiMode was switched to TRUE in order to try to open the GUI-mode
670 * terminal emulator (Win32k will automatically switch to graphical mode,
671 * therefore no additional code is needed).
675 DPRINT1("CONSRV: Opening GUI-mode terminal emulator\n");
676 Status
= GuiInitConsole(Console
,
682 if (!NT_SUCCESS(Status
))
684 DPRINT1("GuiInitConsole: failed, Status = 0x%08lx\n", Status
);
685 RtlFreeUnicodeString(&Console
->Title
);
686 RtlFreeUnicodeString(&Console
->OriginalTitle
);
687 ConioDeleteScreenBuffer(NewBuffer
);
688 CloseHandle(Console
->InputBuffer
.ActiveEvent
);
689 // LeaveCriticalSection(&Console->Lock);
690 DeleteCriticalSection(&Console
->Lock
);
691 RtlFreeHeap(ConSrvHeap
, 0, Console
);
696 DPRINT("Terminal initialized\n");
698 /* All went right, so add the console to the list */
699 ConSrvLockConsoleListExclusive();
700 DPRINT("Insert in the list\n");
701 InsertTailList(&ConsoleList
, &Console
->Entry
);
703 /* The initialization is finished */
704 DPRINT("Change state\n");
705 Console
->State
= CONSOLE_RUNNING
;
707 /* Unlock the console */
708 // LeaveCriticalSection(&Console->Lock);
710 /* Unlock the console list */
711 ConSrvUnlockConsoleList();
713 /* Copy buffer contents to screen */
714 ConioDrawConsole(Console
);
715 DPRINT("Console drawn\n");
717 /* Return the newly created console to the caller and a success code too */
718 *NewConsole
= Console
;
719 return STATUS_SUCCESS
;
723 ConSrvDeleteConsole(PCONSOLE Console
)
725 DPRINT("ConSrvDeleteConsole\n");
728 * Forbid validation of any console by other threads
729 * during the deletion of this console.
731 ConSrvLockConsoleListExclusive();
733 /* Check the existence of the console, and if it's ok, continue */
734 if (!ConSrvValidateConsolePointer(Console
))
736 /* Unlock the console list and return */
737 ConSrvUnlockConsoleList();
742 * If the console is already being destroyed
743 * (thus not running), just return.
745 if (!ConSrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
))
747 /* Unlock the console list and return */
748 ConSrvUnlockConsoleList();
753 * We are about to be destroyed. Signal it to other people
754 * so that they can terminate what they are doing, and that
755 * they cannot longer validate the console.
757 Console
->State
= CONSOLE_TERMINATING
;
760 * Allow other threads to finish their job: basically, unlock
761 * all other calls to EnterCriticalSection(&Console->Lock); by
762 * ConSrvValidateConsole(Unsafe) functions so that they just see
763 * that we are not in CONSOLE_RUNNING state anymore, or unlock
764 * other concurrent calls to ConSrvDeleteConsole so that they
765 * can see that we are in fact already deleting the console.
767 LeaveCriticalSection(&Console
->Lock
);
768 ConSrvUnlockConsoleList();
770 /* FIXME: Send a terminate message to all the processes owning this console */
772 /* Cleanup the UI-oriented part */
773 ConioCleanupConsole(Console
);
776 * Check that the console is in terminating state before continuing
777 * (the cleanup code must not change the state of the console...
778 * ...unless to cancel console deletion ?).
781 ConSrvLockConsoleListExclusive();
783 /* Re-check the existence of the console, and if it's ok, continue */
784 if (!ConSrvValidateConsolePointer(Console
))
786 /* Unlock the console list and return */
787 ConSrvUnlockConsoleList();
791 if (!ConSrvValidateConsoleUnsafe(Console
, CONSOLE_TERMINATING
, TRUE
))
793 ConSrvUnlockConsoleList();
797 /* We are in destruction */
798 Console
->State
= CONSOLE_IN_DESTRUCTION
;
800 /* Remove the console from the list */
801 RemoveEntryList(&Console
->Entry
);
803 /* Reset the count to be sure */
804 Console
->ReferenceCount
= 0;
806 /* Discard all entries in the input event queue */
807 PurgeInputBuffer(Console
);
809 if (Console
->LineBuffer
) RtlFreeHeap(ConSrvHeap
, 0, Console
->LineBuffer
);
811 IntDeleteAllAliases(Console
);
812 HistoryDeleteBuffers(Console
);
814 ConioDeleteScreenBuffer(Console
->ActiveBuffer
);
815 if (!IsListEmpty(&Console
->BufferList
))
817 DPRINT1("BUG: screen buffer list not empty\n");
820 // CloseHandle(Console->InputBuffer.ActiveEvent);
821 if (Console
->UnpauseEvent
) CloseHandle(Console
->UnpauseEvent
);
823 RtlFreeUnicodeString(&Console
->OriginalTitle
);
824 RtlFreeUnicodeString(&Console
->Title
);
826 DPRINT("ConSrvDeleteConsole - Unlocking\n");
827 LeaveCriticalSection(&Console
->Lock
);
828 DPRINT("ConSrvDeleteConsole - Destroying lock\n");
829 DeleteCriticalSection(&Console
->Lock
);
830 DPRINT("ConSrvDeleteConsole - Lock destroyed ; freeing console\n");
832 RtlFreeHeap(ConSrvHeap
, 0, Console
);
833 DPRINT("ConSrvDeleteConsole - Console freed\n");
835 /* Unlock the console list and return */
836 ConSrvUnlockConsoleList();
840 /* PUBLIC SERVER APIS *********************************************************/
842 CSR_API(SrvAllocConsole
)
844 NTSTATUS Status
= STATUS_SUCCESS
;
845 PCONSOLE_ALLOCCONSOLE AllocConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.AllocConsoleRequest
;
846 PCSR_PROCESS CsrProcess
= CsrGetClientThread()->Process
;
847 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrProcess
);
849 if (ProcessData
->Console
!= NULL
)
851 DPRINT1("Process already has a console\n");
852 return STATUS_ACCESS_DENIED
;
855 if (!CsrValidateMessageBuffer(ApiMessage
,
856 (PVOID
*)&AllocConsoleRequest
->ConsoleStartInfo
,
858 sizeof(CONSOLE_START_INFO
)))
860 return STATUS_INVALID_PARAMETER
;
864 * We are about to create a new console. However when ConSrvNewProcess
865 * was called, we didn't know that we wanted to create a new console and
866 * therefore, we by default inherited the handles table from our parent
867 * process. It's only now that we notice that in fact we do not need
868 * them, because we've created a new console and thus we must use it.
870 * Therefore, free the console we can have and our handles table,
871 * and recreate a new one later on.
873 ConSrvRemoveConsole(ProcessData
);
875 /* Initialize a new Console owned by the Console Leader Process */
876 Status
= ConSrvAllocateConsole(ProcessData
,
877 &AllocConsoleRequest
->InputHandle
,
878 &AllocConsoleRequest
->OutputHandle
,
879 &AllocConsoleRequest
->ErrorHandle
,
880 AllocConsoleRequest
->ConsoleStartInfo
);
881 if (!NT_SUCCESS(Status
))
883 DPRINT1("Console allocation failed\n");
887 /* Return it to the caller */
888 AllocConsoleRequest
->Console
= ProcessData
->Console
;
890 /* Input Wait Handle */
891 AllocConsoleRequest
->InputWaitHandle
= ProcessData
->ConsoleEvent
;
893 /* Set the Property Dialog Handler */
894 ProcessData
->PropDispatcher
= AllocConsoleRequest
->PropDispatcher
;
896 /* Set the Ctrl Dispatcher */
897 ProcessData
->CtrlDispatcher
= AllocConsoleRequest
->CtrlDispatcher
;
899 return STATUS_SUCCESS
;
902 CSR_API(SrvAttachConsole
)
904 NTSTATUS Status
= STATUS_SUCCESS
;
905 PCONSOLE_ATTACHCONSOLE AttachConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.AttachConsoleRequest
;
906 PCSR_PROCESS SourceProcess
= NULL
; // The parent process.
907 PCSR_PROCESS TargetProcess
= CsrGetClientThread()->Process
; // Ourselves.
908 HANDLE ProcessId
= ULongToHandle(AttachConsoleRequest
->ProcessId
);
909 PCONSOLE_PROCESS_DATA SourceProcessData
, TargetProcessData
;
911 TargetProcessData
= ConsoleGetPerProcessData(TargetProcess
);
913 if (TargetProcessData
->Console
!= NULL
)
915 DPRINT1("Process already has a console\n");
916 return STATUS_ACCESS_DENIED
;
919 /* Check whether we try to attach to the parent's console */
920 if (ProcessId
== ULongToHandle(ATTACH_PARENT_PROCESS
))
922 PROCESS_BASIC_INFORMATION ProcessInfo
;
923 ULONG Length
= sizeof(ProcessInfo
);
925 /* Get the real parent's ID */
927 Status
= NtQueryInformationProcess(TargetProcess
->ProcessHandle
,
928 ProcessBasicInformation
,
931 if (!NT_SUCCESS(Status
))
933 DPRINT1("SrvAttachConsole - Cannot retrieve basic process info, Status = %lu\n", Status
);
937 ProcessId
= ULongToHandle(ProcessInfo
.InheritedFromUniqueProcessId
);
940 /* Lock the source process via its PID */
941 Status
= CsrLockProcessByClientId(ProcessId
, &SourceProcess
);
942 if (!NT_SUCCESS(Status
)) return Status
;
944 SourceProcessData
= ConsoleGetPerProcessData(SourceProcess
);
946 if (SourceProcessData
->Console
== NULL
)
948 Status
= STATUS_INVALID_HANDLE
;
953 * We are about to create a new console. However when ConSrvNewProcess
954 * was called, we didn't know that we wanted to create a new console and
955 * therefore, we by default inherited the handles table from our parent
956 * process. It's only now that we notice that in fact we do not need
957 * them, because we've created a new console and thus we must use it.
959 * Therefore, free the console we can have and our handles table,
960 * and recreate a new one later on.
962 ConSrvRemoveConsole(TargetProcessData
);
965 * Inherit the console from the parent,
966 * if any, otherwise return an error.
968 Status
= ConSrvInheritConsole(TargetProcessData
,
969 SourceProcessData
->Console
,
971 &AttachConsoleRequest
->InputHandle
,
972 &AttachConsoleRequest
->OutputHandle
,
973 &AttachConsoleRequest
->ErrorHandle
);
974 if (!NT_SUCCESS(Status
))
976 DPRINT1("Console inheritance failed\n");
980 /* Return it to the caller */
981 AttachConsoleRequest
->Console
= TargetProcessData
->Console
;
983 /* Input Wait Handle */
984 AttachConsoleRequest
->InputWaitHandle
= TargetProcessData
->ConsoleEvent
;
986 /* Set the Property Dialog Handler */
987 TargetProcessData
->PropDispatcher
= AttachConsoleRequest
->PropDispatcher
;
989 /* Set the Ctrl Dispatcher */
990 TargetProcessData
->CtrlDispatcher
= AttachConsoleRequest
->CtrlDispatcher
;
992 Status
= STATUS_SUCCESS
;
995 /* Unlock the "source" process and exit */
996 CsrUnlockProcess(SourceProcess
);
1000 CSR_API(SrvFreeConsole
)
1002 ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
));
1003 return STATUS_SUCCESS
;
1006 CSR_API(SrvSetConsoleMode
)
1008 #define CONSOLE_VALID_CONTROL_MODES ( ENABLE_EXTENDED_FLAGS | ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE )
1009 #define CONSOLE_VALID_INPUT_MODES ( ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | \
1010 ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT | \
1011 ENABLE_MOUSE_INPUT )
1012 #define CONSOLE_VALID_OUTPUT_MODES ( ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT )
1015 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleModeRequest
;
1016 DWORD ConsoleMode
= ConsoleModeRequest
->ConsoleMode
;
1017 PCONSOLE_IO_OBJECT Object
= NULL
;
1019 Status
= ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
1020 ConsoleModeRequest
->ConsoleHandle
,
1021 &Object
, NULL
, GENERIC_WRITE
, TRUE
, 0);
1022 if (!NT_SUCCESS(Status
)) return Status
;
1024 Status
= STATUS_SUCCESS
;
1026 if (INPUT_BUFFER
== Object
->Type
)
1028 PCONSOLE_INPUT_BUFFER InputBuffer
= (PCONSOLE_INPUT_BUFFER
)Object
;
1029 PCONSOLE Console
= InputBuffer
->Header
.Console
;
1031 DPRINT("SetConsoleMode(Input, %d)\n", ConsoleMode
);
1034 * 1. Only the presence of valid mode flags is allowed.
1036 if (ConsoleMode
& ~(CONSOLE_VALID_INPUT_MODES
| CONSOLE_VALID_CONTROL_MODES
))
1038 Status
= STATUS_INVALID_PARAMETER
;
1043 * 2. If we use control mode flags without ENABLE_EXTENDED_FLAGS,
1044 * then consider the flags invalid.
1046 if ( (ConsoleMode & CONSOLE_VALID_CONTROL_MODES) &&
1047 (ConsoleMode & ENABLE_EXTENDED_FLAGS) == 0 )
1049 Status = STATUS_INVALID_PARAMETER;
1055 * 3. Now we can continue.
1057 if (ConsoleMode
& CONSOLE_VALID_CONTROL_MODES
)
1059 Console
->QuickEdit
= !!(ConsoleMode
& ENABLE_QUICK_EDIT_MODE
);
1060 Console
->InsertMode
= !!(ConsoleMode
& ENABLE_INSERT_MODE
);
1062 InputBuffer
->Mode
= (ConsoleMode
& CONSOLE_VALID_INPUT_MODES
);
1064 else if (SCREEN_BUFFER
== Object
->Type
)
1066 PCONSOLE_SCREEN_BUFFER Buffer
= (PCONSOLE_SCREEN_BUFFER
)Object
;
1068 DPRINT("SetConsoleMode(Output, %d)\n", ConsoleMode
);
1070 if (ConsoleMode
& ~CONSOLE_VALID_OUTPUT_MODES
)
1072 Status
= STATUS_INVALID_PARAMETER
;
1076 Buffer
->Mode
= (ConsoleMode
& CONSOLE_VALID_OUTPUT_MODES
);
1081 Status
= STATUS_INVALID_HANDLE
;
1085 ConSrvReleaseObject(Object
, TRUE
);
1089 CSR_API(SrvGetConsoleMode
)
1092 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleModeRequest
;
1093 PCONSOLE_IO_OBJECT Object
= NULL
;
1095 Status
= ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
1096 ConsoleModeRequest
->ConsoleHandle
,
1097 &Object
, NULL
, GENERIC_READ
, TRUE
, 0);
1098 if (!NT_SUCCESS(Status
)) return Status
;
1100 Status
= STATUS_SUCCESS
;
1102 if (INPUT_BUFFER
== Object
->Type
)
1104 PCONSOLE_INPUT_BUFFER InputBuffer
= (PCONSOLE_INPUT_BUFFER
)Object
;
1105 PCONSOLE Console
= InputBuffer
->Header
.Console
;
1106 DWORD ConsoleMode
= InputBuffer
->Mode
;
1108 if (Console
->QuickEdit
|| Console
->InsertMode
)
1110 // Windows does this, even if it's not documented on MSDN
1111 ConsoleMode
|= ENABLE_EXTENDED_FLAGS
;
1113 if (Console
->QuickEdit
) ConsoleMode
|= ENABLE_QUICK_EDIT_MODE
;
1114 if (Console
->InsertMode
) ConsoleMode
|= ENABLE_INSERT_MODE
;
1117 ConsoleModeRequest
->ConsoleMode
= ConsoleMode
;
1119 else if (SCREEN_BUFFER
== Object
->Type
)
1121 PCONSOLE_SCREEN_BUFFER Buffer
= (PCONSOLE_SCREEN_BUFFER
)Object
;
1122 ConsoleModeRequest
->ConsoleMode
= Buffer
->Mode
;
1126 Status
= STATUS_INVALID_HANDLE
;
1129 ConSrvReleaseObject(Object
, TRUE
);
1133 CSR_API(SrvSetConsoleTitle
)
1136 PCONSOLE_GETSETCONSOLETITLE TitleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.TitleRequest
;
1137 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
1141 if (!CsrValidateMessageBuffer(ApiMessage
,
1142 (PVOID
)&TitleRequest
->Title
,
1143 TitleRequest
->Length
,
1146 return STATUS_INVALID_PARAMETER
;
1149 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1150 if (!NT_SUCCESS(Status
))
1152 DPRINT1("Can't get console\n");
1156 /* Allocate a new buffer to hold the new title (NULL-terminated) */
1157 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, TitleRequest
->Length
+ sizeof(WCHAR
));
1160 /* Free the old title */
1161 RtlFreeUnicodeString(&Console
->Title
);
1163 /* Copy title to console */
1164 Console
->Title
.Buffer
= Buffer
;
1165 Console
->Title
.Length
= TitleRequest
->Length
;
1166 Console
->Title
.MaximumLength
= Console
->Title
.Length
+ sizeof(WCHAR
);
1167 RtlCopyMemory(Console
->Title
.Buffer
,
1168 TitleRequest
->Title
,
1169 Console
->Title
.Length
);
1170 Console
->Title
.Buffer
[Console
->Title
.Length
/ sizeof(WCHAR
)] = L
'\0';
1172 ConioChangeTitle(Console
);
1173 Status
= STATUS_SUCCESS
;
1177 Status
= STATUS_NO_MEMORY
;
1180 ConSrvReleaseConsole(Console
, TRUE
);
1184 CSR_API(SrvGetConsoleTitle
)
1187 PCONSOLE_GETSETCONSOLETITLE TitleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.TitleRequest
;
1188 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
1192 if (!CsrValidateMessageBuffer(ApiMessage
,
1193 (PVOID
)&TitleRequest
->Title
,
1194 TitleRequest
->Length
,
1197 return STATUS_INVALID_PARAMETER
;
1200 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1201 if (!NT_SUCCESS(Status
))
1203 DPRINT1("Can't get console\n");
1207 /* Copy title of the console to the user title buffer */
1208 if (TitleRequest
->Length
>= sizeof(WCHAR
))
1210 Length
= min(TitleRequest
->Length
- sizeof(WCHAR
), Console
->Title
.Length
);
1211 memcpy(TitleRequest
->Title
, Console
->Title
.Buffer
, Length
);
1212 TitleRequest
->Title
[Length
/ sizeof(WCHAR
)] = L
'\0';
1215 TitleRequest
->Length
= Console
->Title
.Length
;
1217 ConSrvReleaseConsole(Console
, TRUE
);
1218 return STATUS_SUCCESS
;
1221 /**********************************************************************
1222 * HardwareStateProperty
1225 * Set/Get the value of the HardwareState and switch
1226 * between direct video buffer ouput and GDI windowed
1229 * Client hands us a CONSOLE_GETSETHWSTATE object.
1230 * We use the same object to Request.
1232 * ConsoleHwState has the correct size to be compatible
1233 * with NT's, but values are not.
1235 static NTSTATUS FASTCALL
1236 SetConsoleHardwareState(PCONSOLE Console
, ULONG ConsoleHwState
)
1238 DPRINT1("Console Hardware State: %d\n", ConsoleHwState
);
1240 if ((CONSOLE_HARDWARE_STATE_GDI_MANAGED
== ConsoleHwState
)
1241 ||(CONSOLE_HARDWARE_STATE_DIRECT
== ConsoleHwState
))
1243 if (Console
->HardwareState
!= ConsoleHwState
)
1245 /* TODO: implement switching from full screen to windowed mode */
1246 /* TODO: or back; now simply store the hardware state */
1247 Console
->HardwareState
= ConsoleHwState
;
1250 return STATUS_SUCCESS
;
1253 return STATUS_INVALID_PARAMETER_3
; /* Client: (handle, set_get, [mode]) */
1256 CSR_API(SrvGetConsoleHardwareState
)
1259 PCONSOLE_GETSETHWSTATE HardwareStateRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.HardwareStateRequest
;
1260 PCONSOLE_SCREEN_BUFFER Buff
;
1263 Status
= ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
1264 HardwareStateRequest
->OutputHandle
,
1268 if (!NT_SUCCESS(Status
))
1270 DPRINT1("Failed to get console handle in SrvGetConsoleHardwareState\n");
1274 Console
= Buff
->Header
.Console
;
1275 HardwareStateRequest
->State
= Console
->HardwareState
;
1277 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1281 CSR_API(SrvSetConsoleHardwareState
)
1284 PCONSOLE_GETSETHWSTATE HardwareStateRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.HardwareStateRequest
;
1285 PCONSOLE_SCREEN_BUFFER Buff
;
1288 Status
= ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
1289 HardwareStateRequest
->OutputHandle
,
1293 if (!NT_SUCCESS(Status
))
1295 DPRINT1("Failed to get console handle in SrvSetConsoleHardwareState\n");
1299 DPRINT("Setting console hardware state.\n");
1300 Console
= Buff
->Header
.Console
;
1301 Status
= SetConsoleHardwareState(Console
, HardwareStateRequest
->State
);
1303 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1307 CSR_API(SrvGetConsoleDisplayMode
)
1310 PCONSOLE_GETDISPLAYMODE GetDisplayModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetDisplayModeRequest
;
1312 ULONG DisplayMode
= 0;
1314 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
1316 if (!NT_SUCCESS(Status
))
1318 DPRINT1("Failed to get console handle in SrvGetConsoleDisplayMode\n");
1322 if (Console
->ActiveBuffer
->DisplayMode
& CONSOLE_FULLSCREEN_MODE
)
1323 DisplayMode
|= CONSOLE_FULLSCREEN_HARDWARE
; // CONSOLE_FULLSCREEN
1324 else if (Console
->ActiveBuffer
->DisplayMode
& CONSOLE_WINDOWED_MODE
)
1325 DisplayMode
|= CONSOLE_WINDOWED
;
1327 GetDisplayModeRequest
->DisplayMode
= DisplayMode
;
1328 Status
= STATUS_SUCCESS
;
1330 ConSrvReleaseConsole(Console
, TRUE
);
1334 CSR_API(SrvSetConsoleDisplayMode
)
1337 PCONSOLE_SETDISPLAYMODE SetDisplayModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetDisplayModeRequest
;
1338 PCONSOLE_SCREEN_BUFFER Buff
;
1340 Status
= ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
1341 SetDisplayModeRequest
->OutputHandle
,
1345 if (!NT_SUCCESS(Status
))
1347 DPRINT1("Failed to get console handle in SrvSetConsoleDisplayMode\n");
1351 if (SetDisplayModeRequest
->DisplayMode
& ~(CONSOLE_FULLSCREEN_MODE
| CONSOLE_WINDOWED_MODE
))
1353 Status
= STATUS_INVALID_PARAMETER
;
1357 Buff
->DisplayMode
= SetDisplayModeRequest
->DisplayMode
;
1358 // TODO: Change the display mode
1359 SetDisplayModeRequest
->NewSBDim
= Buff
->ScreenBufferSize
;
1361 Status
= STATUS_SUCCESS
;
1364 ConSrvReleaseScreenBuffer(Buff
, TRUE
);
1368 CSR_API(SrvGetConsoleWindow
)
1371 PCONSOLE_GETWINDOW GetWindowRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetWindowRequest
;
1374 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1375 if (!NT_SUCCESS(Status
)) return Status
;
1377 GetWindowRequest
->WindowHandle
= ConioGetConsoleWindowHandle(Console
);
1378 ConSrvReleaseConsole(Console
, TRUE
);
1380 return STATUS_SUCCESS
;
1383 CSR_API(SrvSetConsoleIcon
)
1386 PCONSOLE_SETICON SetIconRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetIconRequest
;
1389 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1390 if (!NT_SUCCESS(Status
)) return Status
;
1392 Status
= (ConioChangeIcon(Console
, SetIconRequest
->WindowIcon
)
1394 : STATUS_UNSUCCESSFUL
);
1396 ConSrvReleaseConsole(Console
, TRUE
);
1401 CSR_API(SrvGetConsoleCP
)
1404 PCONSOLE_GETSETINPUTOUTPUTCP ConsoleCPRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleCPRequest
;
1407 DPRINT("SrvGetConsoleCP, getting %s Code Page\n",
1408 ConsoleCPRequest
->InputCP
? "Input" : "Output");
1410 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1411 if (!NT_SUCCESS(Status
)) return Status
;
1413 ConsoleCPRequest
->CodePage
= (ConsoleCPRequest
->InputCP
? Console
->CodePage
1414 : Console
->OutputCodePage
);
1415 ConSrvReleaseConsole(Console
, TRUE
);
1416 return STATUS_SUCCESS
;
1419 CSR_API(SrvSetConsoleCP
)
1422 PCONSOLE_GETSETINPUTOUTPUTCP ConsoleCPRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleCPRequest
;
1425 DPRINT("SrvSetConsoleCP, setting %s Code Page\n",
1426 ConsoleCPRequest
->InputCP
? "Input" : "Output");
1428 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1429 if (!NT_SUCCESS(Status
)) return Status
;
1431 if (IsValidCodePage(ConsoleCPRequest
->CodePage
))
1433 if (ConsoleCPRequest
->InputCP
)
1434 Console
->CodePage
= ConsoleCPRequest
->CodePage
;
1436 Console
->OutputCodePage
= ConsoleCPRequest
->CodePage
;
1438 ConSrvReleaseConsole(Console
, TRUE
);
1439 return STATUS_SUCCESS
;
1442 ConSrvReleaseConsole(Console
, TRUE
);
1443 return STATUS_INVALID_PARAMETER
;
1446 CSR_API(SrvGetConsoleProcessList
)
1449 PCONSOLE_GETPROCESSLIST GetProcessListRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetProcessListRequest
;
1451 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
1453 PCONSOLE_PROCESS_DATA current
;
1454 PLIST_ENTRY current_entry
;
1457 if (!CsrValidateMessageBuffer(ApiMessage
,
1458 (PVOID
)&GetProcessListRequest
->pProcessIds
,
1459 GetProcessListRequest
->nMaxIds
,
1462 return STATUS_INVALID_PARAMETER
;
1465 Buffer
= GetProcessListRequest
->pProcessIds
;
1467 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1468 if (!NT_SUCCESS(Status
)) return Status
;
1470 for (current_entry
= Console
->ProcessList
.Flink
;
1471 current_entry
!= &Console
->ProcessList
;
1472 current_entry
= current_entry
->Flink
)
1474 current
= CONTAINING_RECORD(current_entry
, CONSOLE_PROCESS_DATA
, ConsoleLink
);
1475 if (++nItems
<= GetProcessListRequest
->nMaxIds
)
1477 *Buffer
++ = HandleToUlong(current
->Process
->ClientId
.UniqueProcess
);
1481 ConSrvReleaseConsole(Console
, TRUE
);
1483 GetProcessListRequest
->nProcessIdsTotal
= nItems
;
1484 return STATUS_SUCCESS
;
1487 CSR_API(SrvGenerateConsoleCtrlEvent
)
1490 PCONSOLE_GENERATECTRLEVENT GenerateCtrlEventRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GenerateCtrlEventRequest
;
1493 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1494 if (!NT_SUCCESS(Status
)) return Status
;
1496 Status
= ConSrvConsoleProcessCtrlEvent(Console
,
1497 GenerateCtrlEventRequest
->ProcessGroup
,
1498 GenerateCtrlEventRequest
->Event
);
1500 ConSrvReleaseConsole(Console
, TRUE
);
1504 CSR_API(SrvGetConsoleSelectionInfo
)
1507 PCONSOLE_GETSELECTIONINFO GetSelectionInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetSelectionInfoRequest
;
1510 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1511 if (NT_SUCCESS(Status
))
1513 memset(&GetSelectionInfoRequest
->Info
, 0, sizeof(CONSOLE_SELECTION_INFO
));
1514 if (Console
->Selection
.dwFlags
!= 0)
1515 GetSelectionInfoRequest
->Info
= Console
->Selection
;
1516 ConSrvReleaseConsole(Console
, TRUE
);