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