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