2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/winsrv/consrv/console.c
5 * PURPOSE: Console Management Functions
6 * PROGRAMMERS: Gé van Geldorp
8 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
11 /* INCLUDES *******************************************************************/
15 #include <ndk/psfuncs.h>
24 // FIXME: Add this prototype to winternl.h / rtlfuncs.h / ...
25 NTSTATUS NTAPI
RtlGetLastNtStatus(VOID
);
27 /* GLOBALS ********************************************************************/
29 static ULONG ConsoleListSize
;
30 static PCONSRV_CONSOLE
* ConsoleList
; /* The list of the ConSrv consoles */
31 static RTL_RESOURCE ListLock
;
33 #define ConSrvLockConsoleListExclusive() \
34 RtlAcquireResourceExclusive(&ListLock, TRUE)
36 #define ConSrvLockConsoleListShared() \
37 RtlAcquireResourceShared(&ListLock, TRUE)
39 #define ConSrvUnlockConsoleList() \
40 RtlReleaseResource(&ListLock)
44 InsertConsole(OUT PHANDLE Handle
,
45 IN PCONSRV_CONSOLE Console
)
47 #define CONSOLE_HANDLES_INCREMENT 2 * 3
49 NTSTATUS Status
= STATUS_SUCCESS
;
51 PCONSRV_CONSOLE
* Block
;
53 ASSERT( (ConsoleList
== NULL
&& ConsoleListSize
== 0) ||
54 (ConsoleList
!= NULL
&& ConsoleListSize
!= 0) );
56 /* All went right, so add the console to the list */
57 ConSrvLockConsoleListExclusive();
58 DPRINT1("Insert in the list\n");
62 for (i
= 0; i
< ConsoleListSize
; i
++)
64 if (ConsoleList
[i
] == NULL
) break;
68 if (i
>= ConsoleListSize
)
70 DPRINT1("Creation of a new handles table\n");
71 /* Allocate a new handles table */
72 Block
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
,
74 CONSOLE_HANDLES_INCREMENT
) * sizeof(PCONSRV_CONSOLE
));
77 Status
= STATUS_UNSUCCESSFUL
;
81 /* If we previously had a handles table, free it and use the new one */
84 /* Copy the handles from the old table to the new one */
87 ConsoleListSize
* sizeof(PCONSRV_CONSOLE
));
88 ConsoleFreeHeap(ConsoleList
);
91 ConsoleListSize
+= CONSOLE_HANDLES_INCREMENT
;
94 ConsoleList
[i
] = Console
;
95 *Handle
= ULongToHandle((i
<< 2) | 0x3);
98 /* Unlock the console list and return status */
99 ConSrvUnlockConsoleList();
106 RemoveConsoleByHandle(IN HANDLE Handle
)
108 NTSTATUS Status
= STATUS_SUCCESS
;
109 PCONSRV_CONSOLE Console
;
111 BOOLEAN ValidHandle
= ((HandleToULong(Handle
) & 0x3) == 0x3);
112 ULONG Index
= HandleToULong(Handle
) >> 2;
114 if (!ValidHandle
) return STATUS_INVALID_HANDLE
;
116 ASSERT( (ConsoleList
== NULL
&& ConsoleListSize
== 0) ||
117 (ConsoleList
!= NULL
&& ConsoleListSize
!= 0) );
119 /* Remove the console from the list */
120 ConSrvLockConsoleListExclusive();
122 if (Index
>= ConsoleListSize
||
123 (Console
= ConsoleList
[Index
]) == NULL
)
125 Status
= STATUS_INVALID_HANDLE
;
129 ConsoleList
[Index
] = NULL
;
132 /* Unlock the console list and return status */
133 ConSrvUnlockConsoleList();
139 RemoveConsoleByPointer(IN PCONSRV_CONSOLE Console
)
143 if (!Console
) return STATUS_INVALID_PARAMETER
;
145 ASSERT( (ConsoleList
== NULL
&& ConsoleListSize
== 0) ||
146 (ConsoleList
!= NULL
&& ConsoleListSize
!= 0) );
148 /* Remove the console from the list */
149 ConSrvLockConsoleListExclusive();
153 for (i
= 0; i
< ConsoleListSize
; i
++)
155 if (ConsoleList
[i
] == Console
) ConsoleList
[i
] = NULL
;
159 /* Unlock the console list */
160 ConSrvUnlockConsoleList();
162 return STATUS_SUCCESS
;
166 ConSrvValidateConsole(OUT PCONSRV_CONSOLE
* Console
,
167 IN HANDLE ConsoleHandle
,
168 IN CONSOLE_STATE ExpectedState
,
169 IN BOOLEAN LockConsole
)
171 BOOLEAN RetVal
= FALSE
;
172 PCONSRV_CONSOLE ValidatedConsole
;
174 BOOLEAN ValidHandle
= ((HandleToULong(ConsoleHandle
) & 0x3) == 0x3);
175 ULONG Index
= HandleToULong(ConsoleHandle
) >> 2;
177 if (!ValidHandle
) return FALSE
;
179 if (!Console
) return FALSE
;
183 * Forbid creation or deletion of consoles when
184 * checking for the existence of a console.
186 ConSrvLockConsoleListShared();
188 if (Index
>= ConsoleListSize
||
189 (ValidatedConsole
= ConsoleList
[Index
]) == NULL
)
191 /* Unlock the console list */
192 ConSrvUnlockConsoleList();
197 ValidatedConsole
= ConsoleList
[Index
];
199 /* Unlock the console list and return */
200 ConSrvUnlockConsoleList();
202 RetVal
= ConDrvValidateConsoleUnsafe(ValidatedConsole
,
205 if (RetVal
) *Console
= ValidatedConsole
;
211 /* PRIVATE FUNCTIONS **********************************************************/
214 ConioPause(PCONSRV_CONSOLE Console
, UINT Flags
)
216 Console
->PauseFlags
|= Flags
;
217 ConDrvPause(Console
);
221 ConioUnpause(PCONSRV_CONSOLE Console
, UINT Flags
)
223 Console
->PauseFlags
&= ~Flags
;
225 // if ((Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION)) == 0)
226 if (Console
->PauseFlags
== 0)
228 ConDrvUnpause(Console
);
230 CsrNotifyWait(&Console
->WriteWaitQueue
,
234 if (!IsListEmpty(&Console
->WriteWaitQueue
))
236 CsrDereferenceWait(&Console
->WriteWaitQueue
);
242 ConSrvGetConsole(IN PCONSOLE_PROCESS_DATA ProcessData
,
243 OUT PCONSRV_CONSOLE
* Console
,
244 IN BOOLEAN LockConsole
)
246 NTSTATUS Status
= STATUS_INVALID_HANDLE
;
247 PCONSRV_CONSOLE GrabConsole
;
249 // if (Console == NULL) return STATUS_INVALID_PARAMETER;
253 // RtlEnterCriticalSection(&ProcessData->HandleTableLock);
255 if (ConSrvValidateConsole(&GrabConsole
,
256 ProcessData
->ConsoleHandle
,
260 InterlockedIncrement(&GrabConsole
->ReferenceCount
);
261 *Console
= GrabConsole
;
262 Status
= STATUS_SUCCESS
;
265 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
270 ConSrvReleaseConsole(IN PCONSRV_CONSOLE Console
,
271 IN BOOLEAN WasConsoleLocked
)
275 if (!Console
) return;
276 // if (Console->ReferenceCount == 0) return; // This shouldn't happen
277 ASSERT(Console
->ReferenceCount
> 0);
279 /* The console must be locked */
280 // ASSERT(Console_locked);
283 * Decrement the reference count. Save the new value too,
284 * because Console->ReferenceCount might be modified after
285 * the console gets unlocked but before we check whether we
288 RefCount
= _InterlockedDecrement(&Console
->ReferenceCount
);
290 /* Unlock the console if needed */
291 if (WasConsoleLocked
) LeaveCriticalSection(&Console
->Lock
);
293 /* Delete the console if needed */
294 if (RefCount
<= 0) ConSrvDeleteConsole(Console
);
298 /* CONSOLE INITIALIZATION FUNCTIONS *******************************************/
301 ConSrvInitConsoleSupport(VOID
)
303 DPRINT("CONSRV: ConSrvInitConsoleSupport()\n");
305 /* Initialize the console list and its lock */
308 RtlInitializeResource(&ListLock
);
310 /* Should call LoadKeyboardLayout */
314 ConSrvInitTerminal(IN OUT PTERMINAL Terminal
,
315 IN OUT PCONSOLE_INFO ConsoleInfo
,
316 IN OUT PVOID ExtraConsoleInfo
,
319 ConSrvDeinitTerminal(IN OUT PTERMINAL Terminal
);
322 ConSrvInitConsole(OUT PHANDLE NewConsoleHandle
,
323 OUT PCONSRV_CONSOLE
* NewConsole
,
324 IN OUT PCONSOLE_START_INFO ConsoleStartInfo
,
325 IN ULONG ConsoleLeaderProcessId
)
328 HANDLE ConsoleHandle
;
329 PCONSRV_CONSOLE Console
;
330 CONSOLE_INFO ConsoleInfo
;
333 TERMINAL Terminal
; /* The ConSrv terminal for this console */
335 if (NewConsole
== NULL
|| ConsoleStartInfo
== NULL
)
336 return STATUS_INVALID_PARAMETER
;
341 * Load the console settings
344 /* 1. Load the default settings */
345 ConSrvGetDefaultSettings(&ConsoleInfo
, ConsoleLeaderProcessId
);
347 /* 2. Get the title of the console (initialize ConsoleInfo.ConsoleTitle) */
348 Length
= min(wcslen(ConsoleStartInfo
->ConsoleTitle
),
349 sizeof(ConsoleInfo
.ConsoleTitle
) / sizeof(ConsoleInfo
.ConsoleTitle
[0]) - 1);
350 wcsncpy(ConsoleInfo
.ConsoleTitle
, ConsoleStartInfo
->ConsoleTitle
, Length
);
351 ConsoleInfo
.ConsoleTitle
[Length
] = L
'\0';
353 /* 3. Initialize the ConSrv terminal */
354 Status
= ConSrvInitTerminal(&Terminal
,
357 ConsoleLeaderProcessId
);
358 if (!NT_SUCCESS(Status
))
360 DPRINT1("CONSRV: Failed to initialize a terminal, Status = 0x%08lx\n", Status
);
363 DPRINT("CONSRV: Terminal initialized\n");
366 * 4. Load the remaining console settings via the registry.
368 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
371 * Either we weren't created by an app launched via a shell-link,
372 * or we failed to load shell-link console properties.
373 * Therefore, load the console infos for the application from the registry.
375 ConSrvReadUserSettings(&ConsoleInfo
, ConsoleLeaderProcessId
);
378 * Now, update them with the properties the user might gave to us
379 * via the STARTUPINFO structure before calling CreateProcess
380 * (and which was transmitted via the ConsoleStartInfo structure).
381 * We therefore overwrite the values read in the registry.
383 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USEFILLATTRIBUTE
)
385 ConsoleInfo
.ScreenAttrib
= (USHORT
)ConsoleStartInfo
->wFillAttribute
;
387 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USECOUNTCHARS
)
389 ConsoleInfo
.ScreenBufferSize
= ConsoleStartInfo
->dwScreenBufferSize
;
391 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USESIZE
)
393 ConsoleInfo
.ConsoleSize
= ConsoleStartInfo
->dwWindowSize
;
397 /* Set-up the code page */
398 ConsoleInfo
.CodePage
= GetOEMCP();
400 /* Initialize a new console via the driver */
401 Status
= ConDrvInitConsole(&Console
, &ConsoleInfo
);
402 if (!NT_SUCCESS(Status
))
404 DPRINT1("Creating a new console failed, Status = 0x%08lx\n", Status
);
405 ConSrvDeinitTerminal(&Terminal
);
410 DPRINT("Console initialized\n");
412 /*** Register ConSrv features ***/
414 /* Initialize process support */
415 InitializeListHead(&Console
->ProcessList
);
416 Console
->NotifiedLastCloseProcess
= NULL
;
417 Console
->NotifyLastClose
= FALSE
;
419 /* Initialize pausing support */
420 Console
->PauseFlags
= 0;
421 InitializeListHead(&Console
->ReadWaitQueue
);
422 InitializeListHead(&Console
->WriteWaitQueue
);
424 /* Initialize the alias and history buffers */
425 Console
->Aliases
= NULL
;
426 InitializeListHead(&Console
->HistoryBuffers
);
427 Console
->HistoryBufferSize
= ConsoleInfo
.HistoryBufferSize
;
428 Console
->NumberOfHistoryBuffers
= ConsoleInfo
.NumberOfHistoryBuffers
;
429 Console
->HistoryNoDup
= ConsoleInfo
.HistoryNoDup
;
431 /* Initialize the Input Line Discipline */
432 Console
->LineBuffer
= NULL
;
433 Console
->LinePos
= Console
->LineMaxSize
= Console
->LineSize
= 0;
434 Console
->LineComplete
= Console
->LineUpPressed
= FALSE
;
436 Console
->LineInsertToggle
=
437 Console
->InsertMode
= ConsoleInfo
.InsertMode
;
438 Console
->QuickEdit
= ConsoleInfo
.QuickEdit
;
441 InitializeListHead(&Console
->PopupWindows
);
444 memcpy(Console
->Colors
, ConsoleInfo
.Colors
, sizeof(ConsoleInfo
.Colors
));
446 /* Attach the ConSrv terminal to the console */
447 Status
= ConDrvRegisterTerminal(Console
, &Terminal
);
448 if (!NT_SUCCESS(Status
))
450 DPRINT1("Failed to register terminal to the given console, Status = 0x%08lx\n", Status
);
451 ConDrvDeleteConsole(Console
);
452 ConSrvDeinitTerminal(&Terminal
);
455 DPRINT("Terminal registered\n");
457 /* All went right, so add the console to the list */
458 Status
= InsertConsole(&ConsoleHandle
, Console
);
460 /* Return the newly created console to the caller and a success code too */
461 *NewConsoleHandle
= ConsoleHandle
;
462 *NewConsole
= Console
;
463 return STATUS_SUCCESS
;
467 ConSrvDeleteConsole(PCONSRV_CONSOLE Console
)
469 DPRINT("ConSrvDeleteConsole\n");
471 // FIXME: Send a terminate message to all the processes owning this console
473 /* Remove the console from the list */
474 RemoveConsoleByPointer(Console
);
476 /* Clean the Input Line Discipline */
477 if (Console
->LineBuffer
) ConsoleFreeHeap(Console
->LineBuffer
);
479 /* Clean aliases and history */
480 IntDeleteAllAliases(Console
);
481 HistoryDeleteBuffers(Console
);
483 /* Now, call the driver. ConDrvDeregisterTerminal is called on-demand. */
484 ConDrvDeleteConsole(Console
);
493 ConSrvConsoleCtrlEventTimeout(IN ULONG CtrlEvent
,
494 IN PCONSOLE_PROCESS_DATA ProcessData
,
497 NTSTATUS Status
= STATUS_SUCCESS
;
499 DPRINT("ConSrvConsoleCtrlEventTimeout Parent ProcessId = %x\n", ProcessData
->Process
->ClientId
.UniqueProcess
);
501 if (ProcessData
->CtrlDispatcher
)
505 HANDLE Thread
= NULL
;
509 Thread
= CreateRemoteThread(ProcessData
->Process
->ProcessHandle
, NULL
, 0,
510 ProcessData
->CtrlDispatcher
,
511 UlongToPtr(CtrlEvent
), 0, NULL
);
514 Status
= RtlGetLastNtStatus();
515 DPRINT1("Failed thread creation, Status = 0x%08lx\n", Status
);
519 DPRINT("ProcessData->CtrlDispatcher remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n", ProcessData
->Process
->ClientId
.UniqueProcess
, ProcessData
->Process
);
520 WaitForSingleObject(Thread
, Timeout
);
529 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
531 Status
= _SEH2_GetExceptionCode();
532 DPRINT1("ConSrvConsoleCtrlEventTimeout - Caught an exception, Status = 0x%08lx\n", Status
);
541 ConSrvConsoleCtrlEvent(IN ULONG CtrlEvent
,
542 IN PCONSOLE_PROCESS_DATA ProcessData
)
544 return ConSrvConsoleCtrlEventTimeout(CtrlEvent
, ProcessData
, 0);
547 PCONSOLE_PROCESS_DATA NTAPI
548 ConSrvGetConsoleLeaderProcess(IN PCONSRV_CONSOLE Console
)
550 if (Console
== NULL
) return NULL
;
552 return CONTAINING_RECORD(Console
->ProcessList
.Blink
,
553 CONSOLE_PROCESS_DATA
,
558 ConSrvGetConsoleProcessList(IN PCONSRV_CONSOLE Console
,
559 IN OUT PULONG ProcessIdsList
,
560 IN ULONG MaxIdListItems
,
561 OUT PULONG ProcessIdsTotal
)
563 PCONSOLE_PROCESS_DATA current
;
564 PLIST_ENTRY current_entry
;
566 if (Console
== NULL
|| ProcessIdsList
== NULL
|| ProcessIdsTotal
== NULL
)
567 return STATUS_INVALID_PARAMETER
;
569 *ProcessIdsTotal
= 0;
571 for (current_entry
= Console
->ProcessList
.Flink
;
572 current_entry
!= &Console
->ProcessList
;
573 current_entry
= current_entry
->Flink
)
575 current
= CONTAINING_RECORD(current_entry
, CONSOLE_PROCESS_DATA
, ConsoleLink
);
576 if (++(*ProcessIdsTotal
) <= MaxIdListItems
)
578 *ProcessIdsList
++ = HandleToUlong(current
->Process
->ClientId
.UniqueProcess
);
582 return STATUS_SUCCESS
;
585 // ConSrvGenerateConsoleCtrlEvent
587 ConSrvConsoleProcessCtrlEvent(IN PCONSRV_CONSOLE Console
,
588 IN ULONG ProcessGroupId
,
591 NTSTATUS Status
= STATUS_SUCCESS
;
592 PLIST_ENTRY current_entry
;
593 PCONSOLE_PROCESS_DATA current
;
595 /* If the console is already being destroyed, just return */
596 if (!ConDrvValidateConsoleState(Console
, CONSOLE_RUNNING
))
597 return STATUS_UNSUCCESSFUL
;
600 * Loop through the process list, from the most recent process
601 * (the active one) to the oldest one (the first created, i.e.
602 * the console leader process), and for each, send an event
603 * (new processes are inserted at the head of the console process list).
605 current_entry
= Console
->ProcessList
.Flink
;
606 while (current_entry
!= &Console
->ProcessList
)
608 current
= CONTAINING_RECORD(current_entry
, CONSOLE_PROCESS_DATA
, ConsoleLink
);
609 current_entry
= current_entry
->Flink
;
612 * Only processes belonging to the same process group are signaled.
613 * If the process group ID is zero, then all the processes are signaled.
615 if (ProcessGroupId
== 0 || current
->Process
->ProcessGroupId
== ProcessGroupId
)
617 Status
= ConSrvConsoleCtrlEvent(CtrlEvent
, current
);
628 /* PUBLIC SERVER APIS *********************************************************/
630 CSR_API(SrvAllocConsole
)
632 NTSTATUS Status
= STATUS_SUCCESS
;
633 PCONSOLE_ALLOCCONSOLE AllocConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.AllocConsoleRequest
;
634 PCSR_PROCESS CsrProcess
= CsrGetClientThread()->Process
;
635 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrProcess
);
637 if (ProcessData
->ConsoleHandle
!= NULL
)
639 DPRINT1("Process already has a console\n");
640 return STATUS_ACCESS_DENIED
;
643 if (!CsrValidateMessageBuffer(ApiMessage
,
644 (PVOID
*)&AllocConsoleRequest
->ConsoleStartInfo
,
646 sizeof(CONSOLE_START_INFO
)))
648 return STATUS_INVALID_PARAMETER
;
651 /* Initialize a new Console owned by the Console Leader Process */
652 Status
= ConSrvAllocateConsole(ProcessData
,
653 &AllocConsoleRequest
->InputHandle
,
654 &AllocConsoleRequest
->OutputHandle
,
655 &AllocConsoleRequest
->ErrorHandle
,
656 AllocConsoleRequest
->ConsoleStartInfo
);
657 if (!NT_SUCCESS(Status
))
659 DPRINT1("Console allocation failed\n");
663 /* Return the console handle and the input wait handle to the caller */
664 AllocConsoleRequest
->ConsoleHandle
= ProcessData
->ConsoleHandle
;
665 AllocConsoleRequest
->InputWaitHandle
= ProcessData
->InputWaitHandle
;
667 /* Set the Property-Dialog and Control-Dispatcher handlers */
668 ProcessData
->PropDispatcher
= AllocConsoleRequest
->PropDispatcher
;
669 ProcessData
->CtrlDispatcher
= AllocConsoleRequest
->CtrlDispatcher
;
671 return STATUS_SUCCESS
;
674 CSR_API(SrvAttachConsole
)
676 NTSTATUS Status
= STATUS_SUCCESS
;
677 PCONSOLE_ATTACHCONSOLE AttachConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.AttachConsoleRequest
;
678 PCSR_PROCESS SourceProcess
= NULL
; // The parent process.
679 PCSR_PROCESS TargetProcess
= CsrGetClientThread()->Process
; // Ourselves.
680 HANDLE ProcessId
= ULongToHandle(AttachConsoleRequest
->ProcessId
);
681 PCONSOLE_PROCESS_DATA SourceProcessData
, TargetProcessData
;
683 TargetProcessData
= ConsoleGetPerProcessData(TargetProcess
);
685 if (TargetProcessData
->ConsoleHandle
!= NULL
)
687 DPRINT1("Process already has a console\n");
688 return STATUS_ACCESS_DENIED
;
691 /* Check whether we try to attach to the parent's console */
692 if (ProcessId
== ULongToHandle(ATTACH_PARENT_PROCESS
))
694 PROCESS_BASIC_INFORMATION ProcessInfo
;
695 ULONG Length
= sizeof(ProcessInfo
);
697 /* Get the real parent's ID */
699 Status
= NtQueryInformationProcess(TargetProcess
->ProcessHandle
,
700 ProcessBasicInformation
,
703 if (!NT_SUCCESS(Status
))
705 DPRINT1("SrvAttachConsole - Cannot retrieve basic process info, Status = %lu\n", Status
);
709 ProcessId
= ULongToHandle(ProcessInfo
.InheritedFromUniqueProcessId
);
712 /* Lock the source process via its PID */
713 Status
= CsrLockProcessByClientId(ProcessId
, &SourceProcess
);
714 if (!NT_SUCCESS(Status
)) return Status
;
716 SourceProcessData
= ConsoleGetPerProcessData(SourceProcess
);
718 if (SourceProcessData
->ConsoleHandle
== NULL
)
720 Status
= STATUS_INVALID_HANDLE
;
725 * Inherit the console from the parent,
726 * if any, otherwise return an error.
728 Status
= ConSrvInheritConsole(TargetProcessData
,
729 SourceProcessData
->ConsoleHandle
,
731 &AttachConsoleRequest
->InputHandle
,
732 &AttachConsoleRequest
->OutputHandle
,
733 &AttachConsoleRequest
->ErrorHandle
);
734 if (!NT_SUCCESS(Status
))
736 DPRINT1("Console inheritance failed\n");
740 /* Return the console handle and the input wait handle to the caller */
741 AttachConsoleRequest
->ConsoleHandle
= TargetProcessData
->ConsoleHandle
;
742 AttachConsoleRequest
->InputWaitHandle
= TargetProcessData
->InputWaitHandle
;
744 /* Set the Property-Dialog and Control-Dispatcher handlers */
745 TargetProcessData
->PropDispatcher
= AttachConsoleRequest
->PropDispatcher
;
746 TargetProcessData
->CtrlDispatcher
= AttachConsoleRequest
->CtrlDispatcher
;
748 Status
= STATUS_SUCCESS
;
751 /* Unlock the "source" process and exit */
752 CsrUnlockProcess(SourceProcess
);
756 CSR_API(SrvFreeConsole
)
758 ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
));
759 return STATUS_SUCCESS
;
763 ConDrvGetConsoleMode(IN PCONSOLE Console
,
764 IN PCONSOLE_IO_OBJECT Object
,
765 OUT PULONG ConsoleMode
);
766 CSR_API(SrvGetConsoleMode
)
769 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleModeRequest
;
770 PCONSOLE_IO_OBJECT Object
;
772 PULONG ConsoleMode
= &ConsoleModeRequest
->Mode
;
774 Status
= ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
775 ConsoleModeRequest
->Handle
,
776 &Object
, NULL
, GENERIC_READ
, TRUE
, 0);
777 if (!NT_SUCCESS(Status
)) return Status
;
779 /* Get the standard console modes */
780 Status
= ConDrvGetConsoleMode(Object
->Console
, Object
,
782 if (NT_SUCCESS(Status
))
785 * If getting the console modes succeeds, then retrieve
786 * the extended CONSRV-specific input modes.
788 if (INPUT_BUFFER
== Object
->Type
)
790 if (Object
->Console
->InsertMode
|| Object
->Console
->QuickEdit
)
792 /* Windows does this, even if it is not documented on MSDN */
793 *ConsoleMode
|= ENABLE_EXTENDED_FLAGS
;
795 if (Object
->Console
->InsertMode
) *ConsoleMode
|= ENABLE_INSERT_MODE
;
796 if (Object
->Console
->QuickEdit
) *ConsoleMode
|= ENABLE_QUICK_EDIT_MODE
;
801 ConSrvReleaseObject(Object
, TRUE
);
806 ConDrvSetConsoleMode(IN PCONSOLE Console
,
807 IN PCONSOLE_IO_OBJECT Object
,
808 IN ULONG ConsoleMode
);
809 CSR_API(SrvSetConsoleMode
)
811 #define CONSOLE_VALID_CONTROL_MODES ( ENABLE_EXTENDED_FLAGS | \
812 ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE )
815 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleModeRequest
;
816 PCONSOLE_IO_OBJECT Object
;
818 ULONG ConsoleMode
= ConsoleModeRequest
->Mode
;
820 Status
= ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
821 ConsoleModeRequest
->Handle
,
822 &Object
, NULL
, GENERIC_WRITE
, TRUE
, 0);
823 if (!NT_SUCCESS(Status
)) return Status
;
825 /* Set the standard console modes (without the CONSRV-specific input modes) */
826 ConsoleMode
&= ~CONSOLE_VALID_CONTROL_MODES
; // Remove CONSRV-specific input modes.
827 Status
= ConDrvSetConsoleMode(Object
->Console
, Object
,
829 if (NT_SUCCESS(Status
))
832 * If setting the console modes succeeds, then set
833 * the extended CONSRV-specific input modes.
835 if (INPUT_BUFFER
== Object
->Type
)
837 ConsoleMode
= ConsoleModeRequest
->Mode
;
839 if (ConsoleMode
& CONSOLE_VALID_CONTROL_MODES
)
842 * If we use control mode flags without ENABLE_EXTENDED_FLAGS,
843 * then consider the flags invalid.
845 if ((ConsoleMode
& ENABLE_EXTENDED_FLAGS
) == 0)
847 Status
= STATUS_INVALID_PARAMETER
;
851 Object
->Console
->InsertMode
= !!(ConsoleMode
& ENABLE_INSERT_MODE
);
852 Object
->Console
->QuickEdit
= !!(ConsoleMode
& ENABLE_QUICK_EDIT_MODE
);
858 ConSrvReleaseObject(Object
, TRUE
);
863 ConDrvGetConsoleTitle(IN PCONSOLE Console
,
865 IN OUT PVOID TitleBuffer
,
866 IN OUT PULONG BufLength
);
867 CSR_API(SrvGetConsoleTitle
)
870 PCONSOLE_GETSETCONSOLETITLE TitleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.TitleRequest
;
871 PCONSRV_CONSOLE Console
;
873 if (!CsrValidateMessageBuffer(ApiMessage
,
874 (PVOID
)&TitleRequest
->Title
,
875 TitleRequest
->Length
,
878 return STATUS_INVALID_PARAMETER
;
881 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
882 if (!NT_SUCCESS(Status
))
884 DPRINT1("Can't get console\n");
888 Status
= ConDrvGetConsoleTitle(Console
,
889 TitleRequest
->Unicode
,
891 &TitleRequest
->Length
);
893 ConSrvReleaseConsole(Console
, TRUE
);
898 ConDrvSetConsoleTitle(IN PCONSOLE Console
,
900 IN PVOID TitleBuffer
,
902 CSR_API(SrvSetConsoleTitle
)
905 PCONSOLE_GETSETCONSOLETITLE TitleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.TitleRequest
;
906 PCONSRV_CONSOLE Console
;
908 if (!CsrValidateMessageBuffer(ApiMessage
,
909 (PVOID
)&TitleRequest
->Title
,
910 TitleRequest
->Length
,
913 return STATUS_INVALID_PARAMETER
;
916 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
917 if (!NT_SUCCESS(Status
))
919 DPRINT1("Can't get console\n");
923 Status
= ConDrvSetConsoleTitle(Console
,
924 TitleRequest
->Unicode
,
926 TitleRequest
->Length
);
927 if (NT_SUCCESS(Status
)) TermChangeTitle(Console
);
929 ConSrvReleaseConsole(Console
, TRUE
);
934 ConDrvGetConsoleCP(IN PCONSOLE Console
,
936 IN BOOLEAN OutputCP
);
937 CSR_API(SrvGetConsoleCP
)
940 PCONSOLE_GETINPUTOUTPUTCP GetConsoleCPRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetConsoleCPRequest
;
941 PCONSRV_CONSOLE Console
;
943 DPRINT("SrvGetConsoleCP, getting %s Code Page\n",
944 GetConsoleCPRequest
->OutputCP
? "Output" : "Input");
946 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
947 if (!NT_SUCCESS(Status
)) return Status
;
949 Status
= ConDrvGetConsoleCP(Console
,
950 &GetConsoleCPRequest
->CodePage
,
951 GetConsoleCPRequest
->OutputCP
);
953 ConSrvReleaseConsole(Console
, TRUE
);
958 ConDrvSetConsoleCP(IN PCONSOLE Console
,
960 IN BOOLEAN OutputCP
);
961 CSR_API(SrvSetConsoleCP
)
963 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
964 PCONSOLE_SETINPUTOUTPUTCP SetConsoleCPRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetConsoleCPRequest
;
965 PCONSRV_CONSOLE Console
;
967 DPRINT("SrvSetConsoleCP, setting %s Code Page\n",
968 SetConsoleCPRequest
->OutputCP
? "Output" : "Input");
970 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
971 if (!NT_SUCCESS(Status
)) return Status
;
973 Status
= ConDrvSetConsoleCP(Console
,
974 SetConsoleCPRequest
->CodePage
,
975 SetConsoleCPRequest
->OutputCP
);
977 ConSrvReleaseConsole(Console
, TRUE
);
981 CSR_API(SrvGetConsoleProcessList
)
984 PCONSOLE_GETPROCESSLIST GetProcessListRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetProcessListRequest
;
985 PCONSRV_CONSOLE Console
;
987 if (!CsrValidateMessageBuffer(ApiMessage
,
988 (PVOID
)&GetProcessListRequest
->ProcessIdsList
,
989 GetProcessListRequest
->ProcessCount
,
992 return STATUS_INVALID_PARAMETER
;
995 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
996 if (!NT_SUCCESS(Status
)) return Status
;
998 Status
= ConSrvGetConsoleProcessList(Console
,
999 GetProcessListRequest
->ProcessIdsList
,
1000 GetProcessListRequest
->ProcessCount
,
1001 &GetProcessListRequest
->ProcessCount
);
1003 ConSrvReleaseConsole(Console
, TRUE
);
1007 CSR_API(SrvGenerateConsoleCtrlEvent
)
1010 PCONSOLE_GENERATECTRLEVENT GenerateCtrlEventRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GenerateCtrlEventRequest
;
1011 PCONSRV_CONSOLE Console
;
1013 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1014 if (!NT_SUCCESS(Status
)) return Status
;
1016 Status
= ConSrvConsoleProcessCtrlEvent(Console
,
1017 GenerateCtrlEventRequest
->ProcessGroupId
,
1018 GenerateCtrlEventRequest
->CtrlEvent
);
1020 ConSrvReleaseConsole(Console
, TRUE
);
1024 CSR_API(SrvConsoleNotifyLastClose
)
1027 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
1028 PCONSRV_CONSOLE Console
;
1030 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
1031 if (!NT_SUCCESS(Status
)) return Status
;
1033 /* Only one process is allowed to be registered for last close notification */
1034 if (!Console
->NotifyLastClose
)
1036 Console
->NotifyLastClose
= TRUE
;
1037 Console
->NotifiedLastCloseProcess
= ProcessData
;
1038 Status
= STATUS_SUCCESS
;
1042 Status
= STATUS_ACCESS_DENIED
;
1045 ConSrvReleaseConsole(Console
, TRUE
);
1051 CSR_API(SrvGetConsoleMouseInfo
)
1054 PCONSOLE_GETMOUSEINFO GetMouseInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetMouseInfoRequest
;
1055 PCONSRV_CONSOLE Console
;
1057 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1058 if (!NT_SUCCESS(Status
)) return Status
;
1060 /* Just retrieve the number of buttons of the mouse attached to this console */
1061 GetMouseInfoRequest
->NumButtons
= GetSystemMetrics(SM_CMOUSEBUTTONS
);
1063 ConSrvReleaseConsole(Console
, TRUE
);
1064 return STATUS_SUCCESS
;
1067 CSR_API(SrvSetConsoleKeyShortcuts
)
1069 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1070 return STATUS_NOT_IMPLEMENTED
;
1073 CSR_API(SrvGetConsoleKeyboardLayoutName
)
1076 PCONSOLE_GETKBDLAYOUTNAME GetKbdLayoutNameRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetKbdLayoutNameRequest
;
1077 PCONSRV_CONSOLE Console
;
1079 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1080 if (!NT_SUCCESS(Status
)) return Status
;
1082 /* Retrieve the keyboard layout name of the system */
1083 if (GetKbdLayoutNameRequest
->Ansi
)
1084 GetKeyboardLayoutNameA((PCHAR
)GetKbdLayoutNameRequest
->LayoutBuffer
);
1086 GetKeyboardLayoutNameW((PWCHAR
)GetKbdLayoutNameRequest
->LayoutBuffer
);
1088 ConSrvReleaseConsole(Console
, TRUE
);
1089 return STATUS_SUCCESS
;
1092 CSR_API(SrvGetConsoleCharType
)
1094 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1095 return STATUS_NOT_IMPLEMENTED
;
1098 CSR_API(SrvSetConsoleLocalEUDC
)
1100 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1101 return STATUS_NOT_IMPLEMENTED
;
1104 CSR_API(SrvSetConsoleCursorMode
)
1106 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1107 return STATUS_NOT_IMPLEMENTED
;
1110 CSR_API(SrvGetConsoleCursorMode
)
1112 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1113 return STATUS_NOT_IMPLEMENTED
;
1116 CSR_API(SrvGetConsoleNlsMode
)
1118 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1119 return STATUS_NOT_IMPLEMENTED
;
1122 CSR_API(SrvSetConsoleNlsMode
)
1124 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1125 return STATUS_NOT_IMPLEMENTED
;
1128 CSR_API(SrvGetConsoleLangId
)
1130 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1131 return STATUS_NOT_IMPLEMENTED
;