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