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>
17 /* This is for COM usage */
29 // FIXME: Add this prototype to winternl.h / rtlfuncs.h / ...
30 NTSTATUS NTAPI
RtlGetLastNtStatus(VOID
);
32 /* GLOBALS ********************************************************************/
34 /* The list of the ConSrv consoles */
35 static ULONG ConsoleListSize
;
36 static PCONSRV_CONSOLE
* ConsoleList
;
37 static RTL_RESOURCE ListLock
;
39 #define ConSrvLockConsoleListExclusive() \
40 RtlAcquireResourceExclusive(&ListLock, TRUE)
42 #define ConSrvLockConsoleListShared() \
43 RtlAcquireResourceShared(&ListLock, TRUE)
45 #define ConSrvUnlockConsoleList() \
46 RtlReleaseResource(&ListLock)
50 InsertConsole(OUT PHANDLE Handle
,
51 IN PCONSRV_CONSOLE Console
)
53 #define CONSOLE_HANDLES_INCREMENT 2 * 3
55 NTSTATUS Status
= STATUS_SUCCESS
;
57 PCONSRV_CONSOLE
* Block
;
59 ASSERT( (ConsoleList
== NULL
&& ConsoleListSize
== 0) ||
60 (ConsoleList
!= NULL
&& ConsoleListSize
!= 0) );
62 /* All went right, so add the console to the list */
63 ConSrvLockConsoleListExclusive();
64 DPRINT("Insert in the list\n");
68 for (i
= 0; i
< ConsoleListSize
; i
++)
70 if (ConsoleList
[i
] == NULL
) break;
74 if (i
>= ConsoleListSize
)
76 DPRINT("Creation of a new handles table\n");
77 /* Allocate a new handles table */
78 Block
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
,
80 CONSOLE_HANDLES_INCREMENT
) * sizeof(PCONSRV_CONSOLE
));
83 Status
= STATUS_UNSUCCESSFUL
;
87 /* If we previously had a handles table, free it and use the new one */
90 /* Copy the handles from the old table to the new one */
93 ConsoleListSize
* sizeof(PCONSRV_CONSOLE
));
94 ConsoleFreeHeap(ConsoleList
);
97 ConsoleListSize
+= CONSOLE_HANDLES_INCREMENT
;
100 ConsoleList
[i
] = Console
;
101 *Handle
= ULongToHandle((i
<< 2) | 0x3);
104 /* Unlock the console list and return status */
105 ConSrvUnlockConsoleList();
112 RemoveConsoleByHandle(IN HANDLE Handle
)
114 NTSTATUS Status
= STATUS_SUCCESS
;
115 PCONSRV_CONSOLE Console
;
117 BOOLEAN ValidHandle
= ((HandleToULong(Handle
) & 0x3) == 0x3);
118 ULONG Index
= HandleToULong(Handle
) >> 2;
120 if (!ValidHandle
) return STATUS_INVALID_HANDLE
;
122 ASSERT( (ConsoleList
== NULL
&& ConsoleListSize
== 0) ||
123 (ConsoleList
!= NULL
&& ConsoleListSize
!= 0) );
125 /* Remove the console from the list */
126 ConSrvLockConsoleListExclusive();
128 if (Index
>= ConsoleListSize
||
129 (Console
= ConsoleList
[Index
]) == NULL
)
131 Status
= STATUS_INVALID_HANDLE
;
135 ConsoleList
[Index
] = NULL
;
138 /* Unlock the console list and return status */
139 ConSrvUnlockConsoleList();
145 RemoveConsoleByPointer(IN PCONSRV_CONSOLE Console
)
149 if (!Console
) return STATUS_INVALID_PARAMETER
;
151 ASSERT( (ConsoleList
== NULL
&& ConsoleListSize
== 0) ||
152 (ConsoleList
!= NULL
&& ConsoleListSize
!= 0) );
154 /* Remove the console from the list */
155 ConSrvLockConsoleListExclusive();
159 for (i
= 0; i
< ConsoleListSize
; i
++)
161 if (ConsoleList
[i
] == Console
) ConsoleList
[i
] = NULL
;
165 /* Unlock the console list and return */
166 ConSrvUnlockConsoleList();
167 return STATUS_SUCCESS
;
171 ConSrvValidateConsole(OUT PCONSRV_CONSOLE
* Console
,
172 IN HANDLE ConsoleHandle
,
173 IN CONSOLE_STATE ExpectedState
,
174 IN BOOLEAN LockConsole
)
176 BOOLEAN RetVal
= FALSE
;
177 PCONSRV_CONSOLE ValidatedConsole
;
179 BOOLEAN ValidHandle
= ((HandleToULong(ConsoleHandle
) & 0x3) == 0x3);
180 ULONG Index
= HandleToULong(ConsoleHandle
) >> 2;
182 if (!ValidHandle
) return FALSE
;
184 if (!Console
) return FALSE
;
188 * Forbid creation or deletion of consoles when
189 * checking for the existence of a console.
191 ConSrvLockConsoleListShared();
193 if (Index
>= ConsoleListSize
||
194 (ValidatedConsole
= ConsoleList
[Index
]) == NULL
)
196 /* Unlock the console list and return */
197 ConSrvUnlockConsoleList();
201 ValidatedConsole
= ConsoleList
[Index
];
203 /* Unlock the console list and return */
204 ConSrvUnlockConsoleList();
206 RetVal
= ConDrvValidateConsoleUnsafe((PCONSOLE
)ValidatedConsole
,
209 if (RetVal
) *Console
= ValidatedConsole
;
215 /* PRIVATE FUNCTIONS **********************************************************/
217 // Adapted from reactos/lib/rtl/unicode.c, RtlCreateUnicodeString line 2180
219 ConsoleCreateUnicodeString(IN OUT PUNICODE_STRING UniDest
,
222 SIZE_T Size
= (wcslen(Source
) + 1) * sizeof(WCHAR
);
223 if (Size
> MAXUSHORT
) return FALSE
;
225 UniDest
->Buffer
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, Size
);
226 if (UniDest
->Buffer
== NULL
) return FALSE
;
228 RtlCopyMemory(UniDest
->Buffer
, Source
, Size
);
229 UniDest
->MaximumLength
= (USHORT
)Size
;
230 UniDest
->Length
= (USHORT
)Size
- sizeof(WCHAR
);
235 // Adapted from reactos/lib/rtl/unicode.c, RtlFreeUnicodeString line 431
237 ConsoleFreeUnicodeString(IN PUNICODE_STRING UnicodeString
)
239 if (UnicodeString
->Buffer
)
241 ConsoleFreeHeap(UnicodeString
->Buffer
);
242 RtlZeroMemory(UnicodeString
, sizeof(UNICODE_STRING
));
247 ConioPause(PCONSRV_CONSOLE Console
, UINT Flags
)
249 Console
->PauseFlags
|= Flags
;
250 ConDrvPause((PCONSOLE
)Console
);
254 ConioUnpause(PCONSRV_CONSOLE Console
, UINT Flags
)
256 Console
->PauseFlags
&= ~Flags
;
258 // if ((Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION)) == 0)
259 if (Console
->PauseFlags
== 0)
261 ConDrvUnpause((PCONSOLE
)Console
);
263 CsrNotifyWait(&Console
->WriteWaitQueue
,
267 if (!IsListEmpty(&Console
->WriteWaitQueue
))
269 CsrDereferenceWait(&Console
->WriteWaitQueue
);
275 ConSrvGetConsole(IN PCONSOLE_PROCESS_DATA ProcessData
,
276 OUT PCONSRV_CONSOLE
* Console
,
277 IN BOOLEAN LockConsole
)
279 NTSTATUS Status
= STATUS_INVALID_HANDLE
;
280 PCONSRV_CONSOLE GrabConsole
;
282 // if (Console == NULL) return STATUS_INVALID_PARAMETER;
286 // RtlEnterCriticalSection(&ProcessData->HandleTableLock);
288 if (ConSrvValidateConsole(&GrabConsole
,
289 ProcessData
->ConsoleHandle
,
293 InterlockedIncrement(&GrabConsole
->ReferenceCount
);
294 *Console
= GrabConsole
;
295 Status
= STATUS_SUCCESS
;
298 // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
303 ConSrvReleaseConsole(IN PCONSRV_CONSOLE Console
,
304 IN BOOLEAN WasConsoleLocked
)
308 if (!Console
) return;
309 // if (Console->ReferenceCount == 0) return; // This shouldn't happen
310 ASSERT(Console
->ReferenceCount
> 0);
312 /* The console must be locked */
313 // ASSERT(Console_locked);
316 * Decrement the reference count. Save the new value too,
317 * because Console->ReferenceCount might be modified after
318 * the console gets unlocked but before we check whether we
321 RefCount
= _InterlockedDecrement(&Console
->ReferenceCount
);
323 /* Unlock the console if needed */
324 if (WasConsoleLocked
) LeaveCriticalSection(&Console
->Lock
);
326 /* Delete the console if needed */
327 if (RefCount
<= 0) ConSrvDeleteConsole(Console
);
331 /* CONSOLE INITIALIZATION FUNCTIONS *******************************************/
334 ConSrvInitConsoleSupport(VOID
)
336 DPRINT("CONSRV: ConSrvInitConsoleSupport()\n");
338 /* Initialize the console list and its lock */
341 RtlInitializeResource(&ListLock
);
343 /* Should call LoadKeyboardLayout */
347 ConSrvInitTerminal(IN OUT PTERMINAL Terminal
,
348 IN OUT PCONSOLE_INFO ConsoleInfo
,
349 IN OUT PVOID ExtraConsoleInfo
,
352 ConSrvDeinitTerminal(IN OUT PTERMINAL Terminal
);
356 LoadShellLinkConsoleInfo(IN OUT PCONSOLE_INFO ConsoleInfo
,
357 IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo
)
359 #define PATH_SEPARATOR L'\\'
364 LPWSTR LinkName
= NULL
;
365 LPWSTR IconPath
= NULL
;
366 WCHAR Buffer
[MAX_PATH
+ 1];
368 ConsoleInitInfo
->ConsoleStartInfo
->IconIndex
= 0;
370 if ((ConsoleInitInfo
->ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
372 // return FALSE; // FIXME!! (for icon loading)
377 /* 1- Find the last path separator if any */
378 LinkName
= wcsrchr(ConsoleInfo
->ConsoleTitle
, PATH_SEPARATOR
);
379 if (LinkName
== NULL
)
380 LinkName
= ConsoleInfo
->ConsoleTitle
;
382 ++LinkName
; // Skip the path separator
384 /* 2- Check for the link extension. The name ".lnk" is considered invalid. */
385 Length
= wcslen(LinkName
);
386 if ( (Length
<= 4) || (wcsicmp(LinkName
+ (Length
- 4), L
".lnk") != 0) )
389 /* 3- It may be a link. Try to retrieve some properties */
390 hRes
= CoInitialize(NULL
);
393 /* Get a pointer to the IShellLink interface */
394 IShellLinkW
* pshl
= NULL
;
395 hRes
= CoCreateInstance(&CLSID_ShellLink
,
397 CLSCTX_INPROC_SERVER
,
402 /* Get a pointer to the IPersistFile interface */
403 IPersistFile
* ppf
= NULL
;
404 hRes
= IPersistFile_QueryInterface(pshl
, &IID_IPersistFile
, (LPVOID
*)&ppf
);
407 /* Load the shortcut */
408 hRes
= IPersistFile_Load(ppf
, ConsoleInfo
->ConsoleTitle
, STGM_READ
);
412 * Finally we can get the properties !
413 * Update the old ones if needed.
418 /* Reset the name of the console with the name of the shortcut */
419 Length
= min(/*Length*/ Length
- 4, // 4 == len(".lnk")
420 sizeof(ConsoleInfo
->ConsoleTitle
) / sizeof(ConsoleInfo
->ConsoleTitle
[0]) - 1);
421 wcsncpy(ConsoleInfo
->ConsoleTitle
, LinkName
, Length
);
422 ConsoleInfo
->ConsoleTitle
[Length
] = L
'\0';
424 /* Get the window showing command */
425 hRes
= IShellLinkW_GetShowCmd(pshl
, &ShowCmd
);
426 if (SUCCEEDED(hRes
)) ConsoleInitInfo
->ConsoleStartInfo
->wShowWindow
= (WORD
)ShowCmd
;
429 // hRes = pshl->GetHotkey(&ShowCmd);
430 // if (SUCCEEDED(hRes)) ConsoleInitInfo->ConsoleStartInfo->HotKey = HotKey;
432 /* Get the icon location, if any */
433 hRes
= IShellLinkW_GetIconLocation(pshl
,
435 sizeof(Buffer
)/sizeof(Buffer
[0]) - 1, // == MAX_PATH
436 &ConsoleInitInfo
->ConsoleStartInfo
->IconIndex
);
437 if (!SUCCEEDED(hRes
))
439 ConsoleInitInfo
->ConsoleStartInfo
->IconIndex
= 0;
446 // FIXME: Since we still don't load console properties from the shortcut,
447 // return false. When this will be done, we will return true instead.
448 RetVal
= TRUE
; // FALSE;
450 IPersistFile_Release(ppf
);
452 IShellLinkW_Release(pshl
);
461 /* Get the associated icon, if any */
462 if (IconPath
== NULL
)
464 // Question: How to retrieve the full path name
465 // of the app we are going to run??
466 Length
= RtlDosSearchPath_U(ConsoleInitInfo
->CurDir
,
467 ConsoleInitInfo
->AppName
,
472 if (Length
> 0 && Length
< sizeof(Buffer
))
475 IconPath
= ConsoleInitInfo
->AppName
;
477 // ConsoleInitInfo->ConsoleStartInfo->IconIndex = 0;
479 DPRINT("IconPath = '%S' ; IconIndex = %lu\n",
480 IconPath
, ConsoleInitInfo
->ConsoleStartInfo
->IconIndex
);
481 if (IconPath
&& *IconPath
)
483 HICON hIcon
= NULL
, hIconSm
= NULL
;
484 PrivateExtractIconExW(IconPath
,
485 ConsoleInitInfo
->ConsoleStartInfo
->IconIndex
,
489 DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon
, hIconSm
);
490 if (hIcon
!= NULL
) ConsoleInitInfo
->ConsoleStartInfo
->hIcon
= hIcon
;
491 if (hIconSm
!= NULL
) ConsoleInitInfo
->ConsoleStartInfo
->hIconSm
= hIconSm
;
495 // FIXME: See the previous FIXME above.
502 ConSrvInitConsole(OUT PHANDLE NewConsoleHandle
,
503 OUT PCONSRV_CONSOLE
* NewConsole
,
504 IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo
,
505 IN ULONG ConsoleLeaderProcessId
)
508 HANDLE ConsoleHandle
;
509 PCONSRV_CONSOLE Console
;
510 CONSOLE_INFO ConsoleInfo
;
513 TERMINAL Terminal
; /* The ConSrv terminal for this console */
515 if (NewConsole
== NULL
|| ConsoleInitInfo
== NULL
)
516 return STATUS_INVALID_PARAMETER
;
521 * Load the console settings
524 /* 1. Load the default settings */
525 ConSrvGetDefaultSettings(&ConsoleInfo
, ConsoleLeaderProcessId
);
527 /* 2. Get the title of the console (initialize ConsoleInfo.ConsoleTitle) */
528 Length
= min(ConsoleInitInfo
->TitleLength
,
529 sizeof(ConsoleInfo
.ConsoleTitle
) / sizeof(ConsoleInfo
.ConsoleTitle
[0]) - 1);
530 wcsncpy(ConsoleInfo
.ConsoleTitle
, ConsoleInitInfo
->ConsoleTitle
, Length
);
531 ConsoleInfo
.ConsoleTitle
[Length
] = L
'\0'; // NULL-terminate it.
533 /* 3. Initialize the ConSrv terminal */
534 Status
= ConSrvInitTerminal(&Terminal
,
537 ConsoleLeaderProcessId
);
538 if (!NT_SUCCESS(Status
))
540 DPRINT1("CONSRV: Failed to initialize a terminal, Status = 0x%08lx\n", Status
);
543 DPRINT("CONSRV: Terminal initialized\n");
546 * Load per-application terminal settings.
548 * Check whether the process creating the console was launched via
549 * a shell-link. ConsoleInfo->ConsoleTitle may be updated with the
550 * name of the shortcut, and ConsoleStartInfo->Icon[Path|Index] too.
552 // if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) // FIXME!! (for icon loading)
554 if (!LoadShellLinkConsoleInfo(&ConsoleInfo
, ConsoleInitInfo
))
556 ConsoleInitInfo
->ConsoleStartInfo
->dwStartupFlags
&= ~STARTF_TITLEISLINKNAME
;
561 * 4. Load the remaining console settings via the registry.
563 if ((ConsoleInitInfo
->ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
566 * Either we weren't created by an app launched via a shell-link,
567 * or we failed to load shell-link console properties.
568 * Therefore, load the console infos for the application from the registry.
570 ConSrvReadUserSettings(&ConsoleInfo
, ConsoleLeaderProcessId
);
573 * Now, update them with the properties the user might gave to us
574 * via the STARTUPINFO structure before calling CreateProcess
575 * (and which was transmitted via the ConsoleStartInfo structure).
576 * We therefore overwrite the values read in the registry.
578 if (ConsoleInitInfo
->ConsoleStartInfo
->dwStartupFlags
& STARTF_USEFILLATTRIBUTE
)
580 ConsoleInfo
.ScreenAttrib
= (USHORT
)ConsoleInitInfo
->ConsoleStartInfo
->wFillAttribute
;
582 if (ConsoleInitInfo
->ConsoleStartInfo
->dwStartupFlags
& STARTF_USECOUNTCHARS
)
584 ConsoleInfo
.ScreenBufferSize
= ConsoleInitInfo
->ConsoleStartInfo
->dwScreenBufferSize
;
586 if (ConsoleInitInfo
->ConsoleStartInfo
->dwStartupFlags
& STARTF_USESIZE
)
588 ConsoleInfo
.ConsoleSize
= ConsoleInitInfo
->ConsoleStartInfo
->dwWindowSize
;
592 /* Set-up the code page */
593 ConsoleInfo
.CodePage
= GetOEMCP();
595 /* Initialize a new console via the driver */
596 Status
= ConDrvInitConsole(&Console
, &ConsoleInfo
);
597 if (!NT_SUCCESS(Status
))
599 DPRINT1("Creating a new console failed, Status = 0x%08lx\n", Status
);
600 ConSrvDeinitTerminal(&Terminal
);
605 DPRINT("Console initialized\n");
607 /*** Register ConSrv features ***/
609 /* Initialize the console title */
611 WCHAR DefaultTitle
[128];
613 ConsoleCreateUnicodeString(&Console
->OriginalTitle
, ConsoleInfo
.ConsoleTitle
);
615 if (ConsoleInfo
.ConsoleTitle
[0] == L
'\0')
617 if (LoadStringW(ConSrvDllInstance
, IDS_CONSOLE_TITLE
, DefaultTitle
, sizeof(DefaultTitle
) / sizeof(DefaultTitle
[0])))
619 ConsoleCreateUnicodeString(&Console
->Title
, DefaultTitle
);
623 ConsoleCreateUnicodeString(&Console
->Title
, L
"ReactOS Console");
629 ConsoleCreateUnicodeString(&Console
->Title
, ConsoleInfo
.ConsoleTitle
);
634 /* Initialize process support */
635 InitializeListHead(&Console
->ProcessList
);
636 Console
->NotifiedLastCloseProcess
= NULL
;
637 Console
->NotifyLastClose
= FALSE
;
639 /* Initialize pausing support */
640 Console
->PauseFlags
= 0;
641 InitializeListHead(&Console
->ReadWaitQueue
);
642 InitializeListHead(&Console
->WriteWaitQueue
);
644 /* Initialize the alias and history buffers */
645 Console
->Aliases
= NULL
;
646 InitializeListHead(&Console
->HistoryBuffers
);
647 Console
->HistoryBufferSize
= ConsoleInfo
.HistoryBufferSize
;
648 Console
->NumberOfHistoryBuffers
= ConsoleInfo
.NumberOfHistoryBuffers
;
649 Console
->HistoryNoDup
= ConsoleInfo
.HistoryNoDup
;
651 /* Initialize the Input Line Discipline */
652 Console
->LineBuffer
= NULL
;
653 Console
->LinePos
= Console
->LineMaxSize
= Console
->LineSize
= 0;
654 Console
->LineComplete
= Console
->LineUpPressed
= FALSE
;
656 Console
->LineInsertToggle
=
657 Console
->InsertMode
= ConsoleInfo
.InsertMode
;
658 Console
->QuickEdit
= ConsoleInfo
.QuickEdit
;
661 InitializeListHead(&Console
->PopupWindows
);
664 memcpy(Console
->Colors
, ConsoleInfo
.Colors
, sizeof(ConsoleInfo
.Colors
));
666 /* Create the Initialization Events */
667 Status
= NtCreateEvent(&Console
->InitEvents
[INIT_SUCCESS
], EVENT_ALL_ACCESS
,
668 NULL
, NotificationEvent
, FALSE
);
669 if (!NT_SUCCESS(Status
))
671 DPRINT1("NtCreateEvent(InitEvents[INIT_SUCCESS]) failed: %lu\n", Status
);
672 ConDrvDeleteConsole(Console
);
673 ConSrvDeinitTerminal(&Terminal
);
676 Status
= NtCreateEvent(&Console
->InitEvents
[INIT_FAILURE
], EVENT_ALL_ACCESS
,
677 NULL
, NotificationEvent
, FALSE
);
678 if (!NT_SUCCESS(Status
))
680 DPRINT1("NtCreateEvent(InitEvents[INIT_FAILURE]) failed: %lu\n", Status
);
681 NtClose(Console
->InitEvents
[INIT_SUCCESS
]);
682 ConDrvDeleteConsole(Console
);
683 ConSrvDeinitTerminal(&Terminal
);
688 * Attach the ConSrv terminal to the console.
689 * This call makes a copy of our local Terminal variable.
691 Status
= ConDrvRegisterTerminal(Console
, &Terminal
);
692 if (!NT_SUCCESS(Status
))
694 DPRINT1("Failed to register terminal to the given console, Status = 0x%08lx\n", Status
);
695 NtClose(Console
->InitEvents
[INIT_FAILURE
]);
696 NtClose(Console
->InitEvents
[INIT_SUCCESS
]);
697 ConDrvDeleteConsole(Console
);
698 ConSrvDeinitTerminal(&Terminal
);
701 DPRINT("Terminal registered\n");
703 /* All went right, so add the console to the list */
704 Status
= InsertConsole(&ConsoleHandle
, Console
);
706 // FIXME! We do not support at all asynchronous console creation!
707 NtSetEvent(Console
->InitEvents
[INIT_SUCCESS
], NULL
);
708 // NtSetEvent(Console->InitEvents[INIT_FAILURE], NULL);
710 /* Return the newly created console to the caller and a success code too */
711 *NewConsoleHandle
= ConsoleHandle
;
712 *NewConsole
= Console
;
713 return STATUS_SUCCESS
;
717 ConSrvDeleteConsole(PCONSRV_CONSOLE Console
)
719 DPRINT("ConSrvDeleteConsole\n");
721 // FIXME: Send a terminate message to all the processes owning this console
723 /* Remove the console from the list */
724 RemoveConsoleByPointer(Console
);
726 /* Destroy the Initialization Events */
727 NtClose(Console
->InitEvents
[INIT_FAILURE
]);
728 NtClose(Console
->InitEvents
[INIT_SUCCESS
]);
730 /* Clean the Input Line Discipline */
731 if (Console
->LineBuffer
) ConsoleFreeHeap(Console
->LineBuffer
);
733 /* Clean aliases and history */
734 IntDeleteAllAliases(Console
);
735 HistoryDeleteBuffers(Console
);
737 /* Free the console title */
738 ConsoleFreeUnicodeString(&Console
->OriginalTitle
);
739 ConsoleFreeUnicodeString(&Console
->Title
);
741 /* Now, call the driver. ConDrvDeregisterTerminal is called on-demand. */
742 ConDrvDeleteConsole((PCONSOLE
)Console
);
744 /* Deinit the ConSrv terminal */
746 // ConSrvDeinitTerminal(&Terminal); // &ConSrvConsole->Console->TermIFace
755 ConSrvConsoleCtrlEventTimeout(IN ULONG CtrlEvent
,
756 IN PCONSOLE_PROCESS_DATA ProcessData
,
759 NTSTATUS Status
= STATUS_SUCCESS
;
761 DPRINT("ConSrvConsoleCtrlEventTimeout Parent ProcessId = %x\n", ProcessData
->Process
->ClientId
.UniqueProcess
);
763 if (ProcessData
->CtrlRoutine
)
767 HANDLE Thread
= NULL
;
771 Thread
= CreateRemoteThread(ProcessData
->Process
->ProcessHandle
, NULL
, 0,
772 ProcessData
->CtrlRoutine
,
773 UlongToPtr(CtrlEvent
), 0, NULL
);
776 Status
= RtlGetLastNtStatus();
777 DPRINT1("Failed thread creation, Status = 0x%08lx\n", Status
);
781 DPRINT("ProcessData->CtrlRoutine remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n",
782 ProcessData
->Process
->ClientId
.UniqueProcess
, ProcessData
->Process
);
783 WaitForSingleObject(Thread
, Timeout
);
792 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
794 Status
= _SEH2_GetExceptionCode();
795 DPRINT1("ConSrvConsoleCtrlEventTimeout - Caught an exception, Status = 0x%08lx\n", Status
);
804 ConSrvConsoleCtrlEvent(IN ULONG CtrlEvent
,
805 IN PCONSOLE_PROCESS_DATA ProcessData
)
807 return ConSrvConsoleCtrlEventTimeout(CtrlEvent
, ProcessData
, 0);
810 PCONSOLE_PROCESS_DATA NTAPI
811 ConSrvGetConsoleLeaderProcess(IN PCONSRV_CONSOLE Console
)
813 if (Console
== NULL
) return NULL
;
815 return CONTAINING_RECORD(Console
->ProcessList
.Blink
,
816 CONSOLE_PROCESS_DATA
,
821 ConSrvGetConsoleProcessList(IN PCONSRV_CONSOLE Console
,
822 IN OUT PULONG ProcessIdsList
,
823 IN ULONG MaxIdListItems
,
824 OUT PULONG ProcessIdsTotal
)
826 PCONSOLE_PROCESS_DATA current
;
827 PLIST_ENTRY current_entry
;
829 if (Console
== NULL
|| ProcessIdsList
== NULL
|| ProcessIdsTotal
== NULL
)
830 return STATUS_INVALID_PARAMETER
;
832 *ProcessIdsTotal
= 0;
834 for (current_entry
= Console
->ProcessList
.Flink
;
835 current_entry
!= &Console
->ProcessList
;
836 current_entry
= current_entry
->Flink
)
838 current
= CONTAINING_RECORD(current_entry
, CONSOLE_PROCESS_DATA
, ConsoleLink
);
839 if (++(*ProcessIdsTotal
) <= MaxIdListItems
)
841 *ProcessIdsList
++ = HandleToUlong(current
->Process
->ClientId
.UniqueProcess
);
845 return STATUS_SUCCESS
;
848 // ConSrvGenerateConsoleCtrlEvent
850 ConSrvConsoleProcessCtrlEvent(IN PCONSRV_CONSOLE Console
,
851 IN ULONG ProcessGroupId
,
854 NTSTATUS Status
= STATUS_SUCCESS
;
855 PLIST_ENTRY current_entry
;
856 PCONSOLE_PROCESS_DATA current
;
858 /* If the console is already being destroyed, just return */
859 if (!ConDrvValidateConsoleState((PCONSOLE
)Console
, CONSOLE_RUNNING
))
860 return STATUS_UNSUCCESSFUL
;
863 * Loop through the process list, from the most recent process
864 * (the active one) to the oldest one (the first created, i.e.
865 * the console leader process), and for each, send an event
866 * (new processes are inserted at the head of the console process list).
868 current_entry
= Console
->ProcessList
.Flink
;
869 while (current_entry
!= &Console
->ProcessList
)
871 current
= CONTAINING_RECORD(current_entry
, CONSOLE_PROCESS_DATA
, ConsoleLink
);
872 current_entry
= current_entry
->Flink
;
875 * Only processes belonging to the same process group are signaled.
876 * If the process group ID is zero, then all the processes are signaled.
878 if (ProcessGroupId
== 0 || current
->Process
->ProcessGroupId
== ProcessGroupId
)
880 Status
= ConSrvConsoleCtrlEvent(CtrlEvent
, current
);
888 /* PUBLIC SERVER APIS *********************************************************/
890 CSR_API(SrvAllocConsole
)
892 NTSTATUS Status
= STATUS_SUCCESS
;
893 PCONSOLE_ALLOCCONSOLE AllocConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.AllocConsoleRequest
;
894 PCSR_PROCESS CsrProcess
= CsrGetClientThread()->Process
;
895 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrProcess
);
896 CONSOLE_INIT_INFO ConsoleInitInfo
;
898 if (ProcessData
->ConsoleHandle
!= NULL
)
900 DPRINT1("Process already has a console\n");
901 return STATUS_ACCESS_DENIED
;
904 if ( !CsrValidateMessageBuffer(ApiMessage
,
905 (PVOID
*)&AllocConsoleRequest
->ConsoleStartInfo
,
907 sizeof(CONSOLE_START_INFO
)) ||
908 !CsrValidateMessageBuffer(ApiMessage
,
909 (PVOID
*)&AllocConsoleRequest
->ConsoleTitle
,
910 AllocConsoleRequest
->TitleLength
,
912 !CsrValidateMessageBuffer(ApiMessage
,
913 (PVOID
*)&AllocConsoleRequest
->Desktop
,
914 AllocConsoleRequest
->DesktopLength
,
916 !CsrValidateMessageBuffer(ApiMessage
,
917 (PVOID
*)&AllocConsoleRequest
->CurDir
,
918 AllocConsoleRequest
->CurDirLength
,
920 !CsrValidateMessageBuffer(ApiMessage
,
921 (PVOID
*)&AllocConsoleRequest
->AppName
,
922 AllocConsoleRequest
->AppNameLength
,
925 return STATUS_INVALID_PARAMETER
;
928 /* Initialize the console initialization info structure */
929 ConsoleInitInfo
.ConsoleStartInfo
= AllocConsoleRequest
->ConsoleStartInfo
;
930 ConsoleInitInfo
.TitleLength
= AllocConsoleRequest
->TitleLength
;
931 ConsoleInitInfo
.ConsoleTitle
= AllocConsoleRequest
->ConsoleTitle
;
932 ConsoleInitInfo
.DesktopLength
= AllocConsoleRequest
->DesktopLength
;
933 ConsoleInitInfo
.Desktop
= AllocConsoleRequest
->Desktop
;
934 ConsoleInitInfo
.AppNameLength
= AllocConsoleRequest
->AppNameLength
;
935 ConsoleInitInfo
.AppName
= AllocConsoleRequest
->AppName
;
936 ConsoleInitInfo
.CurDirLength
= AllocConsoleRequest
->CurDirLength
;
937 ConsoleInitInfo
.CurDir
= AllocConsoleRequest
->CurDir
;
939 /* Initialize a new Console owned by the Console Leader Process */
940 Status
= ConSrvAllocateConsole(ProcessData
,
941 &AllocConsoleRequest
->ConsoleStartInfo
->InputHandle
,
942 &AllocConsoleRequest
->ConsoleStartInfo
->OutputHandle
,
943 &AllocConsoleRequest
->ConsoleStartInfo
->ErrorHandle
,
945 if (!NT_SUCCESS(Status
))
947 DPRINT1("Console allocation failed\n");
951 /* Mark the process as having a console */
952 ProcessData
->ConsoleApp
= TRUE
;
953 CsrProcess
->Flags
|= CsrProcessIsConsoleApp
;
955 /* Return the console handle and the input wait handle to the caller */
956 AllocConsoleRequest
->ConsoleStartInfo
->ConsoleHandle
= ProcessData
->ConsoleHandle
;
957 AllocConsoleRequest
->ConsoleStartInfo
->InputWaitHandle
= ProcessData
->InputWaitHandle
;
959 /* Set the Property-Dialog and Control-Dispatcher handlers */
960 ProcessData
->PropRoutine
= AllocConsoleRequest
->PropRoutine
;
961 ProcessData
->CtrlRoutine
= AllocConsoleRequest
->CtrlRoutine
;
963 return STATUS_SUCCESS
;
966 CSR_API(SrvAttachConsole
)
968 NTSTATUS Status
= STATUS_SUCCESS
;
969 PCONSOLE_ATTACHCONSOLE AttachConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.AttachConsoleRequest
;
970 PCSR_PROCESS SourceProcess
= NULL
; // The parent process.
971 PCSR_PROCESS TargetProcess
= CsrGetClientThread()->Process
; // Ourselves.
972 HANDLE ProcessId
= ULongToHandle(AttachConsoleRequest
->ProcessId
);
973 PCONSOLE_PROCESS_DATA SourceProcessData
, TargetProcessData
;
975 TargetProcessData
= ConsoleGetPerProcessData(TargetProcess
);
977 if (TargetProcessData
->ConsoleHandle
!= NULL
)
979 DPRINT1("Process already has a console\n");
980 return STATUS_ACCESS_DENIED
;
983 if (!CsrValidateMessageBuffer(ApiMessage
,
984 (PVOID
*)&AttachConsoleRequest
->ConsoleStartInfo
,
986 sizeof(CONSOLE_START_INFO
)))
988 return STATUS_INVALID_PARAMETER
;
991 /* Check whether we try to attach to the parent's console */
992 if (ProcessId
== ULongToHandle(ATTACH_PARENT_PROCESS
))
994 PROCESS_BASIC_INFORMATION ProcessInfo
;
995 ULONG Length
= sizeof(ProcessInfo
);
997 /* Get the real parent's ID */
999 Status
= NtQueryInformationProcess(TargetProcess
->ProcessHandle
,
1000 ProcessBasicInformation
,
1003 if (!NT_SUCCESS(Status
))
1005 DPRINT1("SrvAttachConsole - Cannot retrieve basic process info, Status = %lu\n", Status
);
1009 ProcessId
= ULongToHandle(ProcessInfo
.InheritedFromUniqueProcessId
);
1012 /* Lock the source process via its PID */
1013 Status
= CsrLockProcessByClientId(ProcessId
, &SourceProcess
);
1014 if (!NT_SUCCESS(Status
)) return Status
;
1016 SourceProcessData
= ConsoleGetPerProcessData(SourceProcess
);
1018 if (SourceProcessData
->ConsoleHandle
== NULL
)
1020 Status
= STATUS_INVALID_HANDLE
;
1025 * Inherit the console from the parent,
1026 * if any, otherwise return an error.
1028 Status
= ConSrvInheritConsole(TargetProcessData
,
1029 SourceProcessData
->ConsoleHandle
,
1031 &AttachConsoleRequest
->ConsoleStartInfo
->InputHandle
,
1032 &AttachConsoleRequest
->ConsoleStartInfo
->OutputHandle
,
1033 &AttachConsoleRequest
->ConsoleStartInfo
->ErrorHandle
,
1034 AttachConsoleRequest
->ConsoleStartInfo
);
1035 if (!NT_SUCCESS(Status
))
1037 DPRINT1("Console inheritance failed\n");
1041 /* Mark the process as having a console */
1042 TargetProcessData
->ConsoleApp
= TRUE
;
1043 TargetProcess
->Flags
|= CsrProcessIsConsoleApp
;
1045 /* Return the console handle and the input wait handle to the caller */
1046 AttachConsoleRequest
->ConsoleStartInfo
->ConsoleHandle
= TargetProcessData
->ConsoleHandle
;
1047 AttachConsoleRequest
->ConsoleStartInfo
->InputWaitHandle
= TargetProcessData
->InputWaitHandle
;
1049 /* Set the Property-Dialog and Control-Dispatcher handlers */
1050 TargetProcessData
->PropRoutine
= AttachConsoleRequest
->PropRoutine
;
1051 TargetProcessData
->CtrlRoutine
= AttachConsoleRequest
->CtrlRoutine
;
1053 Status
= STATUS_SUCCESS
;
1056 /* Unlock the "source" process and exit */
1057 CsrUnlockProcess(SourceProcess
);
1061 CSR_API(SrvFreeConsole
)
1063 PCSR_PROCESS CsrProcess
= CsrGetClientThread()->Process
;
1064 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrProcess
);
1066 ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
));
1068 /* Mark the process as not having a console anymore */
1069 ProcessData
->ConsoleApp
= FALSE
;
1070 CsrProcess
->Flags
&= ~CsrProcessIsConsoleApp
;
1072 return STATUS_SUCCESS
;
1076 ConDrvGetConsoleMode(IN PCONSOLE Console
,
1077 IN PCONSOLE_IO_OBJECT Object
,
1078 OUT PULONG ConsoleMode
);
1079 CSR_API(SrvGetConsoleMode
)
1082 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleModeRequest
;
1083 PCONSOLE_IO_OBJECT Object
;
1085 PULONG ConsoleMode
= &ConsoleModeRequest
->Mode
;
1087 Status
= ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
1088 ConsoleModeRequest
->Handle
,
1089 &Object
, NULL
, GENERIC_READ
, TRUE
, 0);
1090 if (!NT_SUCCESS(Status
)) return Status
;
1092 /* Get the standard console modes */
1093 Status
= ConDrvGetConsoleMode(Object
->Console
, Object
,
1095 if (NT_SUCCESS(Status
))
1098 * If getting the console modes succeeds, then retrieve
1099 * the extended CONSRV-specific input modes.
1101 if (INPUT_BUFFER
== Object
->Type
)
1103 if (Object
->Console
->InsertMode
|| Object
->Console
->QuickEdit
)
1105 /* Windows also adds ENABLE_EXTENDED_FLAGS, even if it's not documented on MSDN */
1106 *ConsoleMode
|= ENABLE_EXTENDED_FLAGS
;
1108 if (Object
->Console
->InsertMode
) *ConsoleMode
|= ENABLE_INSERT_MODE
;
1109 if (Object
->Console
->QuickEdit
) *ConsoleMode
|= ENABLE_QUICK_EDIT_MODE
;
1114 ConSrvReleaseObject(Object
, TRUE
);
1119 ConDrvSetConsoleMode(IN PCONSOLE Console
,
1120 IN PCONSOLE_IO_OBJECT Object
,
1121 IN ULONG ConsoleMode
);
1122 CSR_API(SrvSetConsoleMode
)
1124 #define CONSOLE_VALID_CONTROL_MODES ( ENABLE_EXTENDED_FLAGS | \
1125 ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE )
1128 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleModeRequest
;
1129 PCONSOLE_IO_OBJECT Object
;
1131 ULONG ConsoleMode
= ConsoleModeRequest
->Mode
;
1133 Status
= ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
1134 ConsoleModeRequest
->Handle
,
1135 &Object
, NULL
, GENERIC_WRITE
, TRUE
, 0);
1136 if (!NT_SUCCESS(Status
)) return Status
;
1138 /* Set the standard console modes (without the CONSRV-specific input modes) */
1139 ConsoleMode
&= ~CONSOLE_VALID_CONTROL_MODES
; // Remove CONSRV-specific input modes.
1140 Status
= ConDrvSetConsoleMode(Object
->Console
, Object
,
1142 if (NT_SUCCESS(Status
))
1145 * If setting the console modes succeeds, then set
1146 * the extended CONSRV-specific input modes.
1148 if (INPUT_BUFFER
== Object
->Type
)
1150 ConsoleMode
= ConsoleModeRequest
->Mode
;
1152 if (ConsoleMode
& CONSOLE_VALID_CONTROL_MODES
)
1155 * If we use control mode flags without ENABLE_EXTENDED_FLAGS,
1156 * then consider the flags invalid.
1158 if ((ConsoleMode
& ENABLE_EXTENDED_FLAGS
) == 0)
1160 Status
= STATUS_INVALID_PARAMETER
;
1164 Object
->Console
->InsertMode
= !!(ConsoleMode
& ENABLE_INSERT_MODE
);
1165 Object
->Console
->QuickEdit
= !!(ConsoleMode
& ENABLE_QUICK_EDIT_MODE
);
1171 ConSrvReleaseObject(Object
, TRUE
);
1175 CSR_API(SrvGetConsoleTitle
)
1178 PCONSOLE_GETSETCONSOLETITLE TitleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.TitleRequest
;
1179 PCONSRV_CONSOLE Console
;
1182 if (!CsrValidateMessageBuffer(ApiMessage
,
1183 (PVOID
)&TitleRequest
->Title
,
1184 TitleRequest
->Length
,
1187 return STATUS_INVALID_PARAMETER
;
1190 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1191 if (!NT_SUCCESS(Status
))
1193 DPRINT1("Can't get console\n");
1197 /* Copy title of the console to the user title buffer */
1198 if (TitleRequest
->Unicode
)
1200 if (TitleRequest
->Length
>= sizeof(WCHAR
))
1202 Length
= min(TitleRequest
->Length
- sizeof(WCHAR
), Console
->Title
.Length
);
1203 RtlCopyMemory(TitleRequest
->Title
, Console
->Title
.Buffer
, Length
);
1204 ((PWCHAR
)TitleRequest
->Title
)[Length
/ sizeof(WCHAR
)] = L
'\0';
1205 TitleRequest
->Length
= Length
;
1209 TitleRequest
->Length
= Console
->Title
.Length
;
1214 if (TitleRequest
->Length
>= sizeof(CHAR
))
1216 Length
= min(TitleRequest
->Length
- sizeof(CHAR
), Console
->Title
.Length
/ sizeof(WCHAR
));
1217 Length
= WideCharToMultiByte(Console
->InputCodePage
, 0,
1218 Console
->Title
.Buffer
, Length
,
1219 TitleRequest
->Title
, Length
,
1221 ((PCHAR
)TitleRequest
->Title
)[Length
] = '\0';
1222 TitleRequest
->Length
= Length
;
1226 TitleRequest
->Length
= Console
->Title
.Length
/ sizeof(WCHAR
);
1230 ConSrvReleaseConsole(Console
, TRUE
);
1234 CSR_API(SrvSetConsoleTitle
)
1237 PCONSOLE_GETSETCONSOLETITLE TitleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.TitleRequest
;
1238 PCONSRV_CONSOLE Console
;
1243 if (!CsrValidateMessageBuffer(ApiMessage
,
1244 (PVOID
)&TitleRequest
->Title
,
1245 TitleRequest
->Length
,
1248 return STATUS_INVALID_PARAMETER
;
1251 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1252 if (!NT_SUCCESS(Status
))
1254 DPRINT1("Can't get console\n");
1258 if (TitleRequest
->Unicode
)
1260 /* Length is in bytes */
1261 Length
= TitleRequest
->Length
;
1265 /* Use the console input CP for the conversion */
1266 Length
= MultiByteToWideChar(Console
->InputCodePage
, 0,
1267 TitleRequest
->Title
, TitleRequest
->Length
,
1269 /* The returned Length was in number of wchars, convert it in bytes */
1270 Length
*= sizeof(WCHAR
);
1273 /* Allocate a new buffer to hold the new title (NULL-terminated) */
1274 Buffer
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, Length
+ sizeof(WCHAR
));
1277 Status
= STATUS_NO_MEMORY
;
1281 /* Free the old title */
1282 ConsoleFreeUnicodeString(&Console
->Title
);
1284 /* Copy title to console */
1285 Console
->Title
.Buffer
= Buffer
;
1286 Console
->Title
.Length
= Length
;
1287 Console
->Title
.MaximumLength
= Console
->Title
.Length
+ sizeof(WCHAR
);
1289 if (TitleRequest
->Unicode
)
1291 RtlCopyMemory(Console
->Title
.Buffer
, TitleRequest
->Title
, Console
->Title
.Length
);
1295 MultiByteToWideChar(Console
->InputCodePage
, 0,
1296 TitleRequest
->Title
, TitleRequest
->Length
,
1297 Console
->Title
.Buffer
,
1298 Console
->Title
.Length
/ sizeof(WCHAR
));
1301 /* NULL-terminate */
1302 Console
->Title
.Buffer
[Console
->Title
.Length
/ sizeof(WCHAR
)] = L
'\0';
1304 TermChangeTitle(Console
);
1305 Status
= STATUS_SUCCESS
;
1308 ConSrvReleaseConsole(Console
, TRUE
);
1313 ConDrvGetConsoleCP(IN PCONSOLE Console
,
1315 IN BOOLEAN OutputCP
);
1316 CSR_API(SrvGetConsoleCP
)
1319 PCONSOLE_GETINPUTOUTPUTCP GetConsoleCPRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetConsoleCPRequest
;
1320 PCONSRV_CONSOLE Console
;
1322 DPRINT("SrvGetConsoleCP, getting %s Code Page\n",
1323 GetConsoleCPRequest
->OutputCP
? "Output" : "Input");
1325 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1326 if (!NT_SUCCESS(Status
)) return Status
;
1328 Status
= ConDrvGetConsoleCP(Console
,
1329 &GetConsoleCPRequest
->CodePage
,
1330 GetConsoleCPRequest
->OutputCP
);
1332 ConSrvReleaseConsole(Console
, TRUE
);
1337 ConDrvSetConsoleCP(IN PCONSOLE Console
,
1339 IN BOOLEAN OutputCP
);
1340 CSR_API(SrvSetConsoleCP
)
1342 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
1343 PCONSOLE_SETINPUTOUTPUTCP SetConsoleCPRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetConsoleCPRequest
;
1344 PCONSRV_CONSOLE Console
;
1346 DPRINT("SrvSetConsoleCP, setting %s Code Page\n",
1347 SetConsoleCPRequest
->OutputCP
? "Output" : "Input");
1349 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1350 if (!NT_SUCCESS(Status
)) return Status
;
1352 Status
= ConDrvSetConsoleCP(Console
,
1353 SetConsoleCPRequest
->CodePage
,
1354 SetConsoleCPRequest
->OutputCP
);
1356 ConSrvReleaseConsole(Console
, TRUE
);
1360 CSR_API(SrvGetConsoleProcessList
)
1363 PCONSOLE_GETPROCESSLIST GetProcessListRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetProcessListRequest
;
1364 PCONSRV_CONSOLE Console
;
1366 if (!CsrValidateMessageBuffer(ApiMessage
,
1367 (PVOID
)&GetProcessListRequest
->ProcessIdsList
,
1368 GetProcessListRequest
->ProcessCount
,
1371 return STATUS_INVALID_PARAMETER
;
1374 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1375 if (!NT_SUCCESS(Status
)) return Status
;
1377 Status
= ConSrvGetConsoleProcessList(Console
,
1378 GetProcessListRequest
->ProcessIdsList
,
1379 GetProcessListRequest
->ProcessCount
,
1380 &GetProcessListRequest
->ProcessCount
);
1382 ConSrvReleaseConsole(Console
, TRUE
);
1386 CSR_API(SrvGenerateConsoleCtrlEvent
)
1389 PCONSOLE_GENERATECTRLEVENT GenerateCtrlEventRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GenerateCtrlEventRequest
;
1390 PCONSRV_CONSOLE Console
;
1392 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1393 if (!NT_SUCCESS(Status
)) return Status
;
1395 Status
= ConSrvConsoleProcessCtrlEvent(Console
,
1396 GenerateCtrlEventRequest
->ProcessGroupId
,
1397 GenerateCtrlEventRequest
->CtrlEvent
);
1399 ConSrvReleaseConsole(Console
, TRUE
);
1403 CSR_API(SrvConsoleNotifyLastClose
)
1406 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
1407 PCONSRV_CONSOLE Console
;
1409 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
1410 if (!NT_SUCCESS(Status
)) return Status
;
1412 /* Only one process is allowed to be registered for last close notification */
1413 if (!Console
->NotifyLastClose
)
1415 Console
->NotifyLastClose
= TRUE
;
1416 Console
->NotifiedLastCloseProcess
= ProcessData
;
1417 Status
= STATUS_SUCCESS
;
1421 Status
= STATUS_ACCESS_DENIED
;
1424 ConSrvReleaseConsole(Console
, TRUE
);
1430 CSR_API(SrvGetConsoleMouseInfo
)
1433 PCONSOLE_GETMOUSEINFO GetMouseInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetMouseInfoRequest
;
1434 PCONSRV_CONSOLE Console
;
1436 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1437 if (!NT_SUCCESS(Status
)) return Status
;
1439 /* Just retrieve the number of buttons of the mouse attached to this console */
1440 GetMouseInfoRequest
->NumButtons
= GetSystemMetrics(SM_CMOUSEBUTTONS
);
1442 ConSrvReleaseConsole(Console
, TRUE
);
1443 return STATUS_SUCCESS
;
1446 CSR_API(SrvSetConsoleKeyShortcuts
)
1448 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1449 return STATUS_NOT_IMPLEMENTED
;
1452 CSR_API(SrvGetConsoleKeyboardLayoutName
)
1455 PCONSOLE_GETKBDLAYOUTNAME GetKbdLayoutNameRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetKbdLayoutNameRequest
;
1456 PCONSRV_CONSOLE Console
;
1458 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1459 if (!NT_SUCCESS(Status
)) return Status
;
1461 /* Retrieve the keyboard layout name of the system */
1462 if (GetKbdLayoutNameRequest
->Ansi
)
1463 GetKeyboardLayoutNameA((PCHAR
)GetKbdLayoutNameRequest
->LayoutBuffer
);
1465 GetKeyboardLayoutNameW((PWCHAR
)GetKbdLayoutNameRequest
->LayoutBuffer
);
1467 ConSrvReleaseConsole(Console
, TRUE
);
1468 return STATUS_SUCCESS
;
1471 CSR_API(SrvGetConsoleCharType
)
1473 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1474 return STATUS_NOT_IMPLEMENTED
;
1477 CSR_API(SrvSetConsoleLocalEUDC
)
1479 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1480 return STATUS_NOT_IMPLEMENTED
;
1483 CSR_API(SrvSetConsoleCursorMode
)
1485 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1486 return STATUS_NOT_IMPLEMENTED
;
1489 CSR_API(SrvGetConsoleCursorMode
)
1491 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1492 return STATUS_NOT_IMPLEMENTED
;
1495 CSR_API(SrvGetConsoleNlsMode
)
1497 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1498 return STATUS_NOT_IMPLEMENTED
;
1501 CSR_API(SrvSetConsoleNlsMode
)
1503 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1504 return STATUS_NOT_IMPLEMENTED
;
1507 CSR_API(SrvGetConsoleLangId
)
1509 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1510 return STATUS_NOT_IMPLEMENTED
;