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 /* The list of the ConSrv consoles */
30 static ULONG ConsoleListSize
;
31 static PCONSRV_CONSOLE
* ConsoleList
;
32 static RTL_RESOURCE ListLock
;
34 #define ConSrvLockConsoleListExclusive() \
35 RtlAcquireResourceExclusive(&ListLock, TRUE)
37 #define ConSrvLockConsoleListShared() \
38 RtlAcquireResourceShared(&ListLock, TRUE)
40 #define ConSrvUnlockConsoleList() \
41 RtlReleaseResource(&ListLock)
45 InsertConsole(OUT PHANDLE Handle
,
46 IN PCONSRV_CONSOLE Console
)
48 #define CONSOLE_HANDLES_INCREMENT 2 * 3
50 NTSTATUS Status
= STATUS_SUCCESS
;
52 PCONSRV_CONSOLE
* Block
;
54 ASSERT( (ConsoleList
== NULL
&& ConsoleListSize
== 0) ||
55 (ConsoleList
!= NULL
&& ConsoleListSize
!= 0) );
57 /* All went right, so add the console to the list */
58 ConSrvLockConsoleListExclusive();
59 DPRINT1("Insert in the list\n");
63 for (i
= 0; i
< ConsoleListSize
; i
++)
65 if (ConsoleList
[i
] == NULL
) break;
69 if (i
>= ConsoleListSize
)
71 DPRINT1("Creation of a new handles table\n");
72 /* Allocate a new handles table */
73 Block
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
,
75 CONSOLE_HANDLES_INCREMENT
) * sizeof(PCONSRV_CONSOLE
));
78 Status
= STATUS_UNSUCCESSFUL
;
82 /* If we previously had a handles table, free it and use the new one */
85 /* Copy the handles from the old table to the new one */
88 ConsoleListSize
* sizeof(PCONSRV_CONSOLE
));
89 ConsoleFreeHeap(ConsoleList
);
92 ConsoleListSize
+= CONSOLE_HANDLES_INCREMENT
;
95 ConsoleList
[i
] = Console
;
96 *Handle
= ULongToHandle((i
<< 2) | 0x3);
99 /* Unlock the console list and return status */
100 ConSrvUnlockConsoleList();
107 RemoveConsoleByHandle(IN HANDLE Handle
)
109 NTSTATUS Status
= STATUS_SUCCESS
;
110 PCONSRV_CONSOLE Console
;
112 BOOLEAN ValidHandle
= ((HandleToULong(Handle
) & 0x3) == 0x3);
113 ULONG Index
= HandleToULong(Handle
) >> 2;
115 if (!ValidHandle
) return STATUS_INVALID_HANDLE
;
117 ASSERT( (ConsoleList
== NULL
&& ConsoleListSize
== 0) ||
118 (ConsoleList
!= NULL
&& ConsoleListSize
!= 0) );
120 /* Remove the console from the list */
121 ConSrvLockConsoleListExclusive();
123 if (Index
>= ConsoleListSize
||
124 (Console
= ConsoleList
[Index
]) == NULL
)
126 Status
= STATUS_INVALID_HANDLE
;
130 ConsoleList
[Index
] = NULL
;
133 /* Unlock the console list and return status */
134 ConSrvUnlockConsoleList();
140 RemoveConsoleByPointer(IN PCONSRV_CONSOLE Console
)
144 if (!Console
) return STATUS_INVALID_PARAMETER
;
146 ASSERT( (ConsoleList
== NULL
&& ConsoleListSize
== 0) ||
147 (ConsoleList
!= NULL
&& ConsoleListSize
!= 0) );
149 /* Remove the console from the list */
150 ConSrvLockConsoleListExclusive();
154 for (i
= 0; i
< ConsoleListSize
; i
++)
156 if (ConsoleList
[i
] == Console
) ConsoleList
[i
] = NULL
;
160 /* Unlock the console list and return */
161 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 and return */
192 ConSrvUnlockConsoleList();
196 ValidatedConsole
= ConsoleList
[Index
];
198 /* Unlock the console list and return */
199 ConSrvUnlockConsoleList();
201 RetVal
= ConDrvValidateConsoleUnsafe((PCONSOLE
)ValidatedConsole
,
204 if (RetVal
) *Console
= ValidatedConsole
;
210 /* PRIVATE FUNCTIONS **********************************************************/
213 ConioPause(PCONSRV_CONSOLE Console
, UINT Flags
)
215 Console
->PauseFlags
|= Flags
;
216 ConDrvPause((PCONSOLE
)Console
);
220 ConioUnpause(PCONSRV_CONSOLE Console
, UINT Flags
)
222 Console
->PauseFlags
&= ~Flags
;
224 // if ((Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION)) == 0)
225 if (Console
->PauseFlags
== 0)
227 ConDrvUnpause((PCONSOLE
)Console
);
229 CsrNotifyWait(&Console
->WriteWaitQueue
,
233 if (!IsListEmpty(&Console
->WriteWaitQueue
))
235 CsrDereferenceWait(&Console
->WriteWaitQueue
);
241 ConSrvGetConsole(IN PCONSOLE_PROCESS_DATA ProcessData
,
242 OUT PCONSRV_CONSOLE
* Console
,
243 IN BOOLEAN LockConsole
)
245 NTSTATUS Status
= STATUS_INVALID_HANDLE
;
246 PCONSRV_CONSOLE GrabConsole
;
248 // if (Console == NULL) return STATUS_INVALID_PARAMETER;
252 // RtlEnterCriticalSection(&ProcessData->HandleTableLock);
254 if (ConSrvValidateConsole(&GrabConsole
,
255 ProcessData
->ConsoleHandle
,
259 InterlockedIncrement(&GrabConsole
->ReferenceCount
);
260 *Console
= GrabConsole
;
261 Status
= STATUS_SUCCESS
;
264 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
269 ConSrvReleaseConsole(IN PCONSRV_CONSOLE Console
,
270 IN BOOLEAN WasConsoleLocked
)
274 if (!Console
) return;
275 // if (Console->ReferenceCount == 0) return; // This shouldn't happen
276 ASSERT(Console
->ReferenceCount
> 0);
278 /* The console must be locked */
279 // ASSERT(Console_locked);
282 * Decrement the reference count. Save the new value too,
283 * because Console->ReferenceCount might be modified after
284 * the console gets unlocked but before we check whether we
287 RefCount
= _InterlockedDecrement(&Console
->ReferenceCount
);
289 /* Unlock the console if needed */
290 if (WasConsoleLocked
) LeaveCriticalSection(&Console
->Lock
);
292 /* Delete the console if needed */
293 if (RefCount
<= 0) ConSrvDeleteConsole(Console
);
297 /* CONSOLE INITIALIZATION FUNCTIONS *******************************************/
300 ConSrvInitConsoleSupport(VOID
)
302 DPRINT("CONSRV: ConSrvInitConsoleSupport()\n");
304 /* Initialize the console list and its lock */
307 RtlInitializeResource(&ListLock
);
309 /* Should call LoadKeyboardLayout */
313 ConSrvInitTerminal(IN OUT PTERMINAL Terminal
,
314 IN OUT PCONSOLE_INFO ConsoleInfo
,
315 IN OUT PVOID ExtraConsoleInfo
,
318 ConSrvDeinitTerminal(IN OUT PTERMINAL Terminal
);
321 ConSrvInitConsole(OUT PHANDLE NewConsoleHandle
,
322 OUT PCONSRV_CONSOLE
* NewConsole
,
323 IN OUT PCONSOLE_START_INFO ConsoleStartInfo
,
324 IN ULONG ConsoleLeaderProcessId
)
327 HANDLE ConsoleHandle
;
328 PCONSRV_CONSOLE Console
;
329 CONSOLE_INFO ConsoleInfo
;
332 TERMINAL Terminal
; /* The ConSrv terminal for this console */
334 if (NewConsole
== NULL
|| ConsoleStartInfo
== NULL
)
335 return STATUS_INVALID_PARAMETER
;
340 * Load the console settings
343 /* 1. Load the default settings */
344 ConSrvGetDefaultSettings(&ConsoleInfo
, ConsoleLeaderProcessId
);
346 /* 2. Get the title of the console (initialize ConsoleInfo.ConsoleTitle) */
347 Length
= min(wcslen(ConsoleStartInfo
->ConsoleTitle
),
348 sizeof(ConsoleInfo
.ConsoleTitle
) / sizeof(ConsoleInfo
.ConsoleTitle
[0]) - 1);
349 wcsncpy(ConsoleInfo
.ConsoleTitle
, ConsoleStartInfo
->ConsoleTitle
, Length
);
350 ConsoleInfo
.ConsoleTitle
[Length
] = L
'\0';
352 /* 3. Initialize the ConSrv terminal */
353 Status
= ConSrvInitTerminal(&Terminal
,
356 ConsoleLeaderProcessId
);
357 if (!NT_SUCCESS(Status
))
359 DPRINT1("CONSRV: Failed to initialize a terminal, Status = 0x%08lx\n", Status
);
362 DPRINT("CONSRV: Terminal initialized\n");
365 * 4. Load the remaining console settings via the registry.
367 if ((ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
370 * Either we weren't created by an app launched via a shell-link,
371 * or we failed to load shell-link console properties.
372 * Therefore, load the console infos for the application from the registry.
374 ConSrvReadUserSettings(&ConsoleInfo
, ConsoleLeaderProcessId
);
377 * Now, update them with the properties the user might gave to us
378 * via the STARTUPINFO structure before calling CreateProcess
379 * (and which was transmitted via the ConsoleStartInfo structure).
380 * We therefore overwrite the values read in the registry.
382 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USEFILLATTRIBUTE
)
384 ConsoleInfo
.ScreenAttrib
= (USHORT
)ConsoleStartInfo
->wFillAttribute
;
386 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USECOUNTCHARS
)
388 ConsoleInfo
.ScreenBufferSize
= ConsoleStartInfo
->dwScreenBufferSize
;
390 if (ConsoleStartInfo
->dwStartupFlags
& STARTF_USESIZE
)
392 ConsoleInfo
.ConsoleSize
= ConsoleStartInfo
->dwWindowSize
;
396 /* Set-up the code page */
397 ConsoleInfo
.CodePage
= GetOEMCP();
399 /* Initialize a new console via the driver */
400 Status
= ConDrvInitConsole(&Console
, &ConsoleInfo
);
401 if (!NT_SUCCESS(Status
))
403 DPRINT1("Creating a new console failed, Status = 0x%08lx\n", Status
);
404 ConSrvDeinitTerminal(&Terminal
);
409 DPRINT("Console initialized\n");
411 /*** Register ConSrv features ***/
413 /* Initialize process support */
414 InitializeListHead(&Console
->ProcessList
);
415 Console
->NotifiedLastCloseProcess
= NULL
;
416 Console
->NotifyLastClose
= FALSE
;
418 /* Initialize pausing support */
419 Console
->PauseFlags
= 0;
420 InitializeListHead(&Console
->ReadWaitQueue
);
421 InitializeListHead(&Console
->WriteWaitQueue
);
423 /* Initialize the alias and history buffers */
424 Console
->Aliases
= NULL
;
425 InitializeListHead(&Console
->HistoryBuffers
);
426 Console
->HistoryBufferSize
= ConsoleInfo
.HistoryBufferSize
;
427 Console
->NumberOfHistoryBuffers
= ConsoleInfo
.NumberOfHistoryBuffers
;
428 Console
->HistoryNoDup
= ConsoleInfo
.HistoryNoDup
;
430 /* Initialize the Input Line Discipline */
431 Console
->LineBuffer
= NULL
;
432 Console
->LinePos
= Console
->LineMaxSize
= Console
->LineSize
= 0;
433 Console
->LineComplete
= Console
->LineUpPressed
= FALSE
;
435 Console
->LineInsertToggle
=
436 Console
->InsertMode
= ConsoleInfo
.InsertMode
;
437 Console
->QuickEdit
= ConsoleInfo
.QuickEdit
;
440 InitializeListHead(&Console
->PopupWindows
);
443 memcpy(Console
->Colors
, ConsoleInfo
.Colors
, sizeof(ConsoleInfo
.Colors
));
446 * Attach the ConSrv terminal to the console.
447 * This call makes a copy of our local Terminal variable.
449 Status
= ConDrvRegisterTerminal(Console
, &Terminal
);
450 if (!NT_SUCCESS(Status
))
452 DPRINT1("Failed to register terminal to the given console, Status = 0x%08lx\n", Status
);
453 ConDrvDeleteConsole(Console
);
454 ConSrvDeinitTerminal(&Terminal
);
457 DPRINT("Terminal registered\n");
459 /* All went right, so add the console to the list */
460 Status
= InsertConsole(&ConsoleHandle
, Console
);
462 /* Return the newly created console to the caller and a success code too */
463 *NewConsoleHandle
= ConsoleHandle
;
464 *NewConsole
= Console
;
465 return STATUS_SUCCESS
;
469 ConSrvDeleteConsole(PCONSRV_CONSOLE Console
)
471 DPRINT("ConSrvDeleteConsole\n");
473 // FIXME: Send a terminate message to all the processes owning this console
475 /* Remove the console from the list */
476 RemoveConsoleByPointer(Console
);
478 /* Clean the Input Line Discipline */
479 if (Console
->LineBuffer
) ConsoleFreeHeap(Console
->LineBuffer
);
481 /* Clean aliases and history */
482 IntDeleteAllAliases(Console
);
483 HistoryDeleteBuffers(Console
);
485 /* Now, call the driver. ConDrvDeregisterTerminal is called on-demand. */
486 ConDrvDeleteConsole((PCONSOLE
)Console
);
488 /* Deinit the ConSrv terminal */
490 // ConSrvDeinitTerminal(&Terminal); // &ConSrvConsole->Console->TermIFace
499 ConSrvConsoleCtrlEventTimeout(IN ULONG CtrlEvent
,
500 IN PCONSOLE_PROCESS_DATA ProcessData
,
503 NTSTATUS Status
= STATUS_SUCCESS
;
505 DPRINT("ConSrvConsoleCtrlEventTimeout Parent ProcessId = %x\n", ProcessData
->Process
->ClientId
.UniqueProcess
);
507 if (ProcessData
->CtrlDispatcher
)
511 HANDLE Thread
= NULL
;
515 Thread
= CreateRemoteThread(ProcessData
->Process
->ProcessHandle
, NULL
, 0,
516 ProcessData
->CtrlDispatcher
,
517 UlongToPtr(CtrlEvent
), 0, NULL
);
520 Status
= RtlGetLastNtStatus();
521 DPRINT1("Failed thread creation, Status = 0x%08lx\n", Status
);
525 DPRINT("ProcessData->CtrlDispatcher remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n", ProcessData
->Process
->ClientId
.UniqueProcess
, ProcessData
->Process
);
526 WaitForSingleObject(Thread
, Timeout
);
535 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
537 Status
= _SEH2_GetExceptionCode();
538 DPRINT1("ConSrvConsoleCtrlEventTimeout - Caught an exception, Status = 0x%08lx\n", Status
);
547 ConSrvConsoleCtrlEvent(IN ULONG CtrlEvent
,
548 IN PCONSOLE_PROCESS_DATA ProcessData
)
550 return ConSrvConsoleCtrlEventTimeout(CtrlEvent
, ProcessData
, 0);
553 PCONSOLE_PROCESS_DATA NTAPI
554 ConSrvGetConsoleLeaderProcess(IN PCONSRV_CONSOLE Console
)
556 if (Console
== NULL
) return NULL
;
558 return CONTAINING_RECORD(Console
->ProcessList
.Blink
,
559 CONSOLE_PROCESS_DATA
,
564 ConSrvGetConsoleProcessList(IN PCONSRV_CONSOLE Console
,
565 IN OUT PULONG ProcessIdsList
,
566 IN ULONG MaxIdListItems
,
567 OUT PULONG ProcessIdsTotal
)
569 PCONSOLE_PROCESS_DATA current
;
570 PLIST_ENTRY current_entry
;
572 if (Console
== NULL
|| ProcessIdsList
== NULL
|| ProcessIdsTotal
== NULL
)
573 return STATUS_INVALID_PARAMETER
;
575 *ProcessIdsTotal
= 0;
577 for (current_entry
= Console
->ProcessList
.Flink
;
578 current_entry
!= &Console
->ProcessList
;
579 current_entry
= current_entry
->Flink
)
581 current
= CONTAINING_RECORD(current_entry
, CONSOLE_PROCESS_DATA
, ConsoleLink
);
582 if (++(*ProcessIdsTotal
) <= MaxIdListItems
)
584 *ProcessIdsList
++ = HandleToUlong(current
->Process
->ClientId
.UniqueProcess
);
588 return STATUS_SUCCESS
;
591 // ConSrvGenerateConsoleCtrlEvent
593 ConSrvConsoleProcessCtrlEvent(IN PCONSRV_CONSOLE Console
,
594 IN ULONG ProcessGroupId
,
597 NTSTATUS Status
= STATUS_SUCCESS
;
598 PLIST_ENTRY current_entry
;
599 PCONSOLE_PROCESS_DATA current
;
601 /* If the console is already being destroyed, just return */
602 if (!ConDrvValidateConsoleState((PCONSOLE
)Console
, CONSOLE_RUNNING
))
603 return STATUS_UNSUCCESSFUL
;
606 * Loop through the process list, from the most recent process
607 * (the active one) to the oldest one (the first created, i.e.
608 * the console leader process), and for each, send an event
609 * (new processes are inserted at the head of the console process list).
611 current_entry
= Console
->ProcessList
.Flink
;
612 while (current_entry
!= &Console
->ProcessList
)
614 current
= CONTAINING_RECORD(current_entry
, CONSOLE_PROCESS_DATA
, ConsoleLink
);
615 current_entry
= current_entry
->Flink
;
618 * Only processes belonging to the same process group are signaled.
619 * If the process group ID is zero, then all the processes are signaled.
621 if (ProcessGroupId
== 0 || current
->Process
->ProcessGroupId
== ProcessGroupId
)
623 Status
= ConSrvConsoleCtrlEvent(CtrlEvent
, current
);
634 /* PUBLIC SERVER APIS *********************************************************/
636 CSR_API(SrvAllocConsole
)
638 NTSTATUS Status
= STATUS_SUCCESS
;
639 PCONSOLE_ALLOCCONSOLE AllocConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.AllocConsoleRequest
;
640 PCSR_PROCESS CsrProcess
= CsrGetClientThread()->Process
;
641 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrProcess
);
643 if (ProcessData
->ConsoleHandle
!= NULL
)
645 DPRINT1("Process already has a console\n");
646 return STATUS_ACCESS_DENIED
;
649 if (!CsrValidateMessageBuffer(ApiMessage
,
650 (PVOID
*)&AllocConsoleRequest
->ConsoleStartInfo
,
652 sizeof(CONSOLE_START_INFO
)))
654 return STATUS_INVALID_PARAMETER
;
657 /* Initialize a new Console owned by the Console Leader Process */
658 Status
= ConSrvAllocateConsole(ProcessData
,
659 &AllocConsoleRequest
->InputHandle
,
660 &AllocConsoleRequest
->OutputHandle
,
661 &AllocConsoleRequest
->ErrorHandle
,
662 AllocConsoleRequest
->ConsoleStartInfo
);
663 if (!NT_SUCCESS(Status
))
665 DPRINT1("Console allocation failed\n");
669 /* Return the console handle and the input wait handle to the caller */
670 AllocConsoleRequest
->ConsoleHandle
= ProcessData
->ConsoleHandle
;
671 AllocConsoleRequest
->InputWaitHandle
= ProcessData
->InputWaitHandle
;
673 /* Set the Property-Dialog and Control-Dispatcher handlers */
674 ProcessData
->PropDispatcher
= AllocConsoleRequest
->PropDispatcher
;
675 ProcessData
->CtrlDispatcher
= AllocConsoleRequest
->CtrlDispatcher
;
677 return STATUS_SUCCESS
;
680 CSR_API(SrvAttachConsole
)
682 NTSTATUS Status
= STATUS_SUCCESS
;
683 PCONSOLE_ATTACHCONSOLE AttachConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.AttachConsoleRequest
;
684 PCSR_PROCESS SourceProcess
= NULL
; // The parent process.
685 PCSR_PROCESS TargetProcess
= CsrGetClientThread()->Process
; // Ourselves.
686 HANDLE ProcessId
= ULongToHandle(AttachConsoleRequest
->ProcessId
);
687 PCONSOLE_PROCESS_DATA SourceProcessData
, TargetProcessData
;
689 TargetProcessData
= ConsoleGetPerProcessData(TargetProcess
);
691 if (TargetProcessData
->ConsoleHandle
!= NULL
)
693 DPRINT1("Process already has a console\n");
694 return STATUS_ACCESS_DENIED
;
697 /* Check whether we try to attach to the parent's console */
698 if (ProcessId
== ULongToHandle(ATTACH_PARENT_PROCESS
))
700 PROCESS_BASIC_INFORMATION ProcessInfo
;
701 ULONG Length
= sizeof(ProcessInfo
);
703 /* Get the real parent's ID */
705 Status
= NtQueryInformationProcess(TargetProcess
->ProcessHandle
,
706 ProcessBasicInformation
,
709 if (!NT_SUCCESS(Status
))
711 DPRINT1("SrvAttachConsole - Cannot retrieve basic process info, Status = %lu\n", Status
);
715 ProcessId
= ULongToHandle(ProcessInfo
.InheritedFromUniqueProcessId
);
718 /* Lock the source process via its PID */
719 Status
= CsrLockProcessByClientId(ProcessId
, &SourceProcess
);
720 if (!NT_SUCCESS(Status
)) return Status
;
722 SourceProcessData
= ConsoleGetPerProcessData(SourceProcess
);
724 if (SourceProcessData
->ConsoleHandle
== NULL
)
726 Status
= STATUS_INVALID_HANDLE
;
731 * Inherit the console from the parent,
732 * if any, otherwise return an error.
734 Status
= ConSrvInheritConsole(TargetProcessData
,
735 SourceProcessData
->ConsoleHandle
,
737 &AttachConsoleRequest
->InputHandle
,
738 &AttachConsoleRequest
->OutputHandle
,
739 &AttachConsoleRequest
->ErrorHandle
);
740 if (!NT_SUCCESS(Status
))
742 DPRINT1("Console inheritance failed\n");
746 /* Return the console handle and the input wait handle to the caller */
747 AttachConsoleRequest
->ConsoleHandle
= TargetProcessData
->ConsoleHandle
;
748 AttachConsoleRequest
->InputWaitHandle
= TargetProcessData
->InputWaitHandle
;
750 /* Set the Property-Dialog and Control-Dispatcher handlers */
751 TargetProcessData
->PropDispatcher
= AttachConsoleRequest
->PropDispatcher
;
752 TargetProcessData
->CtrlDispatcher
= AttachConsoleRequest
->CtrlDispatcher
;
754 Status
= STATUS_SUCCESS
;
757 /* Unlock the "source" process and exit */
758 CsrUnlockProcess(SourceProcess
);
762 CSR_API(SrvFreeConsole
)
764 ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
));
765 return STATUS_SUCCESS
;
769 ConDrvGetConsoleMode(IN PCONSOLE Console
,
770 IN PCONSOLE_IO_OBJECT Object
,
771 OUT PULONG ConsoleMode
);
772 CSR_API(SrvGetConsoleMode
)
775 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleModeRequest
;
776 PCONSOLE_IO_OBJECT Object
;
778 PULONG ConsoleMode
= &ConsoleModeRequest
->Mode
;
780 Status
= ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
781 ConsoleModeRequest
->Handle
,
782 &Object
, NULL
, GENERIC_READ
, TRUE
, 0);
783 if (!NT_SUCCESS(Status
)) return Status
;
785 /* Get the standard console modes */
786 Status
= ConDrvGetConsoleMode(Object
->Console
, Object
,
788 if (NT_SUCCESS(Status
))
791 * If getting the console modes succeeds, then retrieve
792 * the extended CONSRV-specific input modes.
794 if (INPUT_BUFFER
== Object
->Type
)
796 if (Object
->Console
->InsertMode
|| Object
->Console
->QuickEdit
)
798 /* Windows also adds ENABLE_EXTENDED_FLAGS, even if it's not documented on MSDN */
799 *ConsoleMode
|= ENABLE_EXTENDED_FLAGS
;
801 if (Object
->Console
->InsertMode
) *ConsoleMode
|= ENABLE_INSERT_MODE
;
802 if (Object
->Console
->QuickEdit
) *ConsoleMode
|= ENABLE_QUICK_EDIT_MODE
;
807 ConSrvReleaseObject(Object
, TRUE
);
812 ConDrvSetConsoleMode(IN PCONSOLE Console
,
813 IN PCONSOLE_IO_OBJECT Object
,
814 IN ULONG ConsoleMode
);
815 CSR_API(SrvSetConsoleMode
)
817 #define CONSOLE_VALID_CONTROL_MODES ( ENABLE_EXTENDED_FLAGS | \
818 ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE )
821 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleModeRequest
;
822 PCONSOLE_IO_OBJECT Object
;
824 ULONG ConsoleMode
= ConsoleModeRequest
->Mode
;
826 Status
= ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
827 ConsoleModeRequest
->Handle
,
828 &Object
, NULL
, GENERIC_WRITE
, TRUE
, 0);
829 if (!NT_SUCCESS(Status
)) return Status
;
831 /* Set the standard console modes (without the CONSRV-specific input modes) */
832 ConsoleMode
&= ~CONSOLE_VALID_CONTROL_MODES
; // Remove CONSRV-specific input modes.
833 Status
= ConDrvSetConsoleMode(Object
->Console
, Object
,
835 if (NT_SUCCESS(Status
))
838 * If setting the console modes succeeds, then set
839 * the extended CONSRV-specific input modes.
841 if (INPUT_BUFFER
== Object
->Type
)
843 ConsoleMode
= ConsoleModeRequest
->Mode
;
845 if (ConsoleMode
& CONSOLE_VALID_CONTROL_MODES
)
848 * If we use control mode flags without ENABLE_EXTENDED_FLAGS,
849 * then consider the flags invalid.
851 if ((ConsoleMode
& ENABLE_EXTENDED_FLAGS
) == 0)
853 Status
= STATUS_INVALID_PARAMETER
;
857 Object
->Console
->InsertMode
= !!(ConsoleMode
& ENABLE_INSERT_MODE
);
858 Object
->Console
->QuickEdit
= !!(ConsoleMode
& ENABLE_QUICK_EDIT_MODE
);
864 ConSrvReleaseObject(Object
, TRUE
);
869 ConDrvGetConsoleTitle(IN PCONSOLE Console
,
871 IN OUT PVOID TitleBuffer
,
872 IN OUT PULONG BufLength
);
873 CSR_API(SrvGetConsoleTitle
)
876 PCONSOLE_GETSETCONSOLETITLE TitleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.TitleRequest
;
877 PCONSRV_CONSOLE Console
;
879 if (!CsrValidateMessageBuffer(ApiMessage
,
880 (PVOID
)&TitleRequest
->Title
,
881 TitleRequest
->Length
,
884 return STATUS_INVALID_PARAMETER
;
887 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
888 if (!NT_SUCCESS(Status
))
890 DPRINT1("Can't get console\n");
894 Status
= ConDrvGetConsoleTitle(Console
,
895 TitleRequest
->Unicode
,
897 &TitleRequest
->Length
);
899 ConSrvReleaseConsole(Console
, TRUE
);
904 ConDrvSetConsoleTitle(IN PCONSOLE Console
,
906 IN PVOID TitleBuffer
,
908 CSR_API(SrvSetConsoleTitle
)
911 PCONSOLE_GETSETCONSOLETITLE TitleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.TitleRequest
;
912 PCONSRV_CONSOLE Console
;
914 if (!CsrValidateMessageBuffer(ApiMessage
,
915 (PVOID
)&TitleRequest
->Title
,
916 TitleRequest
->Length
,
919 return STATUS_INVALID_PARAMETER
;
922 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
923 if (!NT_SUCCESS(Status
))
925 DPRINT1("Can't get console\n");
929 Status
= ConDrvSetConsoleTitle(Console
,
930 TitleRequest
->Unicode
,
932 TitleRequest
->Length
);
933 // FIXME: Keep this call here, or put it in ConDrvSetConsoleTitle ??
934 if (NT_SUCCESS(Status
)) TermChangeTitle(Console
);
936 ConSrvReleaseConsole(Console
, TRUE
);
941 ConDrvGetConsoleCP(IN PCONSOLE Console
,
943 IN BOOLEAN OutputCP
);
944 CSR_API(SrvGetConsoleCP
)
947 PCONSOLE_GETINPUTOUTPUTCP GetConsoleCPRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetConsoleCPRequest
;
948 PCONSRV_CONSOLE Console
;
950 DPRINT("SrvGetConsoleCP, getting %s Code Page\n",
951 GetConsoleCPRequest
->OutputCP
? "Output" : "Input");
953 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
954 if (!NT_SUCCESS(Status
)) return Status
;
956 Status
= ConDrvGetConsoleCP(Console
,
957 &GetConsoleCPRequest
->CodePage
,
958 GetConsoleCPRequest
->OutputCP
);
960 ConSrvReleaseConsole(Console
, TRUE
);
965 ConDrvSetConsoleCP(IN PCONSOLE Console
,
967 IN BOOLEAN OutputCP
);
968 CSR_API(SrvSetConsoleCP
)
970 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
971 PCONSOLE_SETINPUTOUTPUTCP SetConsoleCPRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetConsoleCPRequest
;
972 PCONSRV_CONSOLE Console
;
974 DPRINT("SrvSetConsoleCP, setting %s Code Page\n",
975 SetConsoleCPRequest
->OutputCP
? "Output" : "Input");
977 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
978 if (!NT_SUCCESS(Status
)) return Status
;
980 Status
= ConDrvSetConsoleCP(Console
,
981 SetConsoleCPRequest
->CodePage
,
982 SetConsoleCPRequest
->OutputCP
);
984 ConSrvReleaseConsole(Console
, TRUE
);
988 CSR_API(SrvGetConsoleProcessList
)
991 PCONSOLE_GETPROCESSLIST GetProcessListRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetProcessListRequest
;
992 PCONSRV_CONSOLE Console
;
994 if (!CsrValidateMessageBuffer(ApiMessage
,
995 (PVOID
)&GetProcessListRequest
->ProcessIdsList
,
996 GetProcessListRequest
->ProcessCount
,
999 return STATUS_INVALID_PARAMETER
;
1002 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1003 if (!NT_SUCCESS(Status
)) return Status
;
1005 Status
= ConSrvGetConsoleProcessList(Console
,
1006 GetProcessListRequest
->ProcessIdsList
,
1007 GetProcessListRequest
->ProcessCount
,
1008 &GetProcessListRequest
->ProcessCount
);
1010 ConSrvReleaseConsole(Console
, TRUE
);
1014 CSR_API(SrvGenerateConsoleCtrlEvent
)
1017 PCONSOLE_GENERATECTRLEVENT GenerateCtrlEventRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GenerateCtrlEventRequest
;
1018 PCONSRV_CONSOLE Console
;
1020 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1021 if (!NT_SUCCESS(Status
)) return Status
;
1023 Status
= ConSrvConsoleProcessCtrlEvent(Console
,
1024 GenerateCtrlEventRequest
->ProcessGroupId
,
1025 GenerateCtrlEventRequest
->CtrlEvent
);
1027 ConSrvReleaseConsole(Console
, TRUE
);
1031 CSR_API(SrvConsoleNotifyLastClose
)
1034 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
1035 PCONSRV_CONSOLE Console
;
1037 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
1038 if (!NT_SUCCESS(Status
)) return Status
;
1040 /* Only one process is allowed to be registered for last close notification */
1041 if (!Console
->NotifyLastClose
)
1043 Console
->NotifyLastClose
= TRUE
;
1044 Console
->NotifiedLastCloseProcess
= ProcessData
;
1045 Status
= STATUS_SUCCESS
;
1049 Status
= STATUS_ACCESS_DENIED
;
1052 ConSrvReleaseConsole(Console
, TRUE
);
1058 CSR_API(SrvGetConsoleMouseInfo
)
1061 PCONSOLE_GETMOUSEINFO GetMouseInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetMouseInfoRequest
;
1062 PCONSRV_CONSOLE Console
;
1064 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1065 if (!NT_SUCCESS(Status
)) return Status
;
1067 /* Just retrieve the number of buttons of the mouse attached to this console */
1068 GetMouseInfoRequest
->NumButtons
= GetSystemMetrics(SM_CMOUSEBUTTONS
);
1070 ConSrvReleaseConsole(Console
, TRUE
);
1071 return STATUS_SUCCESS
;
1074 CSR_API(SrvSetConsoleKeyShortcuts
)
1076 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1077 return STATUS_NOT_IMPLEMENTED
;
1080 CSR_API(SrvGetConsoleKeyboardLayoutName
)
1083 PCONSOLE_GETKBDLAYOUTNAME GetKbdLayoutNameRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetKbdLayoutNameRequest
;
1084 PCONSRV_CONSOLE Console
;
1086 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1087 if (!NT_SUCCESS(Status
)) return Status
;
1089 /* Retrieve the keyboard layout name of the system */
1090 if (GetKbdLayoutNameRequest
->Ansi
)
1091 GetKeyboardLayoutNameA((PCHAR
)GetKbdLayoutNameRequest
->LayoutBuffer
);
1093 GetKeyboardLayoutNameW((PWCHAR
)GetKbdLayoutNameRequest
->LayoutBuffer
);
1095 ConSrvReleaseConsole(Console
, TRUE
);
1096 return STATUS_SUCCESS
;
1099 CSR_API(SrvGetConsoleCharType
)
1101 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1102 return STATUS_NOT_IMPLEMENTED
;
1105 CSR_API(SrvSetConsoleLocalEUDC
)
1107 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1108 return STATUS_NOT_IMPLEMENTED
;
1111 CSR_API(SrvSetConsoleCursorMode
)
1113 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1114 return STATUS_NOT_IMPLEMENTED
;
1117 CSR_API(SrvGetConsoleCursorMode
)
1119 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1120 return STATUS_NOT_IMPLEMENTED
;
1123 CSR_API(SrvGetConsoleNlsMode
)
1125 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1126 return STATUS_NOT_IMPLEMENTED
;
1129 CSR_API(SrvSetConsoleNlsMode
)
1131 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1132 return STATUS_NOT_IMPLEMENTED
;
1135 CSR_API(SrvGetConsoleLangId
)
1137 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1138 return STATUS_NOT_IMPLEMENTED
;