b9ca8d619ede2a7140bec611913743c0924af2ab
[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 #include "consrv.h"
12 #include "guiconsole.h"
13 #include "tuiconsole.h"
14
15 #define NDEBUG
16 #include <debug.h>
17
18 /* FUNCTIONS *****************************************************************/
19
20 BOOL FASTCALL
21 DtbgIsDesktopVisible(VOID)
22 {
23 HWND VisibleDesktopWindow = GetDesktopWindow(); // DESKTOPWNDPROC
24
25 if (VisibleDesktopWindow != NULL &&
26 !IsWindowVisible(VisibleDesktopWindow))
27 {
28 VisibleDesktopWindow = NULL;
29 }
30
31 return VisibleDesktopWindow != NULL;
32 }
33
34 NTSTATUS FASTCALL
35 ConioConsoleFromProcessData(PCONSOLE_PROCESS_DATA ProcessData,
36 PCSRSS_CONSOLE *Console)
37 {
38 PCSRSS_CONSOLE ProcessConsole;
39
40 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
41 ProcessConsole = ProcessData->Console;
42
43 if (!ProcessConsole)
44 {
45 *Console = NULL;
46 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
47 return STATUS_INVALID_HANDLE;
48 }
49
50 InterlockedIncrement(&ProcessConsole->ReferenceCount);
51 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
52 EnterCriticalSection(&(ProcessConsole->Lock));
53 *Console = ProcessConsole;
54
55 return STATUS_SUCCESS;
56 }
57
58 VOID FASTCALL
59 ConioConsoleCtrlEventTimeout(DWORD Event,
60 PCONSOLE_PROCESS_DATA ProcessData,
61 DWORD Timeout)
62 {
63 HANDLE Thread;
64
65 DPRINT("ConioConsoleCtrlEvent Parent ProcessId = %x\n", ProcessData->Process->ClientId.UniqueProcess);
66
67 if (ProcessData->CtrlDispatcher)
68 {
69 Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0,
70 ProcessData->CtrlDispatcher,
71 UlongToPtr(Event), 0, NULL);
72 if (NULL == Thread)
73 {
74 DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
75 return;
76 }
77
78 WaitForSingleObject(Thread, Timeout);
79 CloseHandle(Thread);
80 }
81 }
82
83 VOID FASTCALL
84 ConioConsoleCtrlEvent(DWORD Event, PCONSOLE_PROCESS_DATA ProcessData)
85 {
86 ConioConsoleCtrlEventTimeout(Event, ProcessData, 0);
87 }
88
89 static NTSTATUS WINAPI
90 CsrInitConsole(PCSRSS_CONSOLE Console, int ShowCmd)
91 {
92 NTSTATUS Status;
93 SECURITY_ATTRIBUTES SecurityAttributes;
94 PCSRSS_SCREEN_BUFFER NewBuffer;
95 BOOL GuiMode;
96 WCHAR Title[255];
97
98 Console->Title.MaximumLength = Console->Title.Length = 0;
99 Console->Title.Buffer = NULL;
100
101 if (LoadStringW(ConSrvDllInstance, IDS_COMMAND_PROMPT, Title, sizeof(Title) / sizeof(Title[0])))
102 {
103 RtlCreateUnicodeString(&Console->Title, Title);
104 }
105 else
106 {
107 RtlCreateUnicodeString(&Console->Title, L"Command Prompt");
108 }
109
110 Console->ReferenceCount = 0;
111 Console->LineBuffer = NULL;
112 Console->Header.Type = CONIO_CONSOLE_MAGIC;
113 Console->Header.Console = Console;
114 Console->Mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT;
115 InitializeListHead(&Console->BufferList);
116 Console->ActiveBuffer = NULL;
117 InitializeListHead(&Console->ReadWaitQueue);
118 InitializeListHead(&Console->InputEvents);
119 InitializeListHead(&Console->HistoryBuffers);
120 Console->CodePage = GetOEMCP();
121 Console->OutputCodePage = GetOEMCP();
122
123 SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
124 SecurityAttributes.lpSecurityDescriptor = NULL;
125 SecurityAttributes.bInheritHandle = TRUE;
126
127 Console->ActiveEvent = CreateEventW(&SecurityAttributes, TRUE, FALSE, NULL);
128 if (NULL == Console->ActiveEvent)
129 {
130 RtlFreeUnicodeString(&Console->Title);
131 return STATUS_UNSUCCESSFUL;
132 }
133 Console->PrivateData = NULL;
134 InitializeCriticalSection(&Console->Lock);
135
136 GuiMode = DtbgIsDesktopVisible();
137
138 /* allocate console screen buffer */
139 NewBuffer = HeapAlloc(ConSrvHeap, HEAP_ZERO_MEMORY, sizeof(CSRSS_SCREEN_BUFFER));
140 if (NULL == NewBuffer)
141 {
142 RtlFreeUnicodeString(&Console->Title);
143 DeleteCriticalSection(&Console->Lock);
144 CloseHandle(Console->ActiveEvent);
145 return STATUS_INSUFFICIENT_RESOURCES;
146 }
147 /* init screen buffer with defaults */
148 NewBuffer->CursorInfo.bVisible = TRUE;
149 NewBuffer->CursorInfo.dwSize = CSR_DEFAULT_CURSOR_SIZE;
150 /* make console active, and insert into console list */
151 Console->ActiveBuffer = (PCSRSS_SCREEN_BUFFER) NewBuffer;
152
153 /*
154 * If we are not in GUI-mode, start the text-mode console. If we fail,
155 * try to start the GUI-mode console (win32k will automatically switch
156 * to graphical mode, therefore no additional code is needed).
157 */
158 if (!GuiMode)
159 {
160 DPRINT1("CONSRV: Opening text-mode console\n");
161 Status = TuiInitConsole(Console);
162 if (!NT_SUCCESS(Status))
163 {
164 DPRINT1("Failed to open text-mode console, switching to gui-mode, Status = 0x%08lx\n", Status);
165 GuiMode = TRUE;
166 }
167 }
168
169 /*
170 * Try to open the GUI-mode console. Two cases are possible:
171 * - We are in GUI-mode, therefore GuiMode == TRUE, the previous test-case
172 * failed and we start GUI-mode console.
173 * - We are in text-mode, therefore GuiMode == FALSE, the previous test-case
174 * succeeded BUT we failed at starting text-mode console. Then GuiMode
175 * was switched to TRUE in order to try to open the console in GUI-mode.
176 */
177 if (GuiMode)
178 {
179 DPRINT1("CONSRV: Opening GUI-mode console\n");
180 Status = GuiInitConsole(Console, ShowCmd);
181 if (!NT_SUCCESS(Status))
182 {
183 HeapFree(ConSrvHeap,0, NewBuffer);
184 RtlFreeUnicodeString(&Console->Title);
185 DeleteCriticalSection(&Console->Lock);
186 CloseHandle(Console->ActiveEvent);
187 DPRINT1("GuiInitConsole: failed, Status = 0x%08lx\n", Status);
188 return Status;
189 }
190 }
191
192 Status = CsrInitConsoleScreenBuffer(Console, NewBuffer);
193 if (!NT_SUCCESS(Status))
194 {
195 ConioCleanupConsole(Console);
196 RtlFreeUnicodeString(&Console->Title);
197 DeleteCriticalSection(&Console->Lock);
198 CloseHandle(Console->ActiveEvent);
199 HeapFree(ConSrvHeap, 0, NewBuffer);
200 DPRINT1("CsrInitConsoleScreenBuffer: failed\n");
201 return Status;
202 }
203
204 /* copy buffer contents to screen */
205 ConioDrawConsole(Console);
206
207 return STATUS_SUCCESS;
208 }
209
210 CSR_API(SrvOpenConsole)
211 {
212 NTSTATUS Status = STATUS_SUCCESS;
213 PCSRSS_OPEN_CONSOLE OpenConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.OpenConsoleRequest;
214 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
215
216 DPRINT("SrvOpenConsole\n");
217
218 OpenConsoleRequest->Handle = INVALID_HANDLE_VALUE;
219
220 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
221
222 DPRINT1("SrvOpenConsole - Checkpoint 1\n");
223 DPRINT1("ProcessData = 0x%p ; ProcessData->Console = 0x%p\n", ProcessData, ProcessData->Console);
224
225 if (ProcessData->Console)
226 {
227 DWORD DesiredAccess = OpenConsoleRequest->Access;
228 DWORD ShareMode = OpenConsoleRequest->ShareMode;
229
230 PCSRSS_CONSOLE Console = ProcessData->Console;
231 Object_t *Object;
232
233 DPRINT1("SrvOpenConsole - Checkpoint 2\n");
234 EnterCriticalSection(&Console->Lock);
235 DPRINT1("SrvOpenConsole - Checkpoint 3\n");
236
237 if (OpenConsoleRequest->HandleType == HANDLE_OUTPUT)
238 Object = &Console->ActiveBuffer->Header;
239 else // HANDLE_INPUT
240 Object = &Console->Header;
241
242 if (((DesiredAccess & GENERIC_READ) && Object->ExclusiveRead != 0) ||
243 ((DesiredAccess & GENERIC_WRITE) && Object->ExclusiveWrite != 0) ||
244 (!(ShareMode & FILE_SHARE_READ) && Object->AccessRead != 0) ||
245 (!(ShareMode & FILE_SHARE_WRITE) && Object->AccessWrite != 0))
246 {
247 DPRINT1("Sharing violation\n");
248 Status = STATUS_SHARING_VIOLATION;
249 }
250 else
251 {
252 Status = Win32CsrInsertObject(ProcessData,
253 &OpenConsoleRequest->Handle,
254 Object,
255 DesiredAccess,
256 OpenConsoleRequest->Inheritable,
257 ShareMode);
258 }
259
260 LeaveCriticalSection(&Console->Lock);
261 }
262
263 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
264
265 return Status;
266 }
267
268 CSR_API(SrvAllocConsole)
269 {
270 NTSTATUS Status = STATUS_SUCCESS;
271 PCSRSS_ALLOC_CONSOLE AllocConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AllocConsoleRequest;
272 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
273 PCSRSS_CONSOLE Console;
274 BOOLEAN NewConsole = FALSE;
275
276 DPRINT("SrvAllocConsole\n");
277
278 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
279
280 if (ProcessData->Console)
281 {
282 DPRINT1("Process already has a console\n");
283 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
284 return STATUS_INVALID_PARAMETER;
285 }
286
287 DPRINT1("SrvAllocConsole - Checkpoint 1\n");
288
289 /* If we don't need a console, then get out of here */
290 if (!AllocConsoleRequest->ConsoleNeeded)
291 {
292 DPRINT("No console needed\n");
293 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
294 return STATUS_SUCCESS;
295 }
296
297 /* If we already have one, then don't create a new one... */
298 if (!AllocConsoleRequest->Console ||
299 AllocConsoleRequest->Console != ProcessData->ParentConsole)
300 {
301 /* Allocate a console structure */
302 NewConsole = TRUE;
303 Console = HeapAlloc(ConSrvHeap, HEAP_ZERO_MEMORY, sizeof(CSRSS_CONSOLE));
304 if (NULL == Console)
305 {
306 DPRINT1("Not enough memory for console\n");
307 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
308 return STATUS_NO_MEMORY;
309 }
310
311 /* Initialize list head */
312 InitializeListHead(&Console->ProcessList);
313
314 /* Insert process data required for GUI initialization */
315 InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink);
316
317 /* Initialize the Console */
318 Status = CsrInitConsole(Console, AllocConsoleRequest->ShowCmd);
319 if (!NT_SUCCESS(Status))
320 {
321 DPRINT1("Console init failed\n");
322 HeapFree(ConSrvHeap, 0, Console);
323 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
324 return Status;
325 }
326 }
327 else
328 {
329 /* Reuse our current console */
330 Console = AllocConsoleRequest->Console;
331 }
332
333 /* Set the Process Console */
334 ProcessData->Console = Console;
335
336 /* Return it to the caller */
337 AllocConsoleRequest->Console = Console;
338
339 /* Add a reference count because the process is tied to the console */
340 _InterlockedIncrement(&Console->ReferenceCount);
341
342 if (NewConsole || !ProcessData->bInheritHandles)
343 {
344 /* Insert the Objects */
345 Status = Win32CsrInsertObject(ProcessData,
346 &AllocConsoleRequest->InputHandle,
347 &Console->Header,
348 GENERIC_READ | GENERIC_WRITE,
349 TRUE,
350 FILE_SHARE_READ | FILE_SHARE_WRITE);
351 if (! NT_SUCCESS(Status))
352 {
353 DPRINT1("Failed to insert object\n");
354 ConioDeleteConsole((Object_t *) Console);
355 ProcessData->Console = NULL;
356 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
357 return Status;
358 }
359
360 Status = Win32CsrInsertObject(ProcessData,
361 &AllocConsoleRequest->OutputHandle,
362 &Console->ActiveBuffer->Header,
363 GENERIC_READ | GENERIC_WRITE,
364 TRUE,
365 FILE_SHARE_READ | FILE_SHARE_WRITE);
366 if (!NT_SUCCESS(Status))
367 {
368 DPRINT1("Failed to insert object\n");
369 ConioDeleteConsole((Object_t *) Console);
370 Win32CsrReleaseObject(ProcessData,
371 AllocConsoleRequest->InputHandle);
372 ProcessData->Console = NULL;
373 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
374 return Status;
375 }
376 }
377
378 /* Duplicate the Event */
379 Status = NtDuplicateObject(NtCurrentProcess(),
380 ProcessData->Console->ActiveEvent,
381 ProcessData->Process->ProcessHandle,
382 &ProcessData->ConsoleEvent,
383 EVENT_ALL_ACCESS, 0, 0);
384 if (!NT_SUCCESS(Status))
385 {
386 DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
387 ConioDeleteConsole((Object_t *) Console);
388 if (NewConsole || !ProcessData->bInheritHandles)
389 {
390 Win32CsrReleaseObject(ProcessData,
391 AllocConsoleRequest->OutputHandle);
392 Win32CsrReleaseObject(ProcessData,
393 AllocConsoleRequest->InputHandle);
394 }
395 ProcessData->Console = NULL;
396 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
397 return Status;
398 }
399
400 /* Set the Ctrl Dispatcher */
401 ProcessData->CtrlDispatcher = AllocConsoleRequest->CtrlDispatcher;
402 DPRINT("CSRSS:CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher);
403
404 if (!NewConsole)
405 {
406 /* Insert into the list if it has not been added */
407 InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink);
408 }
409
410 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
411 return STATUS_SUCCESS;
412 }
413
414 CSR_API(SrvFreeConsole)
415 {
416 Win32CsrReleaseConsole(CsrGetClientThread()->Process);
417 return STATUS_SUCCESS;
418 }
419
420 VOID WINAPI
421 ConioDeleteConsole(Object_t *Object)
422 {
423 PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) Object;
424 ConsoleInput *Event;
425
426 DPRINT("ConioDeleteConsole\n");
427
428 /* TODO: Dereference all the waits in Console->ReadWaitQueue */
429
430 /* Drain input event queue */
431 while (Console->InputEvents.Flink != &Console->InputEvents)
432 {
433 Event = (ConsoleInput *) Console->InputEvents.Flink;
434 Console->InputEvents.Flink = Console->InputEvents.Flink->Flink;
435 Console->InputEvents.Flink->Flink->Blink = &Console->InputEvents;
436 HeapFree(ConSrvHeap, 0, Event);
437 }
438
439 ConioCleanupConsole(Console);
440 if (Console->LineBuffer)
441 RtlFreeHeap(ConSrvHeap, 0, Console->LineBuffer);
442 while (!IsListEmpty(&Console->HistoryBuffers))
443 HistoryDeleteBuffer((struct tagHISTORY_BUFFER *)Console->HistoryBuffers.Flink);
444
445 ConioDeleteScreenBuffer(Console->ActiveBuffer);
446 if (!IsListEmpty(&Console->BufferList))
447 {
448 DPRINT1("BUG: screen buffer list not empty\n");
449 }
450
451 CloseHandle(Console->ActiveEvent);
452 if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent);
453 DeleteCriticalSection(&Console->Lock);
454 RtlFreeUnicodeString(&Console->Title);
455 IntDeleteAllAliases(Console->Aliases);
456 HeapFree(ConSrvHeap, 0, Console);
457 }
458
459 VOID WINAPI
460 CsrInitConsoleSupport(VOID)
461 {
462 DPRINT("CSR: CsrInitConsoleSupport()\n");
463
464 /* Should call LoadKeyboardLayout */
465 }
466
467 VOID FASTCALL
468 ConioPause(PCSRSS_CONSOLE Console, UINT Flags)
469 {
470 Console->PauseFlags |= Flags;
471 if (!Console->UnpauseEvent)
472 Console->UnpauseEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
473 }
474
475 VOID FASTCALL
476 ConioUnpause(PCSRSS_CONSOLE Console, UINT Flags)
477 {
478 Console->PauseFlags &= ~Flags;
479 if (Console->PauseFlags == 0 && Console->UnpauseEvent)
480 {
481 SetEvent(Console->UnpauseEvent);
482 CloseHandle(Console->UnpauseEvent);
483 Console->UnpauseEvent = NULL;
484 }
485 }
486
487 CSR_API(SrvSetConsoleMode)
488 {
489 NTSTATUS Status;
490 PCSRSS_CONSOLE_MODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
491 PCSRSS_CONSOLE Console;
492 PCSRSS_SCREEN_BUFFER Buff;
493
494 DPRINT("SrvSetConsoleMode\n");
495
496 Status = Win32CsrLockObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
497 ConsoleModeRequest->ConsoleHandle,
498 (Object_t **) &Console, GENERIC_WRITE, 0);
499 if (!NT_SUCCESS(Status)) return Status;
500
501 Buff = (PCSRSS_SCREEN_BUFFER)Console;
502
503 if (CONIO_CONSOLE_MAGIC == Console->Header.Type)
504 {
505 Console->Mode = ConsoleModeRequest->ConsoleMode & CONSOLE_INPUT_MODE_VALID;
506 }
507 else if (CONIO_SCREEN_BUFFER_MAGIC == Console->Header.Type)
508 {
509 Buff->Mode = ConsoleModeRequest->ConsoleMode & CONSOLE_OUTPUT_MODE_VALID;
510 }
511 else
512 {
513 Status = STATUS_INVALID_HANDLE;
514 }
515
516 Win32CsrUnlockObject((Object_t *)Console);
517
518 return Status;
519 }
520
521 CSR_API(SrvGetConsoleMode)
522 {
523 NTSTATUS Status;
524 PCSRSS_CONSOLE_MODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
525 PCSRSS_CONSOLE Console;
526 PCSRSS_SCREEN_BUFFER Buff;
527
528 DPRINT("SrvGetConsoleMode\n");
529
530 Status = Win32CsrLockObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
531 ConsoleModeRequest->ConsoleHandle,
532 (Object_t **) &Console, GENERIC_READ, 0);
533 if (!NT_SUCCESS(Status)) return Status;
534
535 Status = STATUS_SUCCESS;
536 Buff = (PCSRSS_SCREEN_BUFFER) Console;
537
538 if (CONIO_CONSOLE_MAGIC == Console->Header.Type)
539 {
540 ConsoleModeRequest->ConsoleMode = Console->Mode;
541 }
542 else if (CONIO_SCREEN_BUFFER_MAGIC == Buff->Header.Type)
543 {
544 ConsoleModeRequest->ConsoleMode = Buff->Mode;
545 }
546 else
547 {
548 Status = STATUS_INVALID_HANDLE;
549 }
550
551 Win32CsrUnlockObject((Object_t *)Console);
552 return Status;
553 }
554
555 CSR_API(SrvSetConsoleTitle)
556 {
557 NTSTATUS Status;
558 PCSRSS_CONSOLE_TITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
559 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
560 PCSRSS_CONSOLE Console;
561 PWCHAR Buffer;
562
563 DPRINT("SrvSetConsoleTitle\n");
564
565 if (!CsrValidateMessageBuffer(ApiMessage,
566 (PVOID)&TitleRequest->Title,
567 TitleRequest->Length,
568 sizeof(BYTE)))
569 {
570 return STATUS_INVALID_PARAMETER;
571 }
572 /*
573 if (!Win32CsrValidateBuffer(Process, TitleRequest->Title,
574 TitleRequest->Length, 1))
575 {
576 return STATUS_ACCESS_VIOLATION;
577 }
578 */
579
580 Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
581 if(NT_SUCCESS(Status))
582 {
583 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, TitleRequest->Length);
584 if (Buffer)
585 {
586 /* Copy title to console */
587 RtlFreeUnicodeString(&Console->Title);
588 Console->Title.Buffer = Buffer;
589 Console->Title.Length = Console->Title.MaximumLength = TitleRequest->Length;
590 memcpy(Console->Title.Buffer, TitleRequest->Title, Console->Title.Length);
591
592 if (!ConioChangeTitle(Console))
593 {
594 Status = STATUS_UNSUCCESSFUL;
595 }
596 else
597 {
598 Status = STATUS_SUCCESS;
599 }
600 }
601 else
602 {
603 Status = STATUS_NO_MEMORY;
604 }
605
606 ConioUnlockConsole(Console);
607 }
608
609 return Status;
610 }
611
612 CSR_API(SrvGetConsoleTitle)
613 {
614 NTSTATUS Status;
615 PCSRSS_CONSOLE_TITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
616 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
617 PCSRSS_CONSOLE Console;
618 DWORD Length;
619
620 DPRINT("SrvGetConsoleTitle\n");
621
622 if (!CsrValidateMessageBuffer(ApiMessage,
623 (PVOID)&TitleRequest->Title,
624 TitleRequest->Length,
625 sizeof(BYTE)))
626 {
627 return STATUS_INVALID_PARAMETER;
628 }
629 /*
630 if (!Win32CsrValidateBuffer(Process, TitleRequest->Title,
631 TitleRequest->Length, 1))
632 {
633 return STATUS_ACCESS_VIOLATION;
634 }
635 */
636
637 Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
638 if (!NT_SUCCESS(Status))
639 {
640 DPRINT1("Can't get console\n");
641 return Status;
642 }
643
644 /* Copy title of the console to the user title buffer */
645 if (TitleRequest->Length >= sizeof(WCHAR))
646 {
647 Length = min(TitleRequest->Length - sizeof(WCHAR), Console->Title.Length);
648 memcpy(TitleRequest->Title, Console->Title.Buffer, Length);
649 TitleRequest->Title[Length / sizeof(WCHAR)] = L'\0';
650 }
651
652 TitleRequest->Length = Console->Title.Length;
653
654 ConioUnlockConsole(Console);
655 return STATUS_SUCCESS;
656 }
657
658 /**********************************************************************
659 * HardwareStateProperty
660 *
661 * DESCRIPTION
662 * Set/Get the value of the HardwareState and switch
663 * between direct video buffer ouput and GDI windowed
664 * output.
665 * ARGUMENTS
666 * Client hands us a CSRSS_CONSOLE_HARDWARE_STATE
667 * object. We use the same object to Request.
668 * NOTE
669 * ConsoleHwState has the correct size to be compatible
670 * with NT's, but values are not.
671 */
672 static NTSTATUS FASTCALL
673 SetConsoleHardwareState(PCSRSS_CONSOLE Console, DWORD ConsoleHwState)
674 {
675 DPRINT1("Console Hardware State: %d\n", ConsoleHwState);
676
677 if ((CONSOLE_HARDWARE_STATE_GDI_MANAGED == ConsoleHwState)
678 ||(CONSOLE_HARDWARE_STATE_DIRECT == ConsoleHwState))
679 {
680 if (Console->HardwareState != ConsoleHwState)
681 {
682 /* TODO: implement switching from full screen to windowed mode */
683 /* TODO: or back; now simply store the hardware state */
684 Console->HardwareState = ConsoleHwState;
685 }
686
687 return STATUS_SUCCESS;
688 }
689
690 return STATUS_INVALID_PARAMETER_3; /* Client: (handle, set_get, [mode]) */
691 }
692
693 CSR_API(SrvGetConsoleHardwareState)
694 {
695 NTSTATUS Status;
696 PCSRSS_CONSOLE_HW_STATE ConsoleHardwareStateRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleHardwareStateRequest;
697 PCSRSS_CONSOLE Console;
698
699 DPRINT("SrvGetConsoleHardwareState\n");
700
701 Status = ConioLockConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
702 ConsoleHardwareStateRequest->ConsoleHandle,
703 &Console,
704 GENERIC_READ);
705 if (!NT_SUCCESS(Status))
706 {
707 DPRINT1("Failed to get console handle in SrvGetConsoleHardwareState\n");
708 return Status;
709 }
710
711 ConsoleHardwareStateRequest->State = Console->HardwareState;
712
713 ConioUnlockConsole(Console);
714
715 return Status;
716 }
717
718 CSR_API(SrvSetConsoleHardwareState)
719 {
720 NTSTATUS Status;
721 PCSRSS_CONSOLE_HW_STATE ConsoleHardwareStateRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleHardwareStateRequest;
722 PCSRSS_CONSOLE Console;
723
724 DPRINT("SrvSetConsoleHardwareState\n");
725
726 Status = ConioLockConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
727 ConsoleHardwareStateRequest->ConsoleHandle,
728 &Console,
729 GENERIC_READ);
730 if (!NT_SUCCESS(Status))
731 {
732 DPRINT1("Failed to get console handle in SrvSetConsoleHardwareState\n");
733 return Status;
734 }
735
736 DPRINT("Setting console hardware state.\n");
737 Status = SetConsoleHardwareState(Console, ConsoleHardwareStateRequest->State);
738
739 ConioUnlockConsole(Console);
740
741 return Status;
742 }
743
744 CSR_API(SrvGetConsoleWindow)
745 {
746 NTSTATUS Status;
747 PCSRSS_GET_CONSOLE_WINDOW GetConsoleWindowRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleWindowRequest;
748 PCSRSS_CONSOLE Console;
749
750 DPRINT("SrvGetConsoleWindow\n");
751
752 Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
753 if (!NT_SUCCESS(Status)) return Status;
754
755 GetConsoleWindowRequest->WindowHandle = Console->hWindow;
756 ConioUnlockConsole(Console);
757
758 return STATUS_SUCCESS;
759 }
760
761 CSR_API(SrvSetConsoleIcon)
762 {
763 NTSTATUS Status;
764 PCSRSS_SET_CONSOLE_ICON SetConsoleIconRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetConsoleIconRequest;
765 PCSRSS_CONSOLE Console;
766
767 DPRINT("SrvSetConsoleIcon\n");
768
769 Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
770 if (!NT_SUCCESS(Status)) return Status;
771
772 Status = (ConioChangeIcon(Console, SetConsoleIconRequest->WindowIcon)
773 ? STATUS_SUCCESS
774 : STATUS_UNSUCCESSFUL);
775
776 ConioUnlockConsole(Console);
777
778 return Status;
779 }
780
781 CSR_API(SrvGetConsoleCP)
782 {
783 NTSTATUS Status;
784 PCSRSS_CONSOLE_CP ConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleCPRequest;
785 PCSRSS_CONSOLE Console;
786
787 DPRINT("SrvGetConsoleCP, getting %s Code Page\n",
788 ConsoleCPRequest->InputCP ? "Input" : "Output");
789
790 Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
791 if (!NT_SUCCESS(Status)) return Status;
792
793 ConsoleCPRequest->CodePage = (ConsoleCPRequest->InputCP ? Console->CodePage
794 : Console->OutputCodePage);
795 ConioUnlockConsole(Console);
796 return STATUS_SUCCESS;
797 }
798
799 CSR_API(SrvSetConsoleCP)
800 {
801 NTSTATUS Status;
802 PCSRSS_CONSOLE_CP ConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleCPRequest;
803 PCSRSS_CONSOLE Console;
804
805 DPRINT("SrvSetConsoleCP, setting %s Code Page\n",
806 ConsoleCPRequest->InputCP ? "Input" : "Output");
807
808 Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
809 if (!NT_SUCCESS(Status)) return Status;
810
811 if (IsValidCodePage(ConsoleCPRequest->CodePage))
812 {
813 if (ConsoleCPRequest->InputCP)
814 Console->CodePage = ConsoleCPRequest->CodePage;
815 else
816 Console->OutputCodePage = ConsoleCPRequest->CodePage;
817
818 ConioUnlockConsole(Console);
819 return STATUS_SUCCESS;
820 }
821
822 ConioUnlockConsole(Console);
823 return STATUS_INVALID_PARAMETER;
824 }
825
826 CSR_API(SrvGetConsoleProcessList)
827 {
828 NTSTATUS Status;
829 PCSRSS_GET_PROCESS_LIST GetProcessListRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetProcessListRequest;
830 PDWORD Buffer;
831 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
832 PCSRSS_CONSOLE Console;
833 PCONSOLE_PROCESS_DATA current;
834 PLIST_ENTRY current_entry;
835 ULONG nItems = 0;
836
837 DPRINT("SrvGetConsoleProcessList\n");
838
839 if (!CsrValidateMessageBuffer(ApiMessage,
840 (PVOID)&GetProcessListRequest->pProcessIds,
841 GetProcessListRequest->nMaxIds,
842 sizeof(DWORD)))
843 {
844 return STATUS_INVALID_PARAMETER;
845 }
846
847 Buffer = GetProcessListRequest->pProcessIds;
848
849 /*
850 if (!Win32CsrValidateBuffer(ProcessData, Buffer, GetProcessListRequest->nMaxIds, sizeof(DWORD)))
851 return STATUS_ACCESS_VIOLATION;
852 */
853
854 Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
855 if (!NT_SUCCESS(Status)) return Status;
856
857 for (current_entry = Console->ProcessList.Flink;
858 current_entry != &Console->ProcessList;
859 current_entry = current_entry->Flink)
860 {
861 current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink);
862 if (++nItems <= GetProcessListRequest->nMaxIds)
863 {
864 *Buffer++ = HandleToUlong(current->Process->ClientId.UniqueProcess);
865 }
866 }
867
868 ConioUnlockConsole(Console);
869
870 GetProcessListRequest->nProcessIdsTotal = nItems;
871 return STATUS_SUCCESS;
872 }
873
874 CSR_API(SrvGenerateConsoleCtrlEvent)
875 {
876 NTSTATUS Status;
877 PCSRSS_GENERATE_CTRL_EVENT GenerateCtrlEvent = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GenerateCtrlEvent;
878 PCSRSS_CONSOLE Console;
879 PCONSOLE_PROCESS_DATA current;
880 PLIST_ENTRY current_entry;
881 DWORD Group;
882
883 Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
884 if (!NT_SUCCESS(Status)) return Status;
885
886 Group = GenerateCtrlEvent->ProcessGroup;
887 Status = STATUS_INVALID_PARAMETER;
888 for (current_entry = Console->ProcessList.Flink;
889 current_entry != &Console->ProcessList;
890 current_entry = current_entry->Flink)
891 {
892 current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink);
893 if (Group == 0 || current->Process->ProcessGroupId == Group)
894 {
895 ConioConsoleCtrlEvent(GenerateCtrlEvent->Event, current);
896 Status = STATUS_SUCCESS;
897 }
898 }
899
900 ConioUnlockConsole(Console);
901
902 return Status;
903 }
904
905 CSR_API(SrvGetConsoleSelectionInfo)
906 {
907 NTSTATUS Status;
908 PCSRSS_GET_CONSOLE_SELECTION_INFO GetConsoleSelectionInfo = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleSelectionInfo;
909 PCSRSS_CONSOLE Console;
910
911 Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
912 if (NT_SUCCESS(Status))
913 {
914 memset(&GetConsoleSelectionInfo->Info, 0, sizeof(CONSOLE_SELECTION_INFO));
915 if (Console->Selection.dwFlags != 0)
916 GetConsoleSelectionInfo->Info = Console->Selection;
917 ConioUnlockConsole(Console);
918 }
919
920 return Status;
921 }
922
923 /* EOF */