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 /* This is for COM usage */
28 /* GLOBALS ********************************************************************/
30 /* The list of the ConSrv consoles */
31 static ULONG ConsoleListSize
;
32 static PCONSRV_CONSOLE
* ConsoleList
;
33 static RTL_RESOURCE ListLock
;
35 #define ConSrvLockConsoleListExclusive() \
36 RtlAcquireResourceExclusive(&ListLock, TRUE)
38 #define ConSrvLockConsoleListShared() \
39 RtlAcquireResourceShared(&ListLock, TRUE)
41 #define ConSrvUnlockConsoleList() \
42 RtlReleaseResource(&ListLock)
46 InsertConsole(OUT PHANDLE Handle
,
47 IN PCONSRV_CONSOLE Console
)
49 #define CONSOLE_HANDLES_INCREMENT 2 * 3
51 NTSTATUS Status
= STATUS_SUCCESS
;
53 PCONSRV_CONSOLE
* Block
;
55 ASSERT( (ConsoleList
== NULL
&& ConsoleListSize
== 0) ||
56 (ConsoleList
!= NULL
&& ConsoleListSize
!= 0) );
58 /* All went right, so add the console to the list */
59 ConSrvLockConsoleListExclusive();
60 DPRINT("Insert in the list\n");
64 for (i
= 0; i
< ConsoleListSize
; i
++)
66 if (ConsoleList
[i
] == NULL
) break;
70 if (i
>= ConsoleListSize
)
72 DPRINT("Creation of a new handles table\n");
73 /* Allocate a new handles table */
74 Block
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
,
76 CONSOLE_HANDLES_INCREMENT
) * sizeof(PCONSRV_CONSOLE
));
79 Status
= STATUS_UNSUCCESSFUL
;
83 /* If we previously had a handles table, free it and use the new one */
86 /* Copy the handles from the old table to the new one */
89 ConsoleListSize
* sizeof(PCONSRV_CONSOLE
));
90 ConsoleFreeHeap(ConsoleList
);
93 ConsoleListSize
+= CONSOLE_HANDLES_INCREMENT
;
96 ConsoleList
[i
] = Console
;
97 *Handle
= ULongToHandle((i
<< 2) | 0x3);
100 /* Unlock the console list and return status */
101 ConSrvUnlockConsoleList();
108 RemoveConsoleByHandle(IN HANDLE Handle
)
110 NTSTATUS Status
= STATUS_SUCCESS
;
111 PCONSRV_CONSOLE Console
;
113 BOOLEAN ValidHandle
= ((HandleToULong(Handle
) & 0x3) == 0x3);
114 ULONG Index
= HandleToULong(Handle
) >> 2;
116 if (!ValidHandle
) return STATUS_INVALID_HANDLE
;
118 ASSERT( (ConsoleList
== NULL
&& ConsoleListSize
== 0) ||
119 (ConsoleList
!= NULL
&& ConsoleListSize
!= 0) );
121 /* Remove the console from the list */
122 ConSrvLockConsoleListExclusive();
124 if (Index
>= ConsoleListSize
||
125 (Console
= ConsoleList
[Index
]) == NULL
)
127 Status
= STATUS_INVALID_HANDLE
;
131 ConsoleList
[Index
] = NULL
;
134 /* Unlock the console list and return status */
135 ConSrvUnlockConsoleList();
141 RemoveConsoleByPointer(IN PCONSRV_CONSOLE Console
)
145 if (!Console
) return STATUS_INVALID_PARAMETER
;
147 ASSERT( (ConsoleList
== NULL
&& ConsoleListSize
== 0) ||
148 (ConsoleList
!= NULL
&& ConsoleListSize
!= 0) );
150 /* Remove the console from the list */
151 ConSrvLockConsoleListExclusive();
155 for (i
= 0; i
< ConsoleListSize
; i
++)
157 if (ConsoleList
[i
] == Console
) ConsoleList
[i
] = NULL
;
161 /* Unlock the console list and return */
162 ConSrvUnlockConsoleList();
163 return STATUS_SUCCESS
;
167 ConSrvValidateConsole(OUT PCONSRV_CONSOLE
* Console
,
168 IN HANDLE ConsoleHandle
,
169 IN CONSOLE_STATE ExpectedState
,
170 IN BOOLEAN LockConsole
)
172 BOOLEAN RetVal
= FALSE
;
173 PCONSRV_CONSOLE ValidatedConsole
;
175 BOOLEAN ValidHandle
= ((HandleToULong(ConsoleHandle
) & 0x3) == 0x3);
176 ULONG Index
= HandleToULong(ConsoleHandle
) >> 2;
178 if (!ValidHandle
) return FALSE
;
180 if (!Console
) return FALSE
;
184 * Forbid creation or deletion of consoles when
185 * checking for the existence of a console.
187 ConSrvLockConsoleListShared();
189 if (Index
>= ConsoleListSize
||
190 (ValidatedConsole
= ConsoleList
[Index
]) == NULL
)
192 /* Unlock the console list and return */
193 ConSrvUnlockConsoleList();
197 ValidatedConsole
= ConsoleList
[Index
];
199 /* Unlock the console list and return */
200 ConSrvUnlockConsoleList();
202 RetVal
= ConDrvValidateConsoleUnsafe((PCONSOLE
)ValidatedConsole
,
205 if (RetVal
) *Console
= ValidatedConsole
;
211 /* PRIVATE FUNCTIONS **********************************************************/
213 // Adapted from reactos/lib/rtl/unicode.c, RtlCreateUnicodeString line 2180
215 ConsoleCreateUnicodeString(IN OUT PUNICODE_STRING UniDest
,
218 SIZE_T Size
= (wcslen(Source
) + 1) * sizeof(WCHAR
);
219 if (Size
> MAXUSHORT
) return FALSE
;
221 UniDest
->Buffer
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, Size
);
222 if (UniDest
->Buffer
== NULL
) return FALSE
;
224 RtlCopyMemory(UniDest
->Buffer
, Source
, Size
);
225 UniDest
->MaximumLength
= (USHORT
)Size
;
226 UniDest
->Length
= (USHORT
)Size
- sizeof(WCHAR
);
231 // Adapted from reactos/lib/rtl/unicode.c, RtlFreeUnicodeString line 431
233 ConsoleFreeUnicodeString(IN PUNICODE_STRING UnicodeString
)
235 if (UnicodeString
->Buffer
)
237 ConsoleFreeHeap(UnicodeString
->Buffer
);
238 RtlZeroMemory(UnicodeString
, sizeof(UNICODE_STRING
));
243 ConioPause(PCONSRV_CONSOLE Console
, UINT Flags
)
245 Console
->PauseFlags
|= Flags
;
246 ConDrvPause((PCONSOLE
)Console
);
250 ConioUnpause(PCONSRV_CONSOLE Console
, UINT Flags
)
252 Console
->PauseFlags
&= ~Flags
;
254 // if ((Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION)) == 0)
255 if (Console
->PauseFlags
== 0)
257 ConDrvUnpause((PCONSOLE
)Console
);
259 CsrNotifyWait(&Console
->WriteWaitQueue
,
263 if (!IsListEmpty(&Console
->WriteWaitQueue
))
265 CsrDereferenceWait(&Console
->WriteWaitQueue
);
271 ConSrvGetConsole(IN PCONSOLE_PROCESS_DATA ProcessData
,
272 OUT PCONSRV_CONSOLE
* Console
,
273 IN BOOLEAN LockConsole
)
275 NTSTATUS Status
= STATUS_INVALID_HANDLE
;
276 PCONSRV_CONSOLE GrabConsole
;
278 // if (Console == NULL) return STATUS_INVALID_PARAMETER;
282 if (ConSrvValidateConsole(&GrabConsole
,
283 ProcessData
->ConsoleHandle
,
287 InterlockedIncrement(&GrabConsole
->ReferenceCount
);
288 *Console
= GrabConsole
;
289 Status
= STATUS_SUCCESS
;
296 ConSrvReleaseConsole(IN PCONSRV_CONSOLE Console
,
297 IN BOOLEAN IsConsoleLocked
)
301 if (!Console
) return;
302 // if (Console->ReferenceCount == 0) return; // This shouldn't happen
303 ASSERT(Console
->ReferenceCount
> 0);
305 /* The console must be locked */
306 // ASSERT(Console_locked);
309 * Decrement the reference count. Save the new value too,
310 * because Console->ReferenceCount might be modified after
311 * the console gets unlocked but before we check whether we
314 RefCount
= _InterlockedDecrement(&Console
->ReferenceCount
);
316 /* Unlock the console if needed */
317 if (IsConsoleLocked
) LeaveCriticalSection(&Console
->Lock
);
319 /* Delete the console if needed */
320 if (RefCount
<= 0) ConSrvDeleteConsole(Console
);
324 /* CONSOLE INITIALIZATION FUNCTIONS *******************************************/
327 ConSrvInitConsoleSupport(VOID
)
329 DPRINT("CONSRV: ConSrvInitConsoleSupport()\n");
331 /* Initialize the console list and its lock */
334 RtlInitializeResource(&ListLock
);
336 /* Should call LoadKeyboardLayout */
340 ConSrvInitTerminal(IN OUT PTERMINAL Terminal
,
341 IN OUT PCONSOLE_STATE_INFO ConsoleInfo
,
342 IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo
,
343 IN HANDLE ConsoleLeaderProcessHandle
);
345 ConSrvDeinitTerminal(IN OUT PTERMINAL Terminal
);
349 LoadShellLinkConsoleInfo(IN OUT PCONSOLE_STATE_INFO ConsoleInfo
,
350 IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo
)
352 #define PATH_SEPARATOR L'\\'
357 LPWSTR LinkName
= NULL
;
358 LPWSTR IconPath
= NULL
;
359 WCHAR Buffer
[MAX_PATH
+ 1];
361 ConsoleInitInfo
->ConsoleStartInfo
->IconIndex
= 0;
363 if ((ConsoleInitInfo
->ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
365 // return FALSE; // FIXME!! (for icon loading)
370 /* 1- Find the last path separator if any */
371 LinkName
= wcsrchr(ConsoleInfo
->ConsoleTitle
, PATH_SEPARATOR
);
372 if (LinkName
== NULL
)
373 LinkName
= ConsoleInfo
->ConsoleTitle
;
375 ++LinkName
; // Skip the path separator
377 /* 2- Check for the link extension. The name ".lnk" is considered invalid. */
378 Length
= wcslen(LinkName
);
379 if ( (Length
<= 4) || (wcsicmp(LinkName
+ (Length
- 4), L
".lnk") != 0) )
382 /* 3- It may be a link. Try to retrieve some properties */
383 hRes
= CoInitialize(NULL
);
386 /* Get a pointer to the IShellLink interface */
387 IShellLinkW
* pshl
= NULL
;
388 hRes
= CoCreateInstance(&CLSID_ShellLink
,
390 CLSCTX_INPROC_SERVER
,
395 /* Get a pointer to the IPersistFile interface */
396 IPersistFile
* ppf
= NULL
;
397 hRes
= IPersistFile_QueryInterface(pshl
, &IID_IPersistFile
, (LPVOID
*)&ppf
);
400 /* Load the shortcut */
401 hRes
= IPersistFile_Load(ppf
, ConsoleInfo
->ConsoleTitle
, STGM_READ
);
405 * Finally we can get the properties !
406 * Update the old ones if needed.
411 /* Reset the name of the console with the name of the shortcut */
412 Length
= min(/*Length*/ Length
- 4, // 4 == len(".lnk")
413 (ConsoleInfo
->cbSize
- FIELD_OFFSET(CONSOLE_STATE_INFO
, ConsoleTitle
) - sizeof(UNICODE_NULL
)) / sizeof(WCHAR
));
414 wcsncpy(ConsoleInfo
->ConsoleTitle
, LinkName
, Length
);
415 ConsoleInfo
->ConsoleTitle
[Length
] = UNICODE_NULL
;
417 /* Get the window showing command */
418 hRes
= IShellLinkW_GetShowCmd(pshl
, &ShowCmd
);
419 if (SUCCEEDED(hRes
)) ConsoleInitInfo
->ConsoleStartInfo
->wShowWindow
= (WORD
)ShowCmd
;
422 // hRes = pshl->GetHotkey(&ShowCmd);
423 // if (SUCCEEDED(hRes)) ConsoleInitInfo->ConsoleStartInfo->HotKey = HotKey;
425 /* Get the icon location, if any */
426 hRes
= IShellLinkW_GetIconLocation(pshl
,
428 sizeof(Buffer
)/sizeof(Buffer
[0]) - 1, // == MAX_PATH
429 &ConsoleInitInfo
->ConsoleStartInfo
->IconIndex
);
430 if (!SUCCEEDED(hRes
))
432 ConsoleInitInfo
->ConsoleStartInfo
->IconIndex
= 0;
439 // FIXME: Since we still don't load console properties from the shortcut,
440 // return false. When this will be done, we will return true instead.
441 RetVal
= TRUE
; // FALSE;
443 IPersistFile_Release(ppf
);
445 IShellLinkW_Release(pshl
);
454 /* Get the associated icon, if any */
455 if (IconPath
== NULL
)
457 // Question: How to retrieve the full path name
458 // of the app we are going to run??
459 Length
= RtlDosSearchPath_U(ConsoleInitInfo
->CurDir
,
460 ConsoleInitInfo
->AppName
,
465 if (Length
> 0 && Length
< sizeof(Buffer
))
468 IconPath
= ConsoleInitInfo
->AppName
;
470 // ConsoleInitInfo->ConsoleStartInfo->IconIndex = 0;
472 DPRINT("IconPath = '%S' ; IconIndex = %lu\n",
473 IconPath
, ConsoleInitInfo
->ConsoleStartInfo
->IconIndex
);
474 if (IconPath
&& *IconPath
)
476 HICON hIcon
= NULL
, hIconSm
= NULL
;
478 * FIXME!! Because of a strange bug we have in PrivateExtractIconExW
479 * (see r65683 for more details), we cannot use this API to extract
480 * at the same time the large and small icons from the app.
481 * Instead we just use PrivateExtractIconsW.
483 PrivateExtractIconExW(IconPath,
484 ConsoleInitInfo->ConsoleStartInfo->IconIndex,
489 PrivateExtractIconsW(IconPath
,
490 ConsoleInitInfo
->ConsoleStartInfo
->IconIndex
,
492 &hIcon
, NULL
, 1, LR_COPYFROMRESOURCE
);
493 PrivateExtractIconsW(IconPath
,
494 ConsoleInitInfo
->ConsoleStartInfo
->IconIndex
,
496 &hIconSm
, NULL
, 1, LR_COPYFROMRESOURCE
);
498 DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon
, hIconSm
);
499 if (hIcon
!= NULL
) ConsoleInitInfo
->ConsoleStartInfo
->hIcon
= hIcon
;
500 if (hIconSm
!= NULL
) ConsoleInitInfo
->ConsoleStartInfo
->hIconSm
= hIconSm
;
504 // FIXME: See the previous FIXME above.
511 ConSrvInitConsole(OUT PHANDLE NewConsoleHandle
,
512 OUT PCONSRV_CONSOLE
* NewConsole
,
513 IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo
,
514 IN PCSR_PROCESS ConsoleLeaderProcess
)
517 HANDLE ConsoleHandle
;
518 PCONSRV_CONSOLE Console
;
520 BYTE ConsoleInfoBuffer
[sizeof(CONSOLE_STATE_INFO
) + MAX_PATH
* sizeof(WCHAR
)]; // CONSRV console information
521 PCONSOLE_STATE_INFO ConsoleInfo
= (PCONSOLE_STATE_INFO
)&ConsoleInfoBuffer
;
522 CONSOLE_INFO DrvConsoleInfo
; // Console information for CONDRV
526 TERMINAL Terminal
; /* The ConSrv terminal for this console */
528 if (NewConsole
== NULL
|| ConsoleInitInfo
== NULL
)
529 return STATUS_INVALID_PARAMETER
;
534 * Load the console settings
536 RtlZeroMemory(ConsoleInfo
, sizeof(ConsoleInfoBuffer
));
537 ConsoleInfo
->cbSize
= sizeof(ConsoleInfoBuffer
);
539 /* 1. Get the title of the console (initialize ConsoleInfo->ConsoleTitle) */
540 Length
= min(ConsoleInitInfo
->TitleLength
,
541 (ConsoleInfo
->cbSize
- FIELD_OFFSET(CONSOLE_STATE_INFO
, ConsoleTitle
) - sizeof(UNICODE_NULL
)) / sizeof(WCHAR
));
542 wcsncpy(ConsoleInfo
->ConsoleTitle
, ConsoleInitInfo
->ConsoleTitle
, Length
);
543 ConsoleInfo
->ConsoleTitle
[Length
] = UNICODE_NULL
; // NULL-terminate it.
545 /* 2. Impersonate the caller in order to retrieve settings in its context */
546 if (!CsrImpersonateClient(NULL
))
547 return STATUS_BAD_IMPERSONATION_LEVEL
;
549 /* 3. Load the default settings */
550 ConCfgGetDefaultSettings(ConsoleInfo
);
553 * 4. Load per-application terminal settings.
555 * Check whether the process creating the console was launched via
556 * a shell-link. ConsoleInfo->ConsoleTitle may be updated with the
557 * name of the shortcut, and ConsoleStartInfo->Icon[Path|Index] too.
559 // if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) // FIXME!! (for icon loading)
561 if (!LoadShellLinkConsoleInfo(ConsoleInfo
, ConsoleInitInfo
))
563 ConsoleInitInfo
->ConsoleStartInfo
->dwStartupFlags
&= ~STARTF_TITLEISLINKNAME
;
568 * 5. Load the remaining console settings via the registry.
570 if ((ConsoleInitInfo
->ConsoleStartInfo
->dwStartupFlags
& STARTF_TITLEISLINKNAME
) == 0)
573 * Either we weren't created by an app launched via a shell-link,
574 * or we failed to load shell-link console properties.
575 * Therefore, load the console infos for the application from the registry.
577 ConCfgReadUserSettings(ConsoleInfo
, FALSE
);
580 * Now, update them with the properties the user might gave to us
581 * via the STARTUPINFO structure before calling CreateProcess
582 * (and which was transmitted via the ConsoleStartInfo structure).
583 * We therefore overwrite the values read in the registry.
585 if (ConsoleInitInfo
->ConsoleStartInfo
->dwStartupFlags
& STARTF_USEFILLATTRIBUTE
)
587 ConsoleInfo
->ScreenAttributes
= (USHORT
)ConsoleInitInfo
->ConsoleStartInfo
->wFillAttribute
;
589 if (ConsoleInitInfo
->ConsoleStartInfo
->dwStartupFlags
& STARTF_USECOUNTCHARS
)
591 ConsoleInfo
->ScreenBufferSize
= ConsoleInitInfo
->ConsoleStartInfo
->dwScreenBufferSize
;
593 if (ConsoleInitInfo
->ConsoleStartInfo
->dwStartupFlags
& STARTF_USESIZE
)
595 ConsoleInfo
->WindowSize
= ConsoleInitInfo
->ConsoleStartInfo
->dwWindowSize
;
600 * Now, update them with the properties the user might gave to us
601 * via the STARTUPINFO structure before calling CreateProcess
602 * (and which was transmitted via the ConsoleStartInfo structure).
603 * We therefore overwrite the values read in the registry.
605 if (ConsoleInitInfo
->ConsoleStartInfo
->dwStartupFlags
& STARTF_USEPOSITION
)
607 ConsoleInfo
->AutoPosition
= FALSE
;
608 ConsoleInfo
->WindowPosition
.x
= ConsoleInitInfo
->ConsoleStartInfo
->dwWindowOrigin
.X
;
609 ConsoleInfo
->WindowPosition
.y
= ConsoleInitInfo
->ConsoleStartInfo
->dwWindowOrigin
.Y
;
611 if (ConsoleInitInfo
->ConsoleStartInfo
->dwStartupFlags
& STARTF_RUNFULLSCREEN
)
613 ConsoleInfo
->FullScreen
= TRUE
;
618 /* 6. Revert impersonation */
621 /* Set-up the code page */
622 ConsoleInfo
->CodePage
= GetOEMCP();
625 * Initialize the ConSrv terminal and give it a chance to load
626 * its own settings and override the console settings.
628 Status
= ConSrvInitTerminal(&Terminal
,
631 ConsoleLeaderProcess
->ProcessHandle
);
632 if (!NT_SUCCESS(Status
))
634 DPRINT1("CONSRV: Failed to initialize a terminal, Status = 0x%08lx\n", Status
);
637 DPRINT("CONSRV: Terminal initialized\n");
639 /* Initialize a new console via the driver */
640 // DrvConsoleInfo.InputBufferSize = 0;
641 DrvConsoleInfo
.ScreenBufferSize
= ConsoleInfo
->ScreenBufferSize
;
642 DrvConsoleInfo
.ConsoleSize
= ConsoleInfo
->WindowSize
;
643 DrvConsoleInfo
.CursorSize
= ConsoleInfo
->CursorSize
;
644 // DrvConsoleInfo.CursorBlinkOn = ConsoleInfo->CursorBlinkOn;
645 DrvConsoleInfo
.ScreenAttrib
= ConsoleInfo
->ScreenAttributes
;
646 DrvConsoleInfo
.PopupAttrib
= ConsoleInfo
->PopupAttributes
;
647 DrvConsoleInfo
.CodePage
= ConsoleInfo
->CodePage
;
648 Status
= ConDrvInitConsole(&Console
, &DrvConsoleInfo
);
649 if (!NT_SUCCESS(Status
))
651 DPRINT1("Creating a new console failed, Status = 0x%08lx\n", Status
);
652 ConSrvDeinitTerminal(&Terminal
);
657 DPRINT("Console initialized\n");
659 /*** Register ConSrv features ***/
661 /* Initialize the console title */
663 WCHAR DefaultTitle
[128];
665 ConsoleCreateUnicodeString(&Console
->OriginalTitle
, ConsoleInfo
->ConsoleTitle
);
667 if (ConsoleInfo
->ConsoleTitle
[0] == UNICODE_NULL
)
669 if (LoadStringW(ConSrvDllInstance
, IDS_CONSOLE_TITLE
, DefaultTitle
, sizeof(DefaultTitle
) / sizeof(DefaultTitle
[0])))
671 ConsoleCreateUnicodeString(&Console
->Title
, DefaultTitle
);
675 ConsoleCreateUnicodeString(&Console
->Title
, L
"ReactOS Console");
681 ConsoleCreateUnicodeString(&Console
->Title
, ConsoleInfo
->ConsoleTitle
);
686 /* Initialize process support */
687 InitializeListHead(&Console
->ProcessList
);
688 Console
->NotifiedLastCloseProcess
= NULL
;
689 Console
->NotifyLastClose
= FALSE
;
690 Console
->HasFocus
= FALSE
;
692 /* Initialize pausing support */
693 Console
->PauseFlags
= 0;
694 InitializeListHead(&Console
->ReadWaitQueue
);
695 InitializeListHead(&Console
->WriteWaitQueue
);
697 /* Initialize the alias and history buffers */
698 Console
->Aliases
= NULL
;
699 InitializeListHead(&Console
->HistoryBuffers
);
700 Console
->HistoryBufferSize
= ConsoleInfo
->HistoryBufferSize
;
701 Console
->NumberOfHistoryBuffers
= ConsoleInfo
->NumberOfHistoryBuffers
;
702 Console
->HistoryNoDup
= ConsoleInfo
->HistoryNoDup
;
704 /* Initialize the Input Line Discipline */
705 Console
->LineBuffer
= NULL
;
706 Console
->LinePos
= Console
->LineMaxSize
= Console
->LineSize
= 0;
707 Console
->LineComplete
= Console
->LineUpPressed
= FALSE
;
709 Console
->LineInsertToggle
=
710 Console
->InsertMode
= ConsoleInfo
->InsertMode
;
711 Console
->QuickEdit
= ConsoleInfo
->QuickEdit
;
714 InitializeListHead(&Console
->PopupWindows
);
717 RtlCopyMemory(Console
->Colors
, ConsoleInfo
->ColorTable
,
718 sizeof(ConsoleInfo
->ColorTable
));
720 /* Create the Initialization Events */
721 Status
= NtCreateEvent(&Console
->InitEvents
[INIT_SUCCESS
], EVENT_ALL_ACCESS
,
722 NULL
, NotificationEvent
, FALSE
);
723 if (!NT_SUCCESS(Status
))
725 DPRINT1("NtCreateEvent(InitEvents[INIT_SUCCESS]) failed: %lu\n", Status
);
726 ConDrvDeleteConsole(Console
);
727 ConSrvDeinitTerminal(&Terminal
);
730 Status
= NtCreateEvent(&Console
->InitEvents
[INIT_FAILURE
], EVENT_ALL_ACCESS
,
731 NULL
, NotificationEvent
, FALSE
);
732 if (!NT_SUCCESS(Status
))
734 DPRINT1("NtCreateEvent(InitEvents[INIT_FAILURE]) failed: %lu\n", Status
);
735 NtClose(Console
->InitEvents
[INIT_SUCCESS
]);
736 ConDrvDeleteConsole(Console
);
737 ConSrvDeinitTerminal(&Terminal
);
742 * Attach the ConSrv terminal to the console.
743 * This call makes a copy of our local Terminal variable.
745 Status
= ConDrvAttachTerminal(Console
, &Terminal
);
746 if (!NT_SUCCESS(Status
))
748 DPRINT1("Failed to register terminal to the given console, Status = 0x%08lx\n", Status
);
749 NtClose(Console
->InitEvents
[INIT_FAILURE
]);
750 NtClose(Console
->InitEvents
[INIT_SUCCESS
]);
751 ConDrvDeleteConsole(Console
);
752 ConSrvDeinitTerminal(&Terminal
);
755 DPRINT("Terminal attached\n");
757 /* All went right, so add the console to the list */
758 Status
= InsertConsole(&ConsoleHandle
, Console
);
760 // FIXME! We do not support at all asynchronous console creation!
761 NtSetEvent(Console
->InitEvents
[INIT_SUCCESS
], NULL
);
762 // NtSetEvent(Console->InitEvents[INIT_FAILURE], NULL);
764 /* Return the newly created console to the caller and a success code too */
765 *NewConsoleHandle
= ConsoleHandle
;
766 *NewConsole
= Console
;
767 return STATUS_SUCCESS
;
771 ConSrvDeleteConsole(PCONSRV_CONSOLE Console
)
773 DPRINT("ConSrvDeleteConsole\n");
775 // FIXME: Send a terminate message to all the processes owning this console
777 /* Remove the console from the list */
778 RemoveConsoleByPointer(Console
);
780 /* Destroy the Initialization Events */
781 NtClose(Console
->InitEvents
[INIT_FAILURE
]);
782 NtClose(Console
->InitEvents
[INIT_SUCCESS
]);
784 /* Clean the Input Line Discipline */
785 if (Console
->LineBuffer
) ConsoleFreeHeap(Console
->LineBuffer
);
787 /* Clean aliases and history */
788 IntDeleteAllAliases(Console
);
789 HistoryDeleteBuffers(Console
);
791 /* Free the console title */
792 ConsoleFreeUnicodeString(&Console
->OriginalTitle
);
793 ConsoleFreeUnicodeString(&Console
->Title
);
795 /* Now, call the driver. ConDrvDetachTerminal is called on-demand. */
796 ConDrvDeleteConsole((PCONSOLE
)Console
);
798 /* Deinit the ConSrv terminal */
800 // ConSrvDeinitTerminal(&Terminal);
809 ConSrvConsoleCtrlEventTimeout(IN ULONG CtrlEvent
,
810 IN PCONSOLE_PROCESS_DATA ProcessData
,
813 NTSTATUS Status
= STATUS_SUCCESS
;
815 DPRINT("ConSrvConsoleCtrlEventTimeout Parent ProcessId = %x\n", ProcessData
->Process
->ClientId
.UniqueProcess
);
818 * Be sure we effectively have a control routine. It resides in kernel32.dll (client).
820 if (ProcessData
->CtrlRoutine
== NULL
) return Status
;
824 HANDLE Thread
= NULL
;
828 Thread
= CreateRemoteThread(ProcessData
->Process
->ProcessHandle
, NULL
, 0,
829 ProcessData
->CtrlRoutine
,
830 UlongToPtr(CtrlEvent
), 0, NULL
);
833 Status
= RtlGetLastNtStatus();
834 DPRINT1("Failed thread creation, Status = 0x%08lx\n", Status
);
838 DPRINT("ProcessData->CtrlRoutine remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n",
839 ProcessData
->Process
->ClientId
.UniqueProcess
, ProcessData
->Process
);
840 WaitForSingleObject(Thread
, Timeout
);
849 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
851 Status
= _SEH2_GetExceptionCode();
852 DPRINT1("ConSrvConsoleCtrlEventTimeout - Caught an exception, Status = 0x%08lx\n", Status
);
860 ConSrvConsoleCtrlEvent(IN ULONG CtrlEvent
,
861 IN PCONSOLE_PROCESS_DATA ProcessData
)
863 return ConSrvConsoleCtrlEventTimeout(CtrlEvent
, ProcessData
, 0);
866 PCONSOLE_PROCESS_DATA NTAPI
867 ConSrvGetConsoleLeaderProcess(IN PCONSRV_CONSOLE Console
)
869 if (Console
== NULL
) return NULL
;
871 return CONTAINING_RECORD(Console
->ProcessList
.Blink
,
872 CONSOLE_PROCESS_DATA
,
877 ConSrvGetConsoleProcessList(IN PCONSRV_CONSOLE Console
,
878 IN OUT PULONG ProcessIdsList
,
879 IN ULONG MaxIdListItems
,
880 OUT PULONG ProcessIdsTotal
)
882 PCONSOLE_PROCESS_DATA current
;
883 PLIST_ENTRY current_entry
;
885 if (Console
== NULL
|| ProcessIdsList
== NULL
|| ProcessIdsTotal
== NULL
)
886 return STATUS_INVALID_PARAMETER
;
888 *ProcessIdsTotal
= 0;
890 for (current_entry
= Console
->ProcessList
.Flink
;
891 current_entry
!= &Console
->ProcessList
;
892 current_entry
= current_entry
->Flink
)
894 current
= CONTAINING_RECORD(current_entry
, CONSOLE_PROCESS_DATA
, ConsoleLink
);
895 if (++(*ProcessIdsTotal
) <= MaxIdListItems
)
897 *ProcessIdsList
++ = HandleToUlong(current
->Process
->ClientId
.UniqueProcess
);
901 return STATUS_SUCCESS
;
904 // ConSrvGenerateConsoleCtrlEvent
906 ConSrvConsoleProcessCtrlEvent(IN PCONSRV_CONSOLE Console
,
907 IN ULONG ProcessGroupId
,
910 NTSTATUS Status
= STATUS_SUCCESS
;
911 PLIST_ENTRY current_entry
;
912 PCONSOLE_PROCESS_DATA current
;
914 /* If the console is already being destroyed, just return */
915 if (!ConDrvValidateConsoleState((PCONSOLE
)Console
, CONSOLE_RUNNING
))
916 return STATUS_UNSUCCESSFUL
;
919 * Loop through the process list, from the most recent process
920 * (the active one) to the oldest one (the first created, i.e.
921 * the console leader process), and for each, send an event
922 * (new processes are inserted at the head of the console process list).
924 current_entry
= Console
->ProcessList
.Flink
;
925 while (current_entry
!= &Console
->ProcessList
)
927 current
= CONTAINING_RECORD(current_entry
, CONSOLE_PROCESS_DATA
, ConsoleLink
);
928 current_entry
= current_entry
->Flink
;
931 * Only processes belonging to the same process group are signaled.
932 * If the process group ID is zero, then all the processes are signaled.
934 if (ProcessGroupId
== 0 || current
->Process
->ProcessGroupId
== ProcessGroupId
)
936 Status
= ConSrvConsoleCtrlEvent(CtrlEvent
, current
);
944 ConSrvSetProcessFocus(IN PCSR_PROCESS CsrProcess
,
945 IN BOOLEAN SetForeground
)
947 // FIXME: Call NtUserSetInformationProcess (currently unimplemented!)
948 // for setting Win32 foreground/background flags.
951 CsrSetForegroundPriority(CsrProcess
);
953 CsrSetBackgroundPriority(CsrProcess
);
957 ConSrvSetConsoleProcessFocus(IN PCONSRV_CONSOLE Console
,
958 IN BOOLEAN SetForeground
)
960 PLIST_ENTRY current_entry
;
961 PCONSOLE_PROCESS_DATA current
;
963 /* If the console is already being destroyed, just return */
964 if (!ConDrvValidateConsoleState((PCONSOLE
)Console
, CONSOLE_RUNNING
))
965 return STATUS_UNSUCCESSFUL
;
968 * Loop through the process list, from the most recent process
969 * to the oldest one, and for each, set its foreground priority.
971 current_entry
= Console
->ProcessList
.Flink
;
972 while (current_entry
!= &Console
->ProcessList
)
974 current
= CONTAINING_RECORD(current_entry
, CONSOLE_PROCESS_DATA
, ConsoleLink
);
975 current_entry
= current_entry
->Flink
;
977 ConSrvSetProcessFocus(current
->Process
, SetForeground
);
980 return STATUS_SUCCESS
;
984 /* PUBLIC SERVER APIS *********************************************************/
986 CSR_API(SrvAllocConsole
)
988 NTSTATUS Status
= STATUS_SUCCESS
;
989 PCONSOLE_ALLOCCONSOLE AllocConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.AllocConsoleRequest
;
990 PCSR_PROCESS CsrProcess
= CsrGetClientThread()->Process
;
991 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrProcess
);
992 CONSOLE_INIT_INFO ConsoleInitInfo
;
994 if (ProcessData
->ConsoleHandle
!= NULL
)
996 DPRINT1("Process already has a console\n");
997 return STATUS_ACCESS_DENIED
;
1000 if ( !CsrValidateMessageBuffer(ApiMessage
,
1001 (PVOID
*)&AllocConsoleRequest
->ConsoleStartInfo
,
1003 sizeof(CONSOLE_START_INFO
)) ||
1004 !CsrValidateMessageBuffer(ApiMessage
,
1005 (PVOID
*)&AllocConsoleRequest
->ConsoleTitle
,
1006 AllocConsoleRequest
->TitleLength
,
1008 !CsrValidateMessageBuffer(ApiMessage
,
1009 (PVOID
*)&AllocConsoleRequest
->Desktop
,
1010 AllocConsoleRequest
->DesktopLength
,
1012 !CsrValidateMessageBuffer(ApiMessage
,
1013 (PVOID
*)&AllocConsoleRequest
->CurDir
,
1014 AllocConsoleRequest
->CurDirLength
,
1016 !CsrValidateMessageBuffer(ApiMessage
,
1017 (PVOID
*)&AllocConsoleRequest
->AppName
,
1018 AllocConsoleRequest
->AppNameLength
,
1021 return STATUS_INVALID_PARAMETER
;
1024 /* Initialize the console initialization info structure */
1025 ConsoleInitInfo
.ConsoleStartInfo
= AllocConsoleRequest
->ConsoleStartInfo
;
1026 ConsoleInitInfo
.IsWindowVisible
= TRUE
; // The console window is always visible.
1027 ConsoleInitInfo
.TitleLength
= AllocConsoleRequest
->TitleLength
;
1028 ConsoleInitInfo
.ConsoleTitle
= AllocConsoleRequest
->ConsoleTitle
;
1029 ConsoleInitInfo
.DesktopLength
= AllocConsoleRequest
->DesktopLength
;
1030 ConsoleInitInfo
.Desktop
= AllocConsoleRequest
->Desktop
;
1031 ConsoleInitInfo
.AppNameLength
= AllocConsoleRequest
->AppNameLength
;
1032 ConsoleInitInfo
.AppName
= AllocConsoleRequest
->AppName
;
1033 ConsoleInitInfo
.CurDirLength
= AllocConsoleRequest
->CurDirLength
;
1034 ConsoleInitInfo
.CurDir
= AllocConsoleRequest
->CurDir
;
1036 /* Initialize a new Console owned by the Console Leader Process */
1037 Status
= ConSrvAllocateConsole(ProcessData
,
1038 &AllocConsoleRequest
->ConsoleStartInfo
->InputHandle
,
1039 &AllocConsoleRequest
->ConsoleStartInfo
->OutputHandle
,
1040 &AllocConsoleRequest
->ConsoleStartInfo
->ErrorHandle
,
1042 if (!NT_SUCCESS(Status
))
1044 DPRINT1("Console allocation failed\n");
1048 /* Set the Property-Dialog and Control-Dispatcher handlers */
1049 ProcessData
->PropRoutine
= AllocConsoleRequest
->PropRoutine
;
1050 ProcessData
->CtrlRoutine
= AllocConsoleRequest
->CtrlRoutine
;
1052 return STATUS_SUCCESS
;
1055 CSR_API(SrvAttachConsole
)
1057 NTSTATUS Status
= STATUS_SUCCESS
;
1058 PCONSOLE_ATTACHCONSOLE AttachConsoleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.AttachConsoleRequest
;
1059 PCSR_PROCESS SourceProcess
= NULL
; // The parent process.
1060 PCSR_PROCESS TargetProcess
= CsrGetClientThread()->Process
; // Ourselves.
1061 HANDLE ProcessId
= ULongToHandle(AttachConsoleRequest
->ProcessId
);
1062 PCONSOLE_PROCESS_DATA SourceProcessData
, TargetProcessData
;
1064 TargetProcessData
= ConsoleGetPerProcessData(TargetProcess
);
1066 if (TargetProcessData
->ConsoleHandle
!= NULL
)
1068 DPRINT1("Process already has a console\n");
1069 return STATUS_ACCESS_DENIED
;
1072 if (!CsrValidateMessageBuffer(ApiMessage
,
1073 (PVOID
*)&AttachConsoleRequest
->ConsoleStartInfo
,
1075 sizeof(CONSOLE_START_INFO
)))
1077 return STATUS_INVALID_PARAMETER
;
1080 /* Check whether we try to attach to the parent's console */
1081 if (ProcessId
== ULongToHandle(ATTACH_PARENT_PROCESS
))
1083 PROCESS_BASIC_INFORMATION ProcessInfo
;
1084 ULONG Length
= sizeof(ProcessInfo
);
1086 /* Get the real parent's PID */
1088 Status
= NtQueryInformationProcess(TargetProcess
->ProcessHandle
,
1089 ProcessBasicInformation
,
1092 if (!NT_SUCCESS(Status
))
1094 DPRINT1("SrvAttachConsole - Cannot retrieve basic process info, Status = 0x%08lx\n", Status
);
1098 ProcessId
= ULongToHandle(ProcessInfo
.InheritedFromUniqueProcessId
);
1101 /* Lock the source process via its PID */
1102 Status
= CsrLockProcessByClientId(ProcessId
, &SourceProcess
);
1103 if (!NT_SUCCESS(Status
)) return Status
;
1105 SourceProcessData
= ConsoleGetPerProcessData(SourceProcess
);
1107 if (SourceProcessData
->ConsoleHandle
== NULL
)
1109 Status
= STATUS_INVALID_HANDLE
;
1114 * Inherit the console from the parent,
1115 * if any, otherwise return an error.
1117 Status
= ConSrvInheritConsole(TargetProcessData
,
1118 SourceProcessData
->ConsoleHandle
,
1120 &AttachConsoleRequest
->ConsoleStartInfo
->InputHandle
,
1121 &AttachConsoleRequest
->ConsoleStartInfo
->OutputHandle
,
1122 &AttachConsoleRequest
->ConsoleStartInfo
->ErrorHandle
,
1123 AttachConsoleRequest
->ConsoleStartInfo
);
1124 if (!NT_SUCCESS(Status
))
1126 DPRINT1("Console inheritance failed\n");
1130 /* Set the Property-Dialog and Control-Dispatcher handlers */
1131 TargetProcessData
->PropRoutine
= AttachConsoleRequest
->PropRoutine
;
1132 TargetProcessData
->CtrlRoutine
= AttachConsoleRequest
->CtrlRoutine
;
1134 Status
= STATUS_SUCCESS
;
1137 /* Unlock the "source" process and exit */
1138 CsrUnlockProcess(SourceProcess
);
1142 CSR_API(SrvFreeConsole
)
1144 return ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
));
1148 ConDrvGetConsoleMode(IN PCONSOLE Console
,
1149 IN PCONSOLE_IO_OBJECT Object
,
1150 OUT PULONG ConsoleMode
);
1151 CSR_API(SrvGetConsoleMode
)
1154 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleModeRequest
;
1155 PCONSOLE_IO_OBJECT Object
;
1157 PULONG ConsoleMode
= &ConsoleModeRequest
->Mode
;
1159 Status
= ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
1160 ConsoleModeRequest
->Handle
,
1161 &Object
, NULL
, GENERIC_READ
, TRUE
, 0);
1162 if (!NT_SUCCESS(Status
)) return Status
;
1164 /* Get the standard console modes */
1165 Status
= ConDrvGetConsoleMode(Object
->Console
, Object
,
1167 if (NT_SUCCESS(Status
))
1170 * If getting the console modes succeeds, then retrieve
1171 * the extended CONSRV-specific input modes.
1173 if (INPUT_BUFFER
== Object
->Type
)
1175 if (Object
->Console
->InsertMode
|| Object
->Console
->QuickEdit
)
1177 /* Windows also adds ENABLE_EXTENDED_FLAGS, even if it's not documented on MSDN */
1178 *ConsoleMode
|= ENABLE_EXTENDED_FLAGS
;
1180 if (Object
->Console
->InsertMode
) *ConsoleMode
|= ENABLE_INSERT_MODE
;
1181 if (Object
->Console
->QuickEdit
) *ConsoleMode
|= ENABLE_QUICK_EDIT_MODE
;
1186 ConSrvReleaseObject(Object
, TRUE
);
1191 ConDrvSetConsoleMode(IN PCONSOLE Console
,
1192 IN PCONSOLE_IO_OBJECT Object
,
1193 IN ULONG ConsoleMode
);
1194 CSR_API(SrvSetConsoleMode
)
1196 #define CONSOLE_VALID_CONTROL_MODES ( ENABLE_EXTENDED_FLAGS | \
1197 ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE )
1200 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ConsoleModeRequest
;
1201 PCONSOLE_IO_OBJECT Object
;
1203 ULONG ConsoleMode
= ConsoleModeRequest
->Mode
;
1205 Status
= ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process
),
1206 ConsoleModeRequest
->Handle
,
1207 &Object
, NULL
, GENERIC_WRITE
, TRUE
, 0);
1208 if (!NT_SUCCESS(Status
)) return Status
;
1210 /* Set the standard console modes (without the CONSRV-specific input modes) */
1211 ConsoleMode
&= ~CONSOLE_VALID_CONTROL_MODES
; // Remove CONSRV-specific input modes.
1212 Status
= ConDrvSetConsoleMode(Object
->Console
, Object
,
1214 if (NT_SUCCESS(Status
))
1217 * If setting the console modes succeeds, then set
1218 * the extended CONSRV-specific input modes.
1220 if (INPUT_BUFFER
== Object
->Type
)
1222 ConsoleMode
= ConsoleModeRequest
->Mode
;
1224 if (ConsoleMode
& CONSOLE_VALID_CONTROL_MODES
)
1227 * If we use control mode flags without ENABLE_EXTENDED_FLAGS,
1228 * then consider the flags invalid.
1230 if ((ConsoleMode
& ENABLE_EXTENDED_FLAGS
) == 0)
1232 Status
= STATUS_INVALID_PARAMETER
;
1236 Object
->Console
->InsertMode
= !!(ConsoleMode
& ENABLE_INSERT_MODE
);
1237 Object
->Console
->QuickEdit
= !!(ConsoleMode
& ENABLE_QUICK_EDIT_MODE
);
1243 ConSrvReleaseObject(Object
, TRUE
);
1247 CSR_API(SrvGetConsoleTitle
)
1250 PCONSOLE_GETSETCONSOLETITLE TitleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.TitleRequest
;
1251 PCONSRV_CONSOLE Console
;
1254 if (!CsrValidateMessageBuffer(ApiMessage
,
1255 (PVOID
)&TitleRequest
->Title
,
1256 TitleRequest
->Length
,
1259 return STATUS_INVALID_PARAMETER
;
1262 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1263 if (!NT_SUCCESS(Status
))
1265 DPRINT1("Can't get console, status %lx\n", Status
);
1269 /* Copy title of the console to the user title buffer */
1270 if (TitleRequest
->Unicode
)
1272 if (TitleRequest
->Length
>= sizeof(WCHAR
))
1274 Length
= min(TitleRequest
->Length
- sizeof(WCHAR
), Console
->Title
.Length
);
1275 RtlCopyMemory(TitleRequest
->Title
, Console
->Title
.Buffer
, Length
);
1276 ((PWCHAR
)TitleRequest
->Title
)[Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1277 TitleRequest
->Length
= Length
;
1281 TitleRequest
->Length
= Console
->Title
.Length
;
1286 if (TitleRequest
->Length
>= sizeof(CHAR
))
1288 Length
= min(TitleRequest
->Length
- sizeof(CHAR
), Console
->Title
.Length
/ sizeof(WCHAR
));
1289 Length
= WideCharToMultiByte(Console
->InputCodePage
, 0,
1290 Console
->Title
.Buffer
, Length
,
1291 TitleRequest
->Title
, Length
,
1293 ((PCHAR
)TitleRequest
->Title
)[Length
] = ANSI_NULL
;
1294 TitleRequest
->Length
= Length
;
1298 TitleRequest
->Length
= Console
->Title
.Length
/ sizeof(WCHAR
);
1302 ConSrvReleaseConsole(Console
, TRUE
);
1306 CSR_API(SrvSetConsoleTitle
)
1309 PCONSOLE_GETSETCONSOLETITLE TitleRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.TitleRequest
;
1310 PCONSRV_CONSOLE Console
;
1315 if (!CsrValidateMessageBuffer(ApiMessage
,
1316 (PVOID
)&TitleRequest
->Title
,
1317 TitleRequest
->Length
,
1320 return STATUS_INVALID_PARAMETER
;
1323 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1324 if (!NT_SUCCESS(Status
))
1326 DPRINT1("Can't get console, status %lx\n", Status
);
1330 if (TitleRequest
->Unicode
)
1332 /* Length is in bytes */
1333 Length
= TitleRequest
->Length
;
1337 /* Use the console input CP for the conversion */
1338 Length
= MultiByteToWideChar(Console
->InputCodePage
, 0,
1339 TitleRequest
->Title
, TitleRequest
->Length
,
1341 /* The returned Length was in number of wchars, convert it in bytes */
1342 Length
*= sizeof(WCHAR
);
1345 /* Allocate a new buffer to hold the new title (NULL-terminated) */
1346 Buffer
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, Length
+ sizeof(WCHAR
));
1349 Status
= STATUS_NO_MEMORY
;
1353 /* Free the old title */
1354 ConsoleFreeUnicodeString(&Console
->Title
);
1356 /* Copy title to console */
1357 Console
->Title
.Buffer
= Buffer
;
1358 Console
->Title
.Length
= Length
;
1359 Console
->Title
.MaximumLength
= Console
->Title
.Length
+ sizeof(WCHAR
);
1361 if (TitleRequest
->Unicode
)
1363 RtlCopyMemory(Console
->Title
.Buffer
, TitleRequest
->Title
, Console
->Title
.Length
);
1367 MultiByteToWideChar(Console
->InputCodePage
, 0,
1368 TitleRequest
->Title
, TitleRequest
->Length
,
1369 Console
->Title
.Buffer
,
1370 Console
->Title
.Length
/ sizeof(WCHAR
));
1373 /* NULL-terminate */
1374 Console
->Title
.Buffer
[Console
->Title
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1376 TermChangeTitle(Console
);
1377 Status
= STATUS_SUCCESS
;
1380 ConSrvReleaseConsole(Console
, TRUE
);
1385 ConDrvGetConsoleCP(IN PCONSOLE Console
,
1387 IN BOOLEAN OutputCP
);
1388 CSR_API(SrvGetConsoleCP
)
1391 PCONSOLE_GETINPUTOUTPUTCP GetConsoleCPRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetConsoleCPRequest
;
1392 PCONSRV_CONSOLE Console
;
1394 DPRINT("SrvGetConsoleCP, getting %s Code Page\n",
1395 GetConsoleCPRequest
->OutputCP
? "Output" : "Input");
1397 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1398 if (!NT_SUCCESS(Status
)) return Status
;
1400 Status
= ConDrvGetConsoleCP(Console
,
1401 &GetConsoleCPRequest
->CodePage
,
1402 GetConsoleCPRequest
->OutputCP
);
1404 ConSrvReleaseConsole(Console
, TRUE
);
1409 ConDrvSetConsoleCP(IN PCONSOLE Console
,
1411 IN BOOLEAN OutputCP
);
1412 CSR_API(SrvSetConsoleCP
)
1414 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
1415 PCONSOLE_SETINPUTOUTPUTCP SetConsoleCPRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetConsoleCPRequest
;
1416 PCONSRV_CONSOLE Console
;
1418 DPRINT("SrvSetConsoleCP, setting %s Code Page\n",
1419 SetConsoleCPRequest
->OutputCP
? "Output" : "Input");
1421 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1422 if (!NT_SUCCESS(Status
)) return Status
;
1424 Status
= ConDrvSetConsoleCP(Console
,
1425 SetConsoleCPRequest
->CodePage
,
1426 SetConsoleCPRequest
->OutputCP
);
1428 ConSrvReleaseConsole(Console
, TRUE
);
1432 CSR_API(SrvGetConsoleProcessList
)
1435 PCONSOLE_GETPROCESSLIST GetProcessListRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetProcessListRequest
;
1436 PCONSRV_CONSOLE Console
;
1438 if (!CsrValidateMessageBuffer(ApiMessage
,
1439 (PVOID
)&GetProcessListRequest
->ProcessIdsList
,
1440 GetProcessListRequest
->ProcessCount
,
1443 return STATUS_INVALID_PARAMETER
;
1446 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1447 if (!NT_SUCCESS(Status
)) return Status
;
1449 Status
= ConSrvGetConsoleProcessList(Console
,
1450 GetProcessListRequest
->ProcessIdsList
,
1451 GetProcessListRequest
->ProcessCount
,
1452 &GetProcessListRequest
->ProcessCount
);
1454 ConSrvReleaseConsole(Console
, TRUE
);
1458 CSR_API(SrvGenerateConsoleCtrlEvent
)
1461 PCONSOLE_GENERATECTRLEVENT GenerateCtrlEventRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GenerateCtrlEventRequest
;
1462 PCONSRV_CONSOLE Console
;
1464 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1465 if (!NT_SUCCESS(Status
)) return Status
;
1467 Status
= ConSrvConsoleProcessCtrlEvent(Console
,
1468 GenerateCtrlEventRequest
->ProcessGroupId
,
1469 GenerateCtrlEventRequest
->CtrlEvent
);
1471 ConSrvReleaseConsole(Console
, TRUE
);
1475 CSR_API(SrvConsoleNotifyLastClose
)
1478 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
1479 PCONSRV_CONSOLE Console
;
1481 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
1482 if (!NT_SUCCESS(Status
)) return Status
;
1484 /* Only one process is allowed to be registered for last close notification */
1485 if (!Console
->NotifyLastClose
)
1487 Console
->NotifyLastClose
= TRUE
;
1488 Console
->NotifiedLastCloseProcess
= ProcessData
;
1489 Status
= STATUS_SUCCESS
;
1493 Status
= STATUS_ACCESS_DENIED
;
1496 ConSrvReleaseConsole(Console
, TRUE
);
1502 CSR_API(SrvGetConsoleMouseInfo
)
1505 PCONSOLE_GETMOUSEINFO GetMouseInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetMouseInfoRequest
;
1506 PCONSRV_CONSOLE Console
;
1508 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1509 if (!NT_SUCCESS(Status
)) return Status
;
1511 /* Just retrieve the number of buttons of the mouse attached to this console */
1512 GetMouseInfoRequest
->NumButtons
= GetSystemMetrics(SM_CMOUSEBUTTONS
);
1514 ConSrvReleaseConsole(Console
, TRUE
);
1515 return STATUS_SUCCESS
;
1518 CSR_API(SrvSetConsoleKeyShortcuts
)
1520 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1521 return STATUS_NOT_IMPLEMENTED
;
1524 CSR_API(SrvGetConsoleKeyboardLayoutName
)
1527 PCONSOLE_GETKBDLAYOUTNAME GetKbdLayoutNameRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetKbdLayoutNameRequest
;
1528 PCONSRV_CONSOLE Console
;
1530 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
1531 if (!NT_SUCCESS(Status
)) return Status
;
1533 /* Retrieve the keyboard layout name of the system */
1534 if (GetKbdLayoutNameRequest
->Ansi
)
1535 GetKeyboardLayoutNameA((PCHAR
)GetKbdLayoutNameRequest
->LayoutBuffer
);
1537 GetKeyboardLayoutNameW((PWCHAR
)GetKbdLayoutNameRequest
->LayoutBuffer
);
1539 ConSrvReleaseConsole(Console
, TRUE
);
1540 return STATUS_SUCCESS
;
1543 CSR_API(SrvGetConsoleCharType
)
1545 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1546 return STATUS_NOT_IMPLEMENTED
;
1549 CSR_API(SrvSetConsoleLocalEUDC
)
1551 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1552 return STATUS_NOT_IMPLEMENTED
;
1555 CSR_API(SrvSetConsoleCursorMode
)
1557 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1558 return STATUS_NOT_IMPLEMENTED
;
1561 CSR_API(SrvGetConsoleCursorMode
)
1563 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1564 return STATUS_NOT_IMPLEMENTED
;
1567 CSR_API(SrvGetConsoleNlsMode
)
1569 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1570 return STATUS_NOT_IMPLEMENTED
;
1573 CSR_API(SrvSetConsoleNlsMode
)
1575 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1576 return STATUS_NOT_IMPLEMENTED
;
1579 CSR_API(SrvGetConsoleLangId
)
1581 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
1582 return STATUS_NOT_IMPLEMENTED
;