870432cdd9ba316ad40461fc7608a6468d4ae89a
[reactos.git] / win32ss / user / consrv / console.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/consrv/console.c
5 * PURPOSE: Console Management Functions
6 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #define COBJMACROS
12 #define NONAMELESSUNION
13
14 #include "consrv.h"
15 #include "include/conio.h"
16 #include "conio.h"
17 #include "handle.h"
18 #include "procinit.h"
19 #include "alias.h"
20 #include "coninput.h"
21 #include "conoutput.h"
22 #include "lineinput.h"
23 #include "include/settings.h"
24
25 #include "frontends/gui/guiterm.h"
26
27 #ifdef TUI_CONSOLE
28 #include "frontends/tui/tuiterm.h"
29 #endif
30
31 #include "include/console.h"
32 #include "console.h"
33 #include "resource.h"
34
35 #include <shlwapi.h>
36 #include <shlobj.h>
37
38 #define NDEBUG
39 #include <debug.h>
40
41 /* GLOBALS ********************************************************************/
42
43 static LIST_ENTRY ConsoleList; /* The list of all the allocated consoles */
44 static RTL_RESOURCE ListLock;
45
46 #define ConSrvLockConsoleListExclusive() \
47 RtlAcquireResourceExclusive(&ListLock, TRUE)
48
49 #define ConSrvLockConsoleListShared() \
50 RtlAcquireResourceShared(&ListLock, TRUE)
51
52 #define ConSrvUnlockConsoleList() \
53 RtlReleaseResource(&ListLock)
54
55
56 /* PRIVATE FUNCTIONS **********************************************************/
57
58 #ifdef TUI_CONSOLE
59 static BOOL
60 DtbgIsDesktopVisible(VOID)
61 {
62 return !((BOOL)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE));
63 }
64 #endif
65
66 static ULONG
67 ConSrvConsoleCtrlEventTimeout(DWORD Event,
68 PCONSOLE_PROCESS_DATA ProcessData,
69 DWORD Timeout)
70 {
71 ULONG Status = ERROR_SUCCESS;
72
73 DPRINT("ConSrvConsoleCtrlEventTimeout Parent ProcessId = %x\n", ProcessData->Process->ClientId.UniqueProcess);
74
75 if (ProcessData->CtrlDispatcher)
76 {
77 _SEH2_TRY
78 {
79 HANDLE Thread = NULL;
80
81 _SEH2_TRY
82 {
83 Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0,
84 ProcessData->CtrlDispatcher,
85 UlongToPtr(Event), 0, NULL);
86 if (NULL == Thread)
87 {
88 Status = GetLastError();
89 DPRINT1("Failed thread creation (Error: 0x%x)\n", Status);
90 }
91 else
92 {
93 DPRINT("ProcessData->CtrlDispatcher remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n", ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process);
94 WaitForSingleObject(Thread, Timeout);
95 }
96 }
97 _SEH2_FINALLY
98 {
99 CloseHandle(Thread);
100 }
101 _SEH2_END;
102 }
103 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
104 {
105 Status = RtlNtStatusToDosError(_SEH2_GetExceptionCode());
106 DPRINT1("ConSrvConsoleCtrlEventTimeout - Caught an exception, Status = %08X\n", Status);
107 }
108 _SEH2_END;
109 }
110
111 return Status;
112 }
113
114 static ULONG
115 ConSrvConsoleCtrlEvent(DWORD Event,
116 PCONSOLE_PROCESS_DATA ProcessData)
117 {
118 return ConSrvConsoleCtrlEventTimeout(Event, ProcessData, 0);
119 }
120
121 ULONG FASTCALL
122 ConSrvConsoleProcessCtrlEvent(PCONSOLE Console,
123 ULONG ProcessGroupId,
124 DWORD Event)
125 {
126 ULONG Status = ERROR_SUCCESS;
127 PLIST_ENTRY current_entry;
128 PCONSOLE_PROCESS_DATA current;
129
130 /* If the console is already being destroyed, just return */
131 if (!ConSrvValidateConsole(Console, CONSOLE_RUNNING, FALSE))
132 return STATUS_UNSUCCESSFUL;
133
134 /*
135 * Loop through the process list, from the most recent process
136 * (the active one) to the oldest one (the first created, i.e.
137 * the console leader process), and for each, send an event
138 * (new processes are inserted at the head of the console process list).
139 */
140 current_entry = Console->ProcessList.Flink;
141 while (current_entry != &Console->ProcessList)
142 {
143 current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink);
144 current_entry = current_entry->Flink;
145
146 /*
147 * Only processes belonging to the same process group are signaled.
148 * If the process group ID is zero, then all the processes are signaled.
149 */
150 if (ProcessGroupId == 0 || current->Process->ProcessGroupId == ProcessGroupId)
151 {
152 Status = ConSrvConsoleCtrlEvent(Event, current);
153 }
154 }
155
156 return Status;
157 }
158
159 VOID FASTCALL
160 ConioPause(PCONSOLE Console, UINT Flags)
161 {
162 Console->PauseFlags |= Flags;
163 if (!Console->UnpauseEvent)
164 Console->UnpauseEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
165 }
166
167 VOID FASTCALL
168 ConioUnpause(PCONSOLE Console, UINT Flags)
169 {
170 Console->PauseFlags &= ~Flags;
171
172 // if ((Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION)) == 0)
173 if (Console->PauseFlags == 0 && Console->UnpauseEvent)
174 {
175 SetEvent(Console->UnpauseEvent);
176 CloseHandle(Console->UnpauseEvent);
177 Console->UnpauseEvent = NULL;
178
179 CsrNotifyWait(&Console->WriteWaitQueue,
180 WaitAll,
181 NULL,
182 NULL);
183 if (!IsListEmpty(&Console->WriteWaitQueue))
184 {
185 CsrDereferenceWait(&Console->WriteWaitQueue);
186 }
187 }
188 }
189
190 BOOL FASTCALL
191 ConSrvValidateConsolePointer(PCONSOLE Console)
192 {
193 PLIST_ENTRY ConsoleEntry;
194 PCONSOLE CurrentConsole = NULL;
195
196 if (!Console) return FALSE;
197
198 /* The console list must be locked */
199 // ASSERT(Console_list_locked);
200
201 ConsoleEntry = ConsoleList.Flink;
202 while (ConsoleEntry != &ConsoleList)
203 {
204 CurrentConsole = CONTAINING_RECORD(ConsoleEntry, CONSOLE, Entry);
205 ConsoleEntry = ConsoleEntry->Flink;
206 if (CurrentConsole == Console) return TRUE;
207 }
208
209 return FALSE;
210 }
211
212 BOOL FASTCALL
213 ConSrvValidateConsoleState(PCONSOLE Console,
214 CONSOLE_STATE ExpectedState)
215 {
216 // if (!Console) return FALSE;
217
218 /* The console must be locked */
219 // ASSERT(Console_locked);
220
221 return (Console->State == ExpectedState);
222 }
223
224 BOOL FASTCALL
225 ConSrvValidateConsoleUnsafe(PCONSOLE Console,
226 CONSOLE_STATE ExpectedState,
227 BOOL LockConsole)
228 {
229 if (!Console) return FALSE;
230
231 /*
232 * Lock the console to forbid possible console's state changes
233 * (which must be done when the console is already locked).
234 * If we don't want to lock it, it's because the lock is already
235 * held. So there must be no problems.
236 */
237 if (LockConsole) EnterCriticalSection(&Console->Lock);
238
239 // ASSERT(Console_locked);
240
241 /* Check whether the console's state is what we expect */
242 if (!ConSrvValidateConsoleState(Console, ExpectedState))
243 {
244 if (LockConsole) LeaveCriticalSection(&Console->Lock);
245 return FALSE;
246 }
247
248 return TRUE;
249 }
250
251 BOOL FASTCALL
252 ConSrvValidateConsole(PCONSOLE Console,
253 CONSOLE_STATE ExpectedState,
254 BOOL LockConsole)
255 {
256 BOOL RetVal = FALSE;
257
258 if (!Console) return FALSE;
259
260 /*
261 * Forbid creation or deletion of consoles when
262 * checking for the existence of a console.
263 */
264 ConSrvLockConsoleListShared();
265
266 if (ConSrvValidateConsolePointer(Console))
267 {
268 RetVal = ConSrvValidateConsoleUnsafe(Console,
269 ExpectedState,
270 LockConsole);
271 }
272
273 /* Unlock the console list and return */
274 ConSrvUnlockConsoleList();
275 return RetVal;
276 }
277
278 NTSTATUS
279 FASTCALL
280 ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData,
281 PCONSOLE* Console,
282 BOOL LockConsole)
283 {
284 NTSTATUS Status = STATUS_SUCCESS;
285 PCONSOLE ProcessConsole;
286
287 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
288 ProcessConsole = ProcessData->Console;
289
290 if (ConSrvValidateConsole(ProcessConsole, CONSOLE_RUNNING, LockConsole))
291 {
292 InterlockedIncrement(&ProcessConsole->ReferenceCount);
293 *Console = ProcessConsole;
294 }
295 else
296 {
297 *Console = NULL;
298 Status = STATUS_INVALID_HANDLE;
299 }
300
301 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
302 return Status;
303 }
304
305 VOID FASTCALL
306 ConSrvReleaseConsole(PCONSOLE Console,
307 BOOL WasConsoleLocked)
308 {
309 LONG RefCount = 0;
310
311 if (!Console) return;
312 // if (Console->ReferenceCount == 0) return; // This shouldn't happen
313 ASSERT(Console->ReferenceCount > 0);
314
315 /* The console must be locked */
316 // ASSERT(Console_locked);
317
318 /*
319 * Decrement the reference count. Save the new value too,
320 * because Console->ReferenceCount might be modified after
321 * the console gets unlocked but before we check whether we
322 * can destroy it.
323 */
324 RefCount = _InterlockedDecrement(&Console->ReferenceCount);
325
326 /* Unlock the console if needed */
327 if (WasConsoleLocked) LeaveCriticalSection(&Console->Lock);
328
329 /* Delete the console if needed */
330 if (RefCount <= 0) ConSrvDeleteConsole(Console);
331 }
332
333 VOID WINAPI
334 ConSrvInitConsoleSupport(VOID)
335 {
336 DPRINT("CONSRV: ConSrvInitConsoleSupport()\n");
337
338 /* Initialize the console list and its lock */
339 InitializeListHead(&ConsoleList);
340 RtlInitializeResource(&ListLock);
341
342 /* Should call LoadKeyboardLayout */
343 }
344
345 static BOOL
346 LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo,
347 IN OUT PCONSOLE_INFO ConsoleInfo,
348 OUT LPWSTR IconPath,
349 IN SIZE_T IconPathLength,
350 OUT PINT piIcon)
351 {
352 #define PATH_SEPARATOR L'\\'
353
354 BOOL RetVal = FALSE;
355 LPWSTR LinkName = NULL;
356 SIZE_T Length = 0;
357
358 if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
359 return FALSE;
360
361 if (IconPath == NULL || piIcon == NULL)
362 return FALSE;
363
364 IconPath[0] = L'\0';
365 *piIcon = 0;
366
367 /* 1- Find the last path separator if any */
368 LinkName = wcsrchr(ConsoleStartInfo->ConsoleTitle, PATH_SEPARATOR);
369 if (LinkName == NULL)
370 {
371 LinkName = ConsoleStartInfo->ConsoleTitle;
372 }
373 else
374 {
375 /* Skip the path separator */
376 ++LinkName;
377 }
378
379 /* 2- Check for the link extension. The name ".lnk" is considered invalid. */
380 Length = wcslen(LinkName);
381 if ( (Length <= 4) || (wcsicmp(LinkName + (Length - 4), L".lnk") != 0) )
382 return FALSE;
383
384 /* 3- It may be a link. Try to retrieve some properties */
385 HRESULT hRes = CoInitialize(NULL);
386 if (SUCCEEDED(hRes))
387 {
388 /* Get a pointer to the IShellLink interface */
389 IShellLinkW* pshl = NULL;
390 hRes = CoCreateInstance(&CLSID_ShellLink,
391 NULL,
392 CLSCTX_INPROC_SERVER,
393 &IID_IShellLinkW,
394 (LPVOID*)&pshl);
395 if (SUCCEEDED(hRes))
396 {
397 /* Get a pointer to the IPersistFile interface */
398 IPersistFile* ppf = NULL;
399 hRes = IPersistFile_QueryInterface(pshl, &IID_IPersistFile, (LPVOID*)&ppf);
400 if (SUCCEEDED(hRes))
401 {
402 /* Load the shortcut */
403 hRes = IPersistFile_Load(ppf, ConsoleStartInfo->ConsoleTitle, STGM_READ);
404 if (SUCCEEDED(hRes))
405 {
406 /*
407 * Finally we can get the properties !
408 * Update the old ones if needed.
409 */
410 INT ShowCmd = 0;
411 // WORD HotKey = 0;
412
413 /* Reset the name of the console with the name of the shortcut */
414 Length = min(/*Length*/ Length - 4, // 4 == len(".lnk")
415 sizeof(ConsoleInfo->ConsoleTitle) / sizeof(ConsoleInfo->ConsoleTitle[0]) - 1);
416 wcsncpy(ConsoleInfo->ConsoleTitle, LinkName, Length);
417 ConsoleInfo->ConsoleTitle[Length] = L'\0';
418
419 /* Get the window showing command */
420 hRes = IShellLinkW_GetShowCmd(pshl, &ShowCmd);
421 if (SUCCEEDED(hRes)) ConsoleStartInfo->ShowWindow = (WORD)ShowCmd;
422
423 /* Get the hotkey */
424 // hRes = pshl->GetHotkey(&ShowCmd);
425 // if (SUCCEEDED(hRes)) ConsoleStartInfo->HotKey = HotKey;
426
427 /* Get the icon location, if any */
428 hRes = IShellLinkW_GetIconLocation(pshl, IconPath, IconPathLength, piIcon);
429 if (!SUCCEEDED(hRes))
430 {
431 IconPath[0] = L'\0';
432 }
433
434 // FIXME: Since we still don't load console properties from the shortcut,
435 // return false. When this will be done, we will return true instead.
436 RetVal = FALSE;
437 }
438 IPersistFile_Release(ppf);
439 }
440 IShellLinkW_Release(pshl);
441 }
442 }
443 CoUninitialize();
444
445 return RetVal;
446 }
447
448 NTSTATUS WINAPI
449 ConSrvInitConsole(OUT PCONSOLE* NewConsole,
450 IN OUT PCONSOLE_START_INFO ConsoleStartInfo,
451 IN PCSR_PROCESS ConsoleLeaderProcess)
452 {
453 NTSTATUS Status;
454 SECURITY_ATTRIBUTES SecurityAttributes;
455 CONSOLE_INFO ConsoleInfo;
456 SIZE_T Length = 0;
457 DWORD ProcessId = HandleToUlong(ConsoleLeaderProcess->ClientId.UniqueProcess);
458 PCONSOLE Console;
459 PCONSOLE_SCREEN_BUFFER NewBuffer;
460 BOOL GuiMode;
461 WCHAR Title[128];
462 WCHAR IconPath[MAX_PATH + 1] = L"";
463 INT iIcon = 0;
464
465 if (NewConsole == NULL) return STATUS_INVALID_PARAMETER;
466 *NewConsole = NULL;
467
468 /*
469 * Allocate a console structure
470 */
471 Console = RtlAllocateHeap(ConSrvHeap, HEAP_ZERO_MEMORY, sizeof(CONSOLE));
472 if (NULL == Console)
473 {
474 DPRINT1("Not enough memory for console creation.\n");
475 return STATUS_NO_MEMORY;
476 }
477
478 /*
479 * Load the console settings
480 */
481
482 /* 1. Load the default settings */
483 ConSrvGetDefaultSettings(&ConsoleInfo, ProcessId);
484
485 /* 2. Get the title of the console (initialize ConsoleInfo.ConsoleTitle) */
486 Length = min(wcslen(ConsoleStartInfo->ConsoleTitle),
487 sizeof(ConsoleInfo.ConsoleTitle) / sizeof(ConsoleInfo.ConsoleTitle[0]) - 1);
488 wcsncpy(ConsoleInfo.ConsoleTitle, ConsoleStartInfo->ConsoleTitle, Length);
489 ConsoleInfo.ConsoleTitle[Length] = L'\0';
490
491 /*
492 * 3. Check whether the process creating the console was launched
493 * via a shell-link. ConsoleInfo.ConsoleTitle may be updated by
494 * the name of the shortcut.
495 */
496 if (ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME)
497 {
498 if (!LoadShellLinkConsoleInfo(ConsoleStartInfo,
499 &ConsoleInfo,
500 IconPath,
501 MAX_PATH,
502 &iIcon))
503 {
504 ConsoleStartInfo->dwStartupFlags &= ~STARTF_TITLEISLINKNAME;
505 }
506 }
507
508 /*
509 * 4. Load the remaining console settings via the registry.
510 */
511 if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
512 {
513 /*
514 * Either we weren't created by an app launched via a shell-link,
515 * or we failed to load shell-link console properties.
516 * Therefore, load the console infos for the application from the registry.
517 */
518 ConSrvReadUserSettings(&ConsoleInfo, ProcessId);
519
520 /*
521 * Now, update them with the properties the user might gave to us
522 * via the STARTUPINFO structure before calling CreateProcess
523 * (and which was transmitted via the ConsoleStartInfo structure).
524 * We therefore overwrite the values read in the registry.
525 */
526 if (ConsoleStartInfo->dwStartupFlags & STARTF_USEFILLATTRIBUTE)
527 {
528 ConsoleInfo.ScreenAttrib = ConsoleStartInfo->FillAttribute;
529 }
530 if (ConsoleStartInfo->dwStartupFlags & STARTF_USECOUNTCHARS)
531 {
532 ConsoleInfo.ScreenBufferSize = ConsoleStartInfo->ScreenBufferSize;
533 }
534 if (ConsoleStartInfo->dwStartupFlags & STARTF_USESIZE)
535 {
536 // ConsoleInfo->ConsoleSize = ConsoleStartInfo->ConsoleWindowSize;
537 ConsoleInfo.ConsoleSize.X = (SHORT)ConsoleStartInfo->ConsoleWindowSize.cx;
538 ConsoleInfo.ConsoleSize.Y = (SHORT)ConsoleStartInfo->ConsoleWindowSize.cy;
539 }
540 /*
541 if (ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN)
542 {
543 ConsoleInfo.FullScreen = TRUE;
544 }
545 */
546 }
547
548 /*
549 * Initialize the console
550 */
551 Console->State = CONSOLE_INITIALIZING;
552 InitializeCriticalSection(&Console->Lock);
553 Console->ReferenceCount = 0;
554 InitializeListHead(&Console->ProcessList);
555 memcpy(Console->Colors, ConsoleInfo.Colors, sizeof(ConsoleInfo.Colors));
556 Console->ConsoleSize = ConsoleInfo.ConsoleSize;
557
558 /*
559 * Initialize the input buffer
560 */
561 Console->InputBuffer.Header.Type = INPUT_BUFFER;
562 Console->InputBuffer.Header.Console = Console;
563
564 SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
565 SecurityAttributes.lpSecurityDescriptor = NULL;
566 SecurityAttributes.bInheritHandle = TRUE;
567 Console->InputBuffer.ActiveEvent = CreateEventW(&SecurityAttributes, TRUE, FALSE, NULL);
568 if (NULL == Console->InputBuffer.ActiveEvent)
569 {
570 DeleteCriticalSection(&Console->Lock);
571 RtlFreeHeap(ConSrvHeap, 0, Console);
572 return STATUS_UNSUCCESSFUL;
573 }
574
575 Console->InputBuffer.Mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
576 ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
577 Console->QuickEdit = ConsoleInfo.QuickEdit;
578 Console->InsertMode = ConsoleInfo.InsertMode;
579 InitializeListHead(&Console->InputBuffer.ReadWaitQueue);
580 InitializeListHead(&Console->InputBuffer.InputEvents);
581 Console->LineBuffer = NULL;
582 Console->CodePage = GetOEMCP();
583 Console->OutputCodePage = GetOEMCP();
584
585 /* Initialize a new screen buffer with default settings */
586 InitializeListHead(&Console->BufferList);
587 Status = ConSrvCreateScreenBuffer(Console,
588 &NewBuffer,
589 ConsoleInfo.ScreenBufferSize,
590 ConsoleInfo.ScreenAttrib,
591 ConsoleInfo.PopupAttrib,
592 (ConsoleInfo.FullScreen ? CONSOLE_FULLSCREEN_MODE
593 : CONSOLE_WINDOWED_MODE),
594 TRUE,
595 ConsoleInfo.CursorSize);
596 if (!NT_SUCCESS(Status))
597 {
598 DPRINT1("ConSrvCreateScreenBuffer: failed, Status = 0x%08lx\n", Status);
599 CloseHandle(Console->InputBuffer.ActiveEvent);
600 DeleteCriticalSection(&Console->Lock);
601 RtlFreeHeap(ConSrvHeap, 0, Console);
602 return Status;
603 }
604 /* Make the new screen buffer active */
605 Console->ActiveBuffer = NewBuffer;
606 InitializeListHead(&Console->WriteWaitQueue);
607
608 /*
609 * Initialize the history buffers
610 */
611 InitializeListHead(&Console->HistoryBuffers);
612 Console->HistoryBufferSize = ConsoleInfo.HistoryBufferSize;
613 Console->NumberOfHistoryBuffers = ConsoleInfo.NumberOfHistoryBuffers;
614 Console->HistoryNoDup = ConsoleInfo.HistoryNoDup;
615
616 /* Initialize the console title */
617 RtlCreateUnicodeString(&Console->OriginalTitle, ConsoleInfo.ConsoleTitle);
618 if (ConsoleInfo.ConsoleTitle[0] == L'\0')
619 {
620 if (LoadStringW(ConSrvDllInstance, IDS_CONSOLE_TITLE, Title, sizeof(Title) / sizeof(Title[0])))
621 {
622 RtlCreateUnicodeString(&Console->Title, Title);
623 }
624 else
625 {
626 RtlCreateUnicodeString(&Console->Title, L"ReactOS Console");
627 }
628 }
629 else
630 {
631 RtlCreateUnicodeString(&Console->Title, ConsoleInfo.ConsoleTitle);
632 }
633
634 /* Lock the console until its initialization is finished */
635 // EnterCriticalSection(&Console->Lock);
636
637 /*
638 * If we are not in GUI-mode, start the text-mode terminal emulator.
639 * If we fail, try to start the GUI-mode terminal emulator.
640 */
641 #ifdef TUI_CONSOLE
642 GuiMode = DtbgIsDesktopVisible();
643 #else
644 GuiMode = TRUE;
645 #endif
646
647 #ifdef TUI_CONSOLE
648 if (!GuiMode)
649 {
650 DPRINT1("CONSRV: Opening text-mode terminal emulator\n");
651 Status = TuiInitConsole(Console,
652 ConsoleStartInfo,
653 &ConsoleInfo,
654 ProcessId);
655 if (!NT_SUCCESS(Status))
656 {
657 DPRINT1("Failed to open text-mode terminal emulator, switching to gui-mode, Status = 0x%08lx\n", Status);
658 GuiMode = TRUE;
659 }
660 }
661 #endif
662
663 /*
664 * Try to open the GUI-mode terminal emulator. Two cases are possible:
665 * - We are in GUI-mode, therefore GuiMode == TRUE, the previous test-case
666 * failed and we start GUI-mode terminal emulator.
667 * - We are in text-mode, therefore GuiMode == FALSE, the previous test-case
668 * succeeded BUT we failed at starting text-mode terminal emulator.
669 * Then GuiMode was switched to TRUE in order to try to open the GUI-mode
670 * terminal emulator (Win32k will automatically switch to graphical mode,
671 * therefore no additional code is needed).
672 */
673 if (GuiMode)
674 {
675 DPRINT1("CONSRV: Opening GUI-mode terminal emulator\n");
676 Status = GuiInitConsole(Console,
677 ConsoleStartInfo,
678 &ConsoleInfo,
679 ProcessId,
680 IconPath,
681 iIcon);
682 if (!NT_SUCCESS(Status))
683 {
684 DPRINT1("GuiInitConsole: failed, Status = 0x%08lx\n", Status);
685 RtlFreeUnicodeString(&Console->Title);
686 RtlFreeUnicodeString(&Console->OriginalTitle);
687 ConioDeleteScreenBuffer(NewBuffer);
688 CloseHandle(Console->InputBuffer.ActiveEvent);
689 // LeaveCriticalSection(&Console->Lock);
690 DeleteCriticalSection(&Console->Lock);
691 RtlFreeHeap(ConSrvHeap, 0, Console);
692 return Status;
693 }
694 }
695
696 DPRINT("Terminal initialized\n");
697
698 /* All went right, so add the console to the list */
699 ConSrvLockConsoleListExclusive();
700 DPRINT("Insert in the list\n");
701 InsertTailList(&ConsoleList, &Console->Entry);
702
703 /* The initialization is finished */
704 DPRINT("Change state\n");
705 Console->State = CONSOLE_RUNNING;
706
707 /* Unlock the console */
708 // LeaveCriticalSection(&Console->Lock);
709
710 /* Unlock the console list */
711 ConSrvUnlockConsoleList();
712
713 /* Copy buffer contents to screen */
714 ConioDrawConsole(Console);
715 DPRINT("Console drawn\n");
716
717 /* Return the newly created console to the caller and a success code too */
718 *NewConsole = Console;
719 return STATUS_SUCCESS;
720 }
721
722 VOID WINAPI
723 ConSrvDeleteConsole(PCONSOLE Console)
724 {
725 DPRINT("ConSrvDeleteConsole\n");
726
727 /*
728 * Forbid validation of any console by other threads
729 * during the deletion of this console.
730 */
731 ConSrvLockConsoleListExclusive();
732
733 /* Check the existence of the console, and if it's ok, continue */
734 if (!ConSrvValidateConsolePointer(Console))
735 {
736 /* Unlock the console list and return */
737 ConSrvUnlockConsoleList();
738 return;
739 }
740
741 /*
742 * If the console is already being destroyed
743 * (thus not running), just return.
744 */
745 if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_RUNNING, TRUE))
746 {
747 /* Unlock the console list and return */
748 ConSrvUnlockConsoleList();
749 return;
750 }
751
752 /*
753 * We are about to be destroyed. Signal it to other people
754 * so that they can terminate what they are doing, and that
755 * they cannot longer validate the console.
756 */
757 Console->State = CONSOLE_TERMINATING;
758
759 /*
760 * Allow other threads to finish their job: basically, unlock
761 * all other calls to EnterCriticalSection(&Console->Lock); by
762 * ConSrvValidateConsole(Unsafe) functions so that they just see
763 * that we are not in CONSOLE_RUNNING state anymore, or unlock
764 * other concurrent calls to ConSrvDeleteConsole so that they
765 * can see that we are in fact already deleting the console.
766 */
767 LeaveCriticalSection(&Console->Lock);
768 ConSrvUnlockConsoleList();
769
770 /* FIXME: Send a terminate message to all the processes owning this console */
771
772 /* Cleanup the UI-oriented part */
773 ConioCleanupConsole(Console);
774
775 /***
776 * Check that the console is in terminating state before continuing
777 * (the cleanup code must not change the state of the console...
778 * ...unless to cancel console deletion ?).
779 ***/
780
781 ConSrvLockConsoleListExclusive();
782
783 /* Re-check the existence of the console, and if it's ok, continue */
784 if (!ConSrvValidateConsolePointer(Console))
785 {
786 /* Unlock the console list and return */
787 ConSrvUnlockConsoleList();
788 return;
789 }
790
791 if (!ConSrvValidateConsoleUnsafe(Console, CONSOLE_TERMINATING, TRUE))
792 {
793 ConSrvUnlockConsoleList();
794 return;
795 }
796
797 /* We are in destruction */
798 Console->State = CONSOLE_IN_DESTRUCTION;
799
800 /* Remove the console from the list */
801 RemoveEntryList(&Console->Entry);
802
803 /* Reset the count to be sure */
804 Console->ReferenceCount = 0;
805
806 /* Discard all entries in the input event queue */
807 PurgeInputBuffer(Console);
808
809 if (Console->LineBuffer) RtlFreeHeap(ConSrvHeap, 0, Console->LineBuffer);
810
811 IntDeleteAllAliases(Console);
812 HistoryDeleteBuffers(Console);
813
814 ConioDeleteScreenBuffer(Console->ActiveBuffer);
815 if (!IsListEmpty(&Console->BufferList))
816 {
817 DPRINT1("BUG: screen buffer list not empty\n");
818 }
819
820 // CloseHandle(Console->InputBuffer.ActiveEvent);
821 if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent);
822
823 RtlFreeUnicodeString(&Console->OriginalTitle);
824 RtlFreeUnicodeString(&Console->Title);
825
826 DPRINT("ConSrvDeleteConsole - Unlocking\n");
827 LeaveCriticalSection(&Console->Lock);
828 DPRINT("ConSrvDeleteConsole - Destroying lock\n");
829 DeleteCriticalSection(&Console->Lock);
830 DPRINT("ConSrvDeleteConsole - Lock destroyed ; freeing console\n");
831
832 RtlFreeHeap(ConSrvHeap, 0, Console);
833 DPRINT("ConSrvDeleteConsole - Console freed\n");
834
835 /* Unlock the console list and return */
836 ConSrvUnlockConsoleList();
837 }
838
839
840 /* PUBLIC SERVER APIS *********************************************************/
841
842 CSR_API(SrvAllocConsole)
843 {
844 NTSTATUS Status = STATUS_SUCCESS;
845 PCONSOLE_ALLOCCONSOLE AllocConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AllocConsoleRequest;
846 PCSR_PROCESS CsrProcess = CsrGetClientThread()->Process;
847 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
848
849 if (ProcessData->Console != NULL)
850 {
851 DPRINT1("Process already has a console\n");
852 return STATUS_ACCESS_DENIED;
853 }
854
855 if (!CsrValidateMessageBuffer(ApiMessage,
856 (PVOID*)&AllocConsoleRequest->ConsoleStartInfo,
857 1,
858 sizeof(CONSOLE_START_INFO)))
859 {
860 return STATUS_INVALID_PARAMETER;
861 }
862
863 /*
864 * We are about to create a new console. However when ConSrvNewProcess
865 * was called, we didn't know that we wanted to create a new console and
866 * therefore, we by default inherited the handles table from our parent
867 * process. It's only now that we notice that in fact we do not need
868 * them, because we've created a new console and thus we must use it.
869 *
870 * Therefore, free the console we can have and our handles table,
871 * and recreate a new one later on.
872 */
873 ConSrvRemoveConsole(ProcessData);
874
875 /* Initialize a new Console owned by the Console Leader Process */
876 Status = ConSrvAllocateConsole(ProcessData,
877 &AllocConsoleRequest->InputHandle,
878 &AllocConsoleRequest->OutputHandle,
879 &AllocConsoleRequest->ErrorHandle,
880 AllocConsoleRequest->ConsoleStartInfo);
881 if (!NT_SUCCESS(Status))
882 {
883 DPRINT1("Console allocation failed\n");
884 return Status;
885 }
886
887 /* Return it to the caller */
888 AllocConsoleRequest->Console = ProcessData->Console;
889
890 /* Input Wait Handle */
891 AllocConsoleRequest->InputWaitHandle = ProcessData->ConsoleEvent;
892
893 /* Set the Property Dialog Handler */
894 ProcessData->PropDispatcher = AllocConsoleRequest->PropDispatcher;
895
896 /* Set the Ctrl Dispatcher */
897 ProcessData->CtrlDispatcher = AllocConsoleRequest->CtrlDispatcher;
898
899 return STATUS_SUCCESS;
900 }
901
902 CSR_API(SrvAttachConsole)
903 {
904 NTSTATUS Status = STATUS_SUCCESS;
905 PCONSOLE_ATTACHCONSOLE AttachConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AttachConsoleRequest;
906 PCSR_PROCESS SourceProcess = NULL; // The parent process.
907 PCSR_PROCESS TargetProcess = CsrGetClientThread()->Process; // Ourselves.
908 HANDLE ProcessId = ULongToHandle(AttachConsoleRequest->ProcessId);
909 PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData;
910
911 TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
912
913 if (TargetProcessData->Console != NULL)
914 {
915 DPRINT1("Process already has a console\n");
916 return STATUS_ACCESS_DENIED;
917 }
918
919 /* Check whether we try to attach to the parent's console */
920 if (ProcessId == ULongToHandle(ATTACH_PARENT_PROCESS))
921 {
922 PROCESS_BASIC_INFORMATION ProcessInfo;
923 ULONG Length = sizeof(ProcessInfo);
924
925 /* Get the real parent's ID */
926
927 Status = NtQueryInformationProcess(TargetProcess->ProcessHandle,
928 ProcessBasicInformation,
929 &ProcessInfo,
930 Length, &Length);
931 if (!NT_SUCCESS(Status))
932 {
933 DPRINT1("SrvAttachConsole - Cannot retrieve basic process info, Status = %lu\n", Status);
934 return Status;
935 }
936
937 ProcessId = ULongToHandle(ProcessInfo.InheritedFromUniqueProcessId);
938 }
939
940 /* Lock the source process via its PID */
941 Status = CsrLockProcessByClientId(ProcessId, &SourceProcess);
942 if (!NT_SUCCESS(Status)) return Status;
943
944 SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
945
946 if (SourceProcessData->Console == NULL)
947 {
948 Status = STATUS_INVALID_HANDLE;
949 goto Quit;
950 }
951
952 /*
953 * We are about to create a new console. However when ConSrvNewProcess
954 * was called, we didn't know that we wanted to create a new console and
955 * therefore, we by default inherited the handles table from our parent
956 * process. It's only now that we notice that in fact we do not need
957 * them, because we've created a new console and thus we must use it.
958 *
959 * Therefore, free the console we can have and our handles table,
960 * and recreate a new one later on.
961 */
962 ConSrvRemoveConsole(TargetProcessData);
963
964 /*
965 * Inherit the console from the parent,
966 * if any, otherwise return an error.
967 */
968 Status = ConSrvInheritConsole(TargetProcessData,
969 SourceProcessData->Console,
970 TRUE,
971 &AttachConsoleRequest->InputHandle,
972 &AttachConsoleRequest->OutputHandle,
973 &AttachConsoleRequest->ErrorHandle);
974 if (!NT_SUCCESS(Status))
975 {
976 DPRINT1("Console inheritance failed\n");
977 goto Quit;
978 }
979
980 /* Return it to the caller */
981 AttachConsoleRequest->Console = TargetProcessData->Console;
982
983 /* Input Wait Handle */
984 AttachConsoleRequest->InputWaitHandle = TargetProcessData->ConsoleEvent;
985
986 /* Set the Property Dialog Handler */
987 TargetProcessData->PropDispatcher = AttachConsoleRequest->PropDispatcher;
988
989 /* Set the Ctrl Dispatcher */
990 TargetProcessData->CtrlDispatcher = AttachConsoleRequest->CtrlDispatcher;
991
992 Status = STATUS_SUCCESS;
993
994 Quit:
995 /* Unlock the "source" process and exit */
996 CsrUnlockProcess(SourceProcess);
997 return Status;
998 }
999
1000 CSR_API(SrvFreeConsole)
1001 {
1002 ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process));
1003 return STATUS_SUCCESS;
1004 }
1005
1006 CSR_API(SrvGetConsoleMode)
1007 {
1008 NTSTATUS Status;
1009 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
1010 PCONSOLE_IO_OBJECT Object = NULL;
1011
1012 Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
1013 ConsoleModeRequest->ConsoleHandle,
1014 &Object, NULL, GENERIC_READ, TRUE, 0);
1015 if (!NT_SUCCESS(Status)) return Status;
1016
1017 Status = STATUS_SUCCESS;
1018
1019 if (INPUT_BUFFER == Object->Type)
1020 {
1021 PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
1022 PCONSOLE Console = InputBuffer->Header.Console;
1023 DWORD ConsoleMode = InputBuffer->Mode;
1024
1025 if (Console->QuickEdit || Console->InsertMode)
1026 {
1027 // Windows does this, even if it's not documented on MSDN
1028 ConsoleMode |= ENABLE_EXTENDED_FLAGS;
1029
1030 if (Console->QuickEdit ) ConsoleMode |= ENABLE_QUICK_EDIT_MODE;
1031 if (Console->InsertMode) ConsoleMode |= ENABLE_INSERT_MODE;
1032 }
1033
1034 ConsoleModeRequest->ConsoleMode = ConsoleMode;
1035 }
1036 else if (SCREEN_BUFFER == Object->Type)
1037 {
1038 PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
1039 ConsoleModeRequest->ConsoleMode = Buffer->Mode;
1040 }
1041 else
1042 {
1043 Status = STATUS_INVALID_HANDLE;
1044 }
1045
1046 ConSrvReleaseObject(Object, TRUE);
1047 return Status;
1048 }
1049
1050 CSR_API(SrvSetConsoleMode)
1051 {
1052 #define CONSOLE_VALID_CONTROL_MODES ( ENABLE_EXTENDED_FLAGS | ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE )
1053 #define CONSOLE_VALID_INPUT_MODES ( ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | \
1054 ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT | \
1055 ENABLE_MOUSE_INPUT )
1056 #define CONSOLE_VALID_OUTPUT_MODES ( ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT )
1057
1058 NTSTATUS Status;
1059 PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
1060 DWORD ConsoleMode = ConsoleModeRequest->ConsoleMode;
1061 PCONSOLE_IO_OBJECT Object = NULL;
1062
1063 Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
1064 ConsoleModeRequest->ConsoleHandle,
1065 &Object, NULL, GENERIC_WRITE, TRUE, 0);
1066 if (!NT_SUCCESS(Status)) return Status;
1067
1068 Status = STATUS_SUCCESS;
1069
1070 if (INPUT_BUFFER == Object->Type)
1071 {
1072 PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
1073 PCONSOLE Console = InputBuffer->Header.Console;
1074
1075 DPRINT("SetConsoleMode(Input, %d)\n", ConsoleMode);
1076
1077 /*
1078 * 1. Only the presence of valid mode flags is allowed.
1079 */
1080 if (ConsoleMode & ~(CONSOLE_VALID_INPUT_MODES | CONSOLE_VALID_CONTROL_MODES))
1081 {
1082 Status = STATUS_INVALID_PARAMETER;
1083 goto Quit;
1084 }
1085
1086 /*
1087 * 2. If we use control mode flags without ENABLE_EXTENDED_FLAGS,
1088 * then consider the flags invalid.
1089 *
1090 if ( (ConsoleMode & CONSOLE_VALID_CONTROL_MODES) &&
1091 (ConsoleMode & ENABLE_EXTENDED_FLAGS) == 0 )
1092 {
1093 Status = STATUS_INVALID_PARAMETER;
1094 goto Quit;
1095 }
1096 */
1097
1098 /*
1099 * 3. Now we can continue.
1100 */
1101 if (ConsoleMode & CONSOLE_VALID_CONTROL_MODES)
1102 {
1103 Console->QuickEdit = !!(ConsoleMode & ENABLE_QUICK_EDIT_MODE);
1104 Console->InsertMode = !!(ConsoleMode & ENABLE_INSERT_MODE);
1105 }
1106 InputBuffer->Mode = (ConsoleMode & CONSOLE_VALID_INPUT_MODES);
1107 }
1108 else if (SCREEN_BUFFER == Object->Type)
1109 {
1110 PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
1111
1112 DPRINT("SetConsoleMode(Output, %d)\n", ConsoleMode);
1113
1114 if (ConsoleMode & ~CONSOLE_VALID_OUTPUT_MODES)
1115 {
1116 Status = STATUS_INVALID_PARAMETER;
1117 }
1118 else
1119 {
1120 Buffer->Mode = (ConsoleMode & CONSOLE_VALID_OUTPUT_MODES);
1121 }
1122 }
1123 else
1124 {
1125 Status = STATUS_INVALID_HANDLE;
1126 }
1127
1128 Quit:
1129 ConSrvReleaseObject(Object, TRUE);
1130 return Status;
1131 }
1132
1133 CSR_API(SrvGetConsoleTitle)
1134 {
1135 NTSTATUS Status;
1136 PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
1137 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
1138 PCONSOLE Console;
1139 DWORD Length;
1140
1141 if (!CsrValidateMessageBuffer(ApiMessage,
1142 (PVOID)&TitleRequest->Title,
1143 TitleRequest->Length,
1144 sizeof(BYTE)))
1145 {
1146 return STATUS_INVALID_PARAMETER;
1147 }
1148
1149 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1150 if (!NT_SUCCESS(Status))
1151 {
1152 DPRINT1("Can't get console\n");
1153 return Status;
1154 }
1155
1156 /* Copy title of the console to the user title buffer */
1157 if (TitleRequest->Length >= sizeof(WCHAR))
1158 {
1159 Length = min(TitleRequest->Length - sizeof(WCHAR), Console->Title.Length);
1160 memcpy(TitleRequest->Title, Console->Title.Buffer, Length);
1161 TitleRequest->Title[Length / sizeof(WCHAR)] = L'\0';
1162 }
1163
1164 TitleRequest->Length = Console->Title.Length;
1165
1166 ConSrvReleaseConsole(Console, TRUE);
1167 return STATUS_SUCCESS;
1168 }
1169
1170 CSR_API(SrvSetConsoleTitle)
1171 {
1172 NTSTATUS Status;
1173 PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
1174 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
1175 PCONSOLE Console;
1176 PWCHAR Buffer;
1177
1178 if (!CsrValidateMessageBuffer(ApiMessage,
1179 (PVOID)&TitleRequest->Title,
1180 TitleRequest->Length,
1181 sizeof(BYTE)))
1182 {
1183 return STATUS_INVALID_PARAMETER;
1184 }
1185
1186 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1187 if (!NT_SUCCESS(Status))
1188 {
1189 DPRINT1("Can't get console\n");
1190 return Status;
1191 }
1192
1193 /* Allocate a new buffer to hold the new title (NULL-terminated) */
1194 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, TitleRequest->Length + sizeof(WCHAR));
1195 if (Buffer)
1196 {
1197 /* Free the old title */
1198 RtlFreeUnicodeString(&Console->Title);
1199
1200 /* Copy title to console */
1201 Console->Title.Buffer = Buffer;
1202 Console->Title.Length = TitleRequest->Length;
1203 Console->Title.MaximumLength = Console->Title.Length + sizeof(WCHAR);
1204 RtlCopyMemory(Console->Title.Buffer,
1205 TitleRequest->Title,
1206 Console->Title.Length);
1207 Console->Title.Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0';
1208
1209 ConioChangeTitle(Console);
1210 Status = STATUS_SUCCESS;
1211 }
1212 else
1213 {
1214 Status = STATUS_NO_MEMORY;
1215 }
1216
1217 ConSrvReleaseConsole(Console, TRUE);
1218 return Status;
1219 }
1220
1221 /**********************************************************************
1222 * HardwareStateProperty
1223 *
1224 * DESCRIPTION
1225 * Set/Get the value of the HardwareState and switch
1226 * between direct video buffer ouput and GDI windowed
1227 * output.
1228 * ARGUMENTS
1229 * Client hands us a CONSOLE_GETSETHWSTATE object.
1230 * We use the same object to Request.
1231 * NOTE
1232 * ConsoleHwState has the correct size to be compatible
1233 * with NT's, but values are not.
1234 */
1235 static NTSTATUS FASTCALL
1236 SetConsoleHardwareState(PCONSOLE Console, ULONG ConsoleHwState)
1237 {
1238 DPRINT1("Console Hardware State: %d\n", ConsoleHwState);
1239
1240 if ((CONSOLE_HARDWARE_STATE_GDI_MANAGED == ConsoleHwState)
1241 ||(CONSOLE_HARDWARE_STATE_DIRECT == ConsoleHwState))
1242 {
1243 if (Console->HardwareState != ConsoleHwState)
1244 {
1245 /* TODO: implement switching from full screen to windowed mode */
1246 /* TODO: or back; now simply store the hardware state */
1247 Console->HardwareState = ConsoleHwState;
1248 }
1249
1250 return STATUS_SUCCESS;
1251 }
1252
1253 return STATUS_INVALID_PARAMETER_3; /* Client: (handle, set_get, [mode]) */
1254 }
1255
1256 CSR_API(SrvGetConsoleHardwareState)
1257 {
1258 NTSTATUS Status;
1259 PCONSOLE_GETSETHWSTATE HardwareStateRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.HardwareStateRequest;
1260 PCONSOLE_SCREEN_BUFFER Buff;
1261 PCONSOLE Console;
1262
1263 Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
1264 HardwareStateRequest->OutputHandle,
1265 &Buff,
1266 GENERIC_READ,
1267 TRUE);
1268 if (!NT_SUCCESS(Status))
1269 {
1270 DPRINT1("Failed to get console handle in SrvGetConsoleHardwareState\n");
1271 return Status;
1272 }
1273
1274 Console = Buff->Header.Console;
1275 HardwareStateRequest->State = Console->HardwareState;
1276
1277 ConSrvReleaseScreenBuffer(Buff, TRUE);
1278 return Status;
1279 }
1280
1281 CSR_API(SrvSetConsoleHardwareState)
1282 {
1283 NTSTATUS Status;
1284 PCONSOLE_GETSETHWSTATE HardwareStateRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.HardwareStateRequest;
1285 PCONSOLE_SCREEN_BUFFER Buff;
1286 PCONSOLE Console;
1287
1288 Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
1289 HardwareStateRequest->OutputHandle,
1290 &Buff,
1291 GENERIC_WRITE,
1292 TRUE);
1293 if (!NT_SUCCESS(Status))
1294 {
1295 DPRINT1("Failed to get console handle in SrvSetConsoleHardwareState\n");
1296 return Status;
1297 }
1298
1299 DPRINT("Setting console hardware state.\n");
1300 Console = Buff->Header.Console;
1301 Status = SetConsoleHardwareState(Console, HardwareStateRequest->State);
1302
1303 ConSrvReleaseScreenBuffer(Buff, TRUE);
1304 return Status;
1305 }
1306
1307 CSR_API(SrvGetConsoleDisplayMode)
1308 {
1309 NTSTATUS Status;
1310 PCONSOLE_GETDISPLAYMODE GetDisplayModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetDisplayModeRequest;
1311 PCONSOLE Console;
1312 ULONG DisplayMode = 0;
1313
1314 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
1315 &Console, TRUE);
1316 if (!NT_SUCCESS(Status))
1317 {
1318 DPRINT1("Failed to get console handle in SrvGetConsoleDisplayMode\n");
1319 return Status;
1320 }
1321
1322 if (Console->ActiveBuffer->DisplayMode & CONSOLE_FULLSCREEN_MODE)
1323 DisplayMode |= CONSOLE_FULLSCREEN_HARDWARE; // CONSOLE_FULLSCREEN
1324 else if (Console->ActiveBuffer->DisplayMode & CONSOLE_WINDOWED_MODE)
1325 DisplayMode |= CONSOLE_WINDOWED;
1326
1327 GetDisplayModeRequest->DisplayMode = DisplayMode;
1328 Status = STATUS_SUCCESS;
1329
1330 ConSrvReleaseConsole(Console, TRUE);
1331 return Status;
1332 }
1333
1334 CSR_API(SrvSetConsoleDisplayMode)
1335 {
1336 NTSTATUS Status;
1337 PCONSOLE_SETDISPLAYMODE SetDisplayModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetDisplayModeRequest;
1338 PCONSOLE_SCREEN_BUFFER Buff;
1339
1340 Status = ConSrvGetScreenBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
1341 SetDisplayModeRequest->OutputHandle,
1342 &Buff,
1343 GENERIC_WRITE,
1344 TRUE);
1345 if (!NT_SUCCESS(Status))
1346 {
1347 DPRINT1("Failed to get console handle in SrvSetConsoleDisplayMode\n");
1348 return Status;
1349 }
1350
1351 if (SetDisplayModeRequest->DisplayMode & ~(CONSOLE_FULLSCREEN_MODE | CONSOLE_WINDOWED_MODE))
1352 {
1353 Status = STATUS_INVALID_PARAMETER;
1354 }
1355 else
1356 {
1357 Buff->DisplayMode = SetDisplayModeRequest->DisplayMode;
1358 // TODO: Change the display mode
1359 SetDisplayModeRequest->NewSBDim = Buff->ScreenBufferSize;
1360
1361 Status = STATUS_SUCCESS;
1362 }
1363
1364 ConSrvReleaseScreenBuffer(Buff, TRUE);
1365 return Status;
1366 }
1367
1368 CSR_API(SrvGetConsoleWindow)
1369 {
1370 NTSTATUS Status;
1371 PCONSOLE_GETWINDOW GetWindowRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetWindowRequest;
1372 PCONSOLE Console;
1373
1374 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1375 if (!NT_SUCCESS(Status)) return Status;
1376
1377 GetWindowRequest->WindowHandle = ConioGetConsoleWindowHandle(Console);
1378 ConSrvReleaseConsole(Console, TRUE);
1379
1380 return STATUS_SUCCESS;
1381 }
1382
1383 CSR_API(SrvSetConsoleIcon)
1384 {
1385 NTSTATUS Status;
1386 PCONSOLE_SETICON SetIconRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetIconRequest;
1387 PCONSOLE Console;
1388
1389 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1390 if (!NT_SUCCESS(Status)) return Status;
1391
1392 Status = (ConioChangeIcon(Console, SetIconRequest->WindowIcon)
1393 ? STATUS_SUCCESS
1394 : STATUS_UNSUCCESSFUL);
1395
1396 ConSrvReleaseConsole(Console, TRUE);
1397
1398 return Status;
1399 }
1400
1401 CSR_API(SrvGetConsoleCP)
1402 {
1403 NTSTATUS Status;
1404 PCONSOLE_GETSETINPUTOUTPUTCP ConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleCPRequest;
1405 PCONSOLE Console;
1406
1407 DPRINT("SrvGetConsoleCP, getting %s Code Page\n",
1408 ConsoleCPRequest->InputCP ? "Input" : "Output");
1409
1410 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1411 if (!NT_SUCCESS(Status)) return Status;
1412
1413 ConsoleCPRequest->CodePage = (ConsoleCPRequest->InputCP ? Console->CodePage
1414 : Console->OutputCodePage);
1415 ConSrvReleaseConsole(Console, TRUE);
1416 return STATUS_SUCCESS;
1417 }
1418
1419 CSR_API(SrvSetConsoleCP)
1420 {
1421 NTSTATUS Status;
1422 PCONSOLE_GETSETINPUTOUTPUTCP ConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleCPRequest;
1423 PCONSOLE Console;
1424
1425 DPRINT("SrvSetConsoleCP, setting %s Code Page\n",
1426 ConsoleCPRequest->InputCP ? "Input" : "Output");
1427
1428 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1429 if (!NT_SUCCESS(Status)) return Status;
1430
1431 if (IsValidCodePage(ConsoleCPRequest->CodePage))
1432 {
1433 if (ConsoleCPRequest->InputCP)
1434 Console->CodePage = ConsoleCPRequest->CodePage;
1435 else
1436 Console->OutputCodePage = ConsoleCPRequest->CodePage;
1437
1438 ConSrvReleaseConsole(Console, TRUE);
1439 return STATUS_SUCCESS;
1440 }
1441
1442 ConSrvReleaseConsole(Console, TRUE);
1443 return STATUS_INVALID_PARAMETER;
1444 }
1445
1446 CSR_API(SrvGetConsoleProcessList)
1447 {
1448 NTSTATUS Status;
1449 PCONSOLE_GETPROCESSLIST GetProcessListRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetProcessListRequest;
1450 PDWORD Buffer;
1451 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
1452 PCONSOLE Console;
1453 PCONSOLE_PROCESS_DATA current;
1454 PLIST_ENTRY current_entry;
1455 ULONG nItems = 0;
1456
1457 if (!CsrValidateMessageBuffer(ApiMessage,
1458 (PVOID)&GetProcessListRequest->pProcessIds,
1459 GetProcessListRequest->nMaxIds,
1460 sizeof(DWORD)))
1461 {
1462 return STATUS_INVALID_PARAMETER;
1463 }
1464
1465 Buffer = GetProcessListRequest->pProcessIds;
1466
1467 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1468 if (!NT_SUCCESS(Status)) return Status;
1469
1470 for (current_entry = Console->ProcessList.Flink;
1471 current_entry != &Console->ProcessList;
1472 current_entry = current_entry->Flink)
1473 {
1474 current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink);
1475 if (++nItems <= GetProcessListRequest->nMaxIds)
1476 {
1477 *Buffer++ = HandleToUlong(current->Process->ClientId.UniqueProcess);
1478 }
1479 }
1480
1481 ConSrvReleaseConsole(Console, TRUE);
1482
1483 GetProcessListRequest->nProcessIdsTotal = nItems;
1484 return STATUS_SUCCESS;
1485 }
1486
1487 CSR_API(SrvGenerateConsoleCtrlEvent)
1488 {
1489 NTSTATUS Status;
1490 PCONSOLE_GENERATECTRLEVENT GenerateCtrlEventRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GenerateCtrlEventRequest;
1491 PCONSOLE Console;
1492
1493 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1494 if (!NT_SUCCESS(Status)) return Status;
1495
1496 Status = ConSrvConsoleProcessCtrlEvent(Console,
1497 GenerateCtrlEventRequest->ProcessGroup,
1498 GenerateCtrlEventRequest->Event);
1499
1500 ConSrvReleaseConsole(Console, TRUE);
1501 return Status;
1502 }
1503
1504 CSR_API(SrvGetConsoleSelectionInfo)
1505 {
1506 NTSTATUS Status;
1507 PCONSOLE_GETSELECTIONINFO GetSelectionInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetSelectionInfoRequest;
1508 PCONSOLE Console;
1509
1510 Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
1511 if (NT_SUCCESS(Status))
1512 {
1513 memset(&GetSelectionInfoRequest->Info, 0, sizeof(CONSOLE_SELECTION_INFO));
1514 if (Console->Selection.dwFlags != 0)
1515 GetSelectionInfoRequest->Info = Console->Selection;
1516 ConSrvReleaseConsole(Console, TRUE);
1517 }
1518
1519 return Status;
1520 }
1521
1522 /* EOF */