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