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