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