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