[KERNEL32]
[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 /* Notify all the waits only if we see Ctrl-C or Ctrl-Break */
68 if (Event == CTRL_C_EVENT || Event == CTRL_BREAK_EVENT)
69 {
70 DWORD Flag = (1 << Event); // Transform an integer value to a power of 2.
71 NTSTATUS Status;
72 PCSRSS_CONSOLE Console;
73 // LIST_ENTRY WaitQueue;
74
75 DPRINT1("ConioConsoleCtrlEvent - Ctrl-C captured\n");
76 Status = ConioConsoleFromProcessData(ProcessData, &Console);
77 if (NT_SUCCESS(Status))
78 {
79 DPRINT1("ConioConsoleCtrlEvent - console captured, try to dereference waits...\n");
80 /*
81 * Wake-up all of the writing waiters, dereference them
82 * and purge them all from the list.
83 */
84 if (CsrNotifyWait(&Console->ReadWaitQueue,
85 WaitAll,
86 (PVOID)Flag,
87 NULL))
88 {
89 DPRINT1("ConioConsoleCtrlEvent - waits dereferenced...\n");
90 // InitializeListHead(&WaitQueue);
91
92 // CsrMoveSatisfiedWait(&WaitQueue, &Console->ReadWaitQueue);
93 if (!IsListEmpty(&Console->ReadWaitQueue /* &WaitQueue */))
94 {
95 CsrDereferenceWait(&Console->ReadWaitQueue /* &WaitQueue */);
96 }
97 }
98 ConioUnlockConsole(Console); // NOTE_WAITS: <-- Here we have the possibility to free the console waits also.
99 }
100 }
101
102 /* Notify the process of the control event */
103 if (ProcessData->CtrlDispatcher)
104 {
105 Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0,
106 ProcessData->CtrlDispatcher,
107 UlongToPtr(Event), 0, NULL);
108 if (NULL == Thread)
109 {
110 DPRINT1("Failed thread creation (Error: 0x%x)\n", GetLastError());
111 return;
112 }
113
114 DPRINT1("We succeeded at creating ProcessData->CtrlDispatcher remote thread, ProcessId = %x, Process = 0x%p\n", ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process);
115 WaitForSingleObject(Thread, Timeout);
116 CloseHandle(Thread);
117 }
118 }
119
120 VOID FASTCALL
121 ConioConsoleCtrlEvent(DWORD Event, PCONSOLE_PROCESS_DATA ProcessData)
122 {
123 ConioConsoleCtrlEventTimeout(Event, ProcessData, 0);
124 }
125
126 /* static */ NTSTATUS WINAPI
127 CsrInitConsole(PCSRSS_CONSOLE* NewConsole, int ShowCmd)
128 {
129 NTSTATUS Status;
130 SECURITY_ATTRIBUTES SecurityAttributes;
131 PCSRSS_CONSOLE Console;
132 PCSRSS_SCREEN_BUFFER NewBuffer;
133 BOOL GuiMode;
134 WCHAR Title[255];
135
136 if (NewConsole == NULL) return STATUS_INVALID_PARAMETER;
137
138 *NewConsole = NULL;
139
140 /* Allocate a console structure */
141 Console = HeapAlloc(ConSrvHeap, HEAP_ZERO_MEMORY, sizeof(CSRSS_CONSOLE));
142 if (NULL == Console)
143 {
144 DPRINT1("Not enough memory for console creation.\n");
145 return STATUS_NO_MEMORY;
146 }
147
148 /* Initialize the console */
149 Console->Title.MaximumLength = Console->Title.Length = 0;
150 Console->Title.Buffer = NULL;
151
152 if (LoadStringW(ConSrvDllInstance, IDS_COMMAND_PROMPT, Title, sizeof(Title) / sizeof(Title[0])))
153 {
154 RtlCreateUnicodeString(&Console->Title, Title);
155 }
156 else
157 {
158 RtlCreateUnicodeString(&Console->Title, L"Command Prompt");
159 }
160
161 Console->ReferenceCount = 0;
162 Console->LineBuffer = NULL;
163 Console->Header.Type = CONIO_CONSOLE_MAGIC;
164 Console->Header.Console = Console;
165 Console->Mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT;
166 InitializeListHead(&Console->ProcessList);
167 InitializeListHead(&Console->BufferList);
168 Console->ActiveBuffer = NULL;
169 // Console->SatisfiedWaits = NULL;
170 InitializeListHead(&Console->ReadWaitQueue);
171 InitializeListHead(&Console->WriteWaitQueue);
172 InitializeListHead(&Console->InputEvents);
173 InitializeListHead(&Console->HistoryBuffers);
174 Console->CodePage = GetOEMCP();
175 Console->OutputCodePage = GetOEMCP();
176
177 SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
178 SecurityAttributes.lpSecurityDescriptor = NULL;
179 SecurityAttributes.bInheritHandle = TRUE;
180
181 Console->ActiveEvent = CreateEventW(&SecurityAttributes, TRUE, FALSE, NULL);
182 if (NULL == Console->ActiveEvent)
183 {
184 RtlFreeUnicodeString(&Console->Title);
185 HeapFree(ConSrvHeap, 0, Console);
186 return STATUS_UNSUCCESSFUL;
187 }
188 Console->PrivateData = NULL;
189 InitializeCriticalSection(&Console->Lock);
190
191 GuiMode = DtbgIsDesktopVisible();
192
193 /* allocate console screen buffer */
194 NewBuffer = HeapAlloc(ConSrvHeap, HEAP_ZERO_MEMORY, sizeof(CSRSS_SCREEN_BUFFER));
195 if (NULL == NewBuffer)
196 {
197 RtlFreeUnicodeString(&Console->Title);
198 DeleteCriticalSection(&Console->Lock);
199 CloseHandle(Console->ActiveEvent);
200 HeapFree(ConSrvHeap, 0, Console);
201 return STATUS_INSUFFICIENT_RESOURCES;
202 }
203 /* init screen buffer with defaults */
204 NewBuffer->CursorInfo.bVisible = TRUE;
205 NewBuffer->CursorInfo.dwSize = CSR_DEFAULT_CURSOR_SIZE;
206 /* make console active, and insert into console list */
207 Console->ActiveBuffer = (PCSRSS_SCREEN_BUFFER) NewBuffer;
208
209 /*
210 * If we are not in GUI-mode, start the text-mode console. If we fail,
211 * try to start the GUI-mode console (win32k will automatically switch
212 * to graphical mode, therefore no additional code is needed).
213 */
214 if (!GuiMode)
215 {
216 DPRINT1("CONSRV: Opening text-mode console\n");
217 Status = TuiInitConsole(Console);
218 if (!NT_SUCCESS(Status))
219 {
220 DPRINT1("Failed to open text-mode console, switching to gui-mode, Status = 0x%08lx\n", Status);
221 GuiMode = TRUE;
222 }
223 }
224
225 /*
226 * Try to open the GUI-mode console. Two cases are possible:
227 * - We are in GUI-mode, therefore GuiMode == TRUE, the previous test-case
228 * failed and we start GUI-mode console.
229 * - We are in text-mode, therefore GuiMode == FALSE, the previous test-case
230 * succeeded BUT we failed at starting text-mode console. Then GuiMode
231 * was switched to TRUE in order to try to open the console in GUI-mode.
232 */
233 if (GuiMode)
234 {
235 DPRINT1("CONSRV: Opening GUI-mode console\n");
236 Status = GuiInitConsole(Console, ShowCmd);
237 if (!NT_SUCCESS(Status))
238 {
239 HeapFree(ConSrvHeap,0, NewBuffer);
240 RtlFreeUnicodeString(&Console->Title);
241 DeleteCriticalSection(&Console->Lock);
242 CloseHandle(Console->ActiveEvent);
243 DPRINT1("GuiInitConsole: failed, Status = 0x%08lx\n", Status);
244 HeapFree(ConSrvHeap, 0, Console);
245 return Status;
246 }
247 }
248
249 Status = CsrInitConsoleScreenBuffer(Console, NewBuffer);
250 if (!NT_SUCCESS(Status))
251 {
252 ConioCleanupConsole(Console);
253 RtlFreeUnicodeString(&Console->Title);
254 DeleteCriticalSection(&Console->Lock);
255 CloseHandle(Console->ActiveEvent);
256 HeapFree(ConSrvHeap, 0, NewBuffer);
257 DPRINT1("CsrInitConsoleScreenBuffer: failed\n");
258 HeapFree(ConSrvHeap, 0, Console);
259 return Status;
260 }
261
262 /* Copy buffer contents to screen */
263 ConioDrawConsole(Console);
264
265 *NewConsole = Console;
266
267 return STATUS_SUCCESS;
268 }
269
270 CSR_API(SrvOpenConsole)
271 {
272 NTSTATUS Status = STATUS_SUCCESS;
273 PCSRSS_OPEN_CONSOLE OpenConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.OpenConsoleRequest;
274 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
275
276 DPRINT("SrvOpenConsole\n");
277
278 OpenConsoleRequest->Handle = INVALID_HANDLE_VALUE;
279
280 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
281
282 DPRINT1("SrvOpenConsole - Checkpoint 1\n");
283 DPRINT1("ProcessData = 0x%p ; ProcessData->Console = 0x%p\n", ProcessData, ProcessData->Console);
284
285 if (ProcessData->Console)
286 {
287 DWORD DesiredAccess = OpenConsoleRequest->Access;
288 DWORD ShareMode = OpenConsoleRequest->ShareMode;
289
290 PCSRSS_CONSOLE Console = ProcessData->Console;
291 Object_t *Object;
292
293 DPRINT1("SrvOpenConsole - Checkpoint 2\n");
294 EnterCriticalSection(&Console->Lock);
295 DPRINT1("SrvOpenConsole - Checkpoint 3\n");
296
297 if (OpenConsoleRequest->HandleType == HANDLE_OUTPUT)
298 Object = &Console->ActiveBuffer->Header;
299 else // HANDLE_INPUT
300 Object = &Console->Header;
301
302 if (((DesiredAccess & GENERIC_READ) && Object->ExclusiveRead != 0) ||
303 ((DesiredAccess & GENERIC_WRITE) && Object->ExclusiveWrite != 0) ||
304 (!(ShareMode & FILE_SHARE_READ) && Object->AccessRead != 0) ||
305 (!(ShareMode & FILE_SHARE_WRITE) && Object->AccessWrite != 0))
306 {
307 DPRINT1("Sharing violation\n");
308 Status = STATUS_SHARING_VIOLATION;
309 }
310 else
311 {
312 Status = Win32CsrInsertObject(ProcessData,
313 &OpenConsoleRequest->Handle,
314 Object,
315 DesiredAccess,
316 OpenConsoleRequest->Inheritable,
317 ShareMode);
318 }
319
320 LeaveCriticalSection(&Console->Lock);
321 }
322
323 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
324
325 return Status;
326 }
327
328 CSR_API(SrvAllocConsole)
329 {
330 NTSTATUS Status = STATUS_SUCCESS;
331 PCSRSS_ALLOC_CONSOLE AllocConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AllocConsoleRequest;
332 PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
333
334 DPRINT("SrvAllocConsole\n");
335
336 if (ProcessData->Console != NULL)
337 {
338 DPRINT1("Process already has a console\n");
339 return STATUS_INVALID_PARAMETER;
340 }
341
342 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
343
344 DPRINT1("SrvAllocConsole - Checkpoint 1\n");
345
346 /* Initialize a new Console */
347 Status = CsrInitConsole(&ProcessData->Console, AllocConsoleRequest->ShowCmd);
348 if (!NT_SUCCESS(Status))
349 {
350 DPRINT1("Console initialization failed\n");
351 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
352 return Status;
353 }
354
355 /* Insert the process into the processes list of the console */
356 InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink);
357
358 /* Return it to the caller */
359 AllocConsoleRequest->Console = ProcessData->Console;
360
361 /* Add a reference count because the process is tied to the console */
362 _InterlockedIncrement(&ProcessData->Console->ReferenceCount);
363
364 #if 0000
365 /*
366 * We've just created a new console. However when ConsoleNewProcess was
367 * called, we didn't know that we wanted to create a new console and
368 * therefore, we by default inherited the handles table from our parent
369 * process. It's only now that we notice that in fact we do not need
370 * them, because we've created a new console and thus we must use it.
371 *
372 * Therefore, free our handles table and recreate a new one.
373 */
374
375 ULONG i;
376
377 /* Close all console handles and free the handle table memory */
378 for (i = 0; i < ProcessData->HandleTableSize; i++)
379 {
380 Win32CsrCloseHandleEntry(&ProcessData->HandleTable[i]);
381 }
382 ProcessData->HandleTableSize = 0;
383 RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
384 ProcessData->HandleTable = NULL;
385 #endif
386
387 /*
388 * Create a new handle table - Insert the IO handles
389 */
390
391 /* Insert the Input handle */
392 Status = Win32CsrInsertObject(ProcessData,
393 &AllocConsoleRequest->InputHandle,
394 &ProcessData->Console->Header,
395 GENERIC_READ | GENERIC_WRITE,
396 TRUE,
397 FILE_SHARE_READ | FILE_SHARE_WRITE);
398 if (!NT_SUCCESS(Status))
399 {
400 DPRINT1("Failed to insert the input handle\n");
401 ConioDeleteConsole(ProcessData->Console);
402 ProcessData->Console = NULL;
403 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
404 return Status;
405 }
406
407 /* Insert the Output handle */
408 Status = Win32CsrInsertObject(ProcessData,
409 &AllocConsoleRequest->OutputHandle,
410 &ProcessData->Console->ActiveBuffer->Header,
411 GENERIC_READ | GENERIC_WRITE,
412 TRUE,
413 FILE_SHARE_READ | FILE_SHARE_WRITE);
414 if (!NT_SUCCESS(Status))
415 {
416 DPRINT1("Failed to insert the output handle\n");
417 ConioDeleteConsole(ProcessData->Console);
418 Win32CsrReleaseObject(ProcessData,
419 AllocConsoleRequest->InputHandle);
420 ProcessData->Console = NULL;
421 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
422 return Status;
423 }
424
425 /* Insert the Error handle */
426 Status = Win32CsrInsertObject(ProcessData,
427 &AllocConsoleRequest->ErrorHandle,
428 &ProcessData->Console->ActiveBuffer->Header,
429 GENERIC_READ | GENERIC_WRITE,
430 TRUE,
431 FILE_SHARE_READ | FILE_SHARE_WRITE);
432 if (!NT_SUCCESS(Status))
433 {
434 DPRINT1("Failed to insert the error handle\n");
435 ConioDeleteConsole(ProcessData->Console);
436 Win32CsrReleaseObject(ProcessData,
437 AllocConsoleRequest->OutputHandle);
438 Win32CsrReleaseObject(ProcessData,
439 AllocConsoleRequest->InputHandle);
440 ProcessData->Console = NULL;
441 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
442 return Status;
443 }
444
445 /* Duplicate the Event */
446 Status = NtDuplicateObject(NtCurrentProcess(),
447 ProcessData->Console->ActiveEvent,
448 ProcessData->Process->ProcessHandle,
449 &ProcessData->ConsoleEvent,
450 EVENT_ALL_ACCESS, 0, 0);
451 if (!NT_SUCCESS(Status))
452 {
453 DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
454 ConioDeleteConsole(ProcessData->Console);
455 // if (NewConsole /* || !ProcessData->bInheritHandles */)
456 {
457 Win32CsrReleaseObject(ProcessData,
458 AllocConsoleRequest->ErrorHandle);
459 Win32CsrReleaseObject(ProcessData,
460 AllocConsoleRequest->OutputHandle);
461 Win32CsrReleaseObject(ProcessData,
462 AllocConsoleRequest->InputHandle);
463 }
464 ProcessData->Console = NULL;
465 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
466 return Status;
467 }
468 /* Input Wait Handle */
469 AllocConsoleRequest->InputWaitHandle = ProcessData->ConsoleEvent;
470
471 /* Set the Ctrl Dispatcher */
472 ProcessData->CtrlDispatcher = AllocConsoleRequest->CtrlDispatcher;
473 DPRINT("CSRSS:CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher);
474
475 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
476 return STATUS_SUCCESS;
477 }
478
479 CSR_API(SrvFreeConsole)
480 {
481 DPRINT1("SrvFreeConsole\n");
482 Win32CsrReleaseConsole(CsrGetClientThread()->Process);
483 return STATUS_SUCCESS;
484 }
485
486 VOID WINAPI
487 ConioDeleteConsole(PCSRSS_CONSOLE Console)
488 {
489 ConsoleInput *Event;
490
491 DPRINT("ConioDeleteConsole\n");
492
493 /* TODO: Dereference all the waits in Console->ReadWaitQueue */
494 /* TODO: Dereference all the waits in Console->WriteWaitQueue */
495
496 /* Drain input event queue */
497 while (Console->InputEvents.Flink != &Console->InputEvents)
498 {
499 Event = (ConsoleInput *) Console->InputEvents.Flink;
500 Console->InputEvents.Flink = Console->InputEvents.Flink->Flink;
501 Console->InputEvents.Flink->Flink->Blink = &Console->InputEvents;
502 HeapFree(ConSrvHeap, 0, Event);
503 }
504
505 ConioCleanupConsole(Console);
506 if (Console->LineBuffer)
507 RtlFreeHeap(ConSrvHeap, 0, Console->LineBuffer);
508 while (!IsListEmpty(&Console->HistoryBuffers))
509 HistoryDeleteBuffer((struct tagHISTORY_BUFFER *)Console->HistoryBuffers.Flink);
510
511 ConioDeleteScreenBuffer(Console->ActiveBuffer);
512 if (!IsListEmpty(&Console->BufferList))
513 {
514 DPRINT1("BUG: screen buffer list not empty\n");
515 }
516
517 CloseHandle(Console->ActiveEvent);
518 if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent);
519 DeleteCriticalSection(&Console->Lock);
520 RtlFreeUnicodeString(&Console->Title);
521 IntDeleteAllAliases(Console->Aliases);
522 HeapFree(ConSrvHeap, 0, Console);
523 }
524
525 VOID WINAPI
526 CsrInitConsoleSupport(VOID)
527 {
528 DPRINT("CSR: CsrInitConsoleSupport()\n");
529
530 /* Should call LoadKeyboardLayout */
531 }
532
533 VOID FASTCALL
534 ConioPause(PCSRSS_CONSOLE Console, UINT Flags)
535 {
536 Console->PauseFlags |= Flags;
537 if (!Console->UnpauseEvent)
538 Console->UnpauseEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
539 }
540
541 VOID FASTCALL
542 ConioUnpause(PCSRSS_CONSOLE Console, UINT Flags)
543 {
544 // LIST_ENTRY WaitQueue;
545
546 Console->PauseFlags &= ~Flags;
547
548 // if ((Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION)) == 0)
549 if (Console->PauseFlags == 0 && Console->UnpauseEvent)
550 {
551 SetEvent(Console->UnpauseEvent);
552 CloseHandle(Console->UnpauseEvent);
553 Console->UnpauseEvent = NULL;
554
555 /*
556 * Wake-up all of the writing waiters, dereference them
557 * and purge them all from the list.
558 */
559 if (CsrNotifyWait(&Console->WriteWaitQueue,
560 WaitAll,
561 NULL,
562 NULL))
563 {
564 // InitializeListHead(&WaitQueue);
565
566 // CsrMoveSatisfiedWait(&WaitQueue, &Console->WriteWaitQueue);
567 if (!IsListEmpty(&Console->WriteWaitQueue /* &WaitQueue */))
568 {
569 CsrDereferenceWait(&Console->WriteWaitQueue /* &WaitQueue */);
570 }
571 }
572 }
573 }
574
575 CSR_API(SrvSetConsoleMode)
576 {
577 NTSTATUS Status;
578 PCSRSS_CONSOLE_MODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
579 PCSRSS_CONSOLE Console;
580 PCSRSS_SCREEN_BUFFER Buff;
581
582 DPRINT("SrvSetConsoleMode\n");
583
584 Status = Win32CsrLockObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
585 ConsoleModeRequest->ConsoleHandle,
586 (Object_t **) &Console, GENERIC_WRITE, 0);
587 if (!NT_SUCCESS(Status)) return Status;
588
589 Buff = (PCSRSS_SCREEN_BUFFER)Console;
590
591 if (CONIO_CONSOLE_MAGIC == Console->Header.Type)
592 {
593 Console->Mode = ConsoleModeRequest->ConsoleMode & CONSOLE_INPUT_MODE_VALID;
594 }
595 else if (CONIO_SCREEN_BUFFER_MAGIC == Console->Header.Type)
596 {
597 Buff->Mode = ConsoleModeRequest->ConsoleMode & CONSOLE_OUTPUT_MODE_VALID;
598 }
599 else
600 {
601 Status = STATUS_INVALID_HANDLE;
602 }
603
604 Win32CsrUnlockObject((Object_t *)Console);
605
606 return Status;
607 }
608
609 CSR_API(SrvGetConsoleMode)
610 {
611 NTSTATUS Status;
612 PCSRSS_CONSOLE_MODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
613 PCSRSS_CONSOLE Console;
614 PCSRSS_SCREEN_BUFFER Buff;
615
616 DPRINT("SrvGetConsoleMode\n");
617
618 Status = Win32CsrLockObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
619 ConsoleModeRequest->ConsoleHandle,
620 (Object_t **) &Console, GENERIC_READ, 0);
621 if (!NT_SUCCESS(Status)) return Status;
622
623 Status = STATUS_SUCCESS;
624 Buff = (PCSRSS_SCREEN_BUFFER) Console;
625
626 if (CONIO_CONSOLE_MAGIC == Console->Header.Type)
627 {
628 ConsoleModeRequest->ConsoleMode = Console->Mode;
629 }
630 else if (CONIO_SCREEN_BUFFER_MAGIC == Buff->Header.Type)
631 {
632 ConsoleModeRequest->ConsoleMode = Buff->Mode;
633 }
634 else
635 {
636 Status = STATUS_INVALID_HANDLE;
637 }
638
639 Win32CsrUnlockObject((Object_t *)Console);
640 return Status;
641 }
642
643 CSR_API(SrvSetConsoleTitle)
644 {
645 NTSTATUS Status;
646 PCSRSS_CONSOLE_TITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
647 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
648 PCSRSS_CONSOLE 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 = ConioConsoleFromProcessData(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 PCSRSS_CONSOLE_TITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
697 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
698 PCSRSS_CONSOLE 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 = ConioConsoleFromProcessData(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 CSRSS_CONSOLE_HARDWARE_STATE
741 * object. 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(PCSRSS_CONSOLE 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 PCSRSS_CONSOLE_HW_STATE ConsoleHardwareStateRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleHardwareStateRequest;
771 PCSRSS_CONSOLE Console;
772
773 DPRINT("SrvGetConsoleHardwareState\n");
774
775 Status = ConioLockConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
776 ConsoleHardwareStateRequest->ConsoleHandle,
777 &Console,
778 GENERIC_READ);
779 if (!NT_SUCCESS(Status))
780 {
781 DPRINT1("Failed to get console handle in SrvGetConsoleHardwareState\n");
782 return Status;
783 }
784
785 ConsoleHardwareStateRequest->State = Console->HardwareState;
786
787 ConioUnlockConsole(Console);
788
789 return Status;
790 }
791
792 CSR_API(SrvSetConsoleHardwareState)
793 {
794 NTSTATUS Status;
795 PCSRSS_CONSOLE_HW_STATE ConsoleHardwareStateRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleHardwareStateRequest;
796 PCSRSS_CONSOLE Console;
797
798 DPRINT("SrvSetConsoleHardwareState\n");
799
800 Status = ConioLockConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
801 ConsoleHardwareStateRequest->ConsoleHandle,
802 &Console,
803 GENERIC_READ);
804 if (!NT_SUCCESS(Status))
805 {
806 DPRINT1("Failed to get console handle in SrvSetConsoleHardwareState\n");
807 return Status;
808 }
809
810 DPRINT("Setting console hardware state.\n");
811 Status = SetConsoleHardwareState(Console, ConsoleHardwareStateRequest->State);
812
813 ConioUnlockConsole(Console);
814
815 return Status;
816 }
817
818 CSR_API(SrvGetConsoleWindow)
819 {
820 NTSTATUS Status;
821 PCSRSS_GET_CONSOLE_WINDOW GetConsoleWindowRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleWindowRequest;
822 PCSRSS_CONSOLE Console;
823
824 DPRINT("SrvGetConsoleWindow\n");
825
826 Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
827 if (!NT_SUCCESS(Status)) return Status;
828
829 GetConsoleWindowRequest->WindowHandle = Console->hWindow;
830 ConioUnlockConsole(Console);
831
832 return STATUS_SUCCESS;
833 }
834
835 CSR_API(SrvSetConsoleIcon)
836 {
837 NTSTATUS Status;
838 PCSRSS_SET_CONSOLE_ICON SetConsoleIconRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetConsoleIconRequest;
839 PCSRSS_CONSOLE Console;
840
841 DPRINT("SrvSetConsoleIcon\n");
842
843 Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
844 if (!NT_SUCCESS(Status)) return Status;
845
846 Status = (ConioChangeIcon(Console, SetConsoleIconRequest->WindowIcon)
847 ? STATUS_SUCCESS
848 : STATUS_UNSUCCESSFUL);
849
850 ConioUnlockConsole(Console);
851
852 return Status;
853 }
854
855 CSR_API(SrvGetConsoleCP)
856 {
857 NTSTATUS Status;
858 PCSRSS_CONSOLE_CP ConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleCPRequest;
859 PCSRSS_CONSOLE Console;
860
861 DPRINT("SrvGetConsoleCP, getting %s Code Page\n",
862 ConsoleCPRequest->InputCP ? "Input" : "Output");
863
864 Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
865 if (!NT_SUCCESS(Status)) return Status;
866
867 ConsoleCPRequest->CodePage = (ConsoleCPRequest->InputCP ? Console->CodePage
868 : Console->OutputCodePage);
869 ConioUnlockConsole(Console);
870 return STATUS_SUCCESS;
871 }
872
873 CSR_API(SrvSetConsoleCP)
874 {
875 NTSTATUS Status;
876 PCSRSS_CONSOLE_CP ConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleCPRequest;
877 PCSRSS_CONSOLE Console;
878
879 DPRINT("SrvSetConsoleCP, setting %s Code Page\n",
880 ConsoleCPRequest->InputCP ? "Input" : "Output");
881
882 Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
883 if (!NT_SUCCESS(Status)) return Status;
884
885 if (IsValidCodePage(ConsoleCPRequest->CodePage))
886 {
887 if (ConsoleCPRequest->InputCP)
888 Console->CodePage = ConsoleCPRequest->CodePage;
889 else
890 Console->OutputCodePage = ConsoleCPRequest->CodePage;
891
892 ConioUnlockConsole(Console);
893 return STATUS_SUCCESS;
894 }
895
896 ConioUnlockConsole(Console);
897 return STATUS_INVALID_PARAMETER;
898 }
899
900 CSR_API(SrvGetConsoleProcessList)
901 {
902 NTSTATUS Status;
903 PCSRSS_GET_PROCESS_LIST GetProcessListRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetProcessListRequest;
904 PDWORD Buffer;
905 // PCSR_PROCESS Process = CsrGetClientThread()->Process;
906 PCSRSS_CONSOLE Console;
907 PCONSOLE_PROCESS_DATA current;
908 PLIST_ENTRY current_entry;
909 ULONG nItems = 0;
910
911 DPRINT("SrvGetConsoleProcessList\n");
912
913 if (!CsrValidateMessageBuffer(ApiMessage,
914 (PVOID)&GetProcessListRequest->pProcessIds,
915 GetProcessListRequest->nMaxIds,
916 sizeof(DWORD)))
917 {
918 return STATUS_INVALID_PARAMETER;
919 }
920
921 Buffer = GetProcessListRequest->pProcessIds;
922
923 Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
924 if (!NT_SUCCESS(Status)) return Status;
925
926 for (current_entry = Console->ProcessList.Flink;
927 current_entry != &Console->ProcessList;
928 current_entry = current_entry->Flink)
929 {
930 current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink);
931 if (++nItems <= GetProcessListRequest->nMaxIds)
932 {
933 *Buffer++ = HandleToUlong(current->Process->ClientId.UniqueProcess);
934 }
935 }
936
937 ConioUnlockConsole(Console);
938
939 GetProcessListRequest->nProcessIdsTotal = nItems;
940 return STATUS_SUCCESS;
941 }
942
943 CSR_API(SrvGenerateConsoleCtrlEvent)
944 {
945 NTSTATUS Status;
946 PCSRSS_GENERATE_CTRL_EVENT GenerateCtrlEvent = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GenerateCtrlEvent;
947 PCSRSS_CONSOLE Console;
948 PCONSOLE_PROCESS_DATA current;
949 PLIST_ENTRY current_entry;
950 DWORD Group;
951
952 Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
953 if (!NT_SUCCESS(Status)) return Status;
954
955 Group = GenerateCtrlEvent->ProcessGroup;
956 Status = STATUS_INVALID_PARAMETER;
957 for (current_entry = Console->ProcessList.Flink;
958 current_entry != &Console->ProcessList;
959 current_entry = current_entry->Flink)
960 {
961 current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink);
962 if (Group == 0 || current->Process->ProcessGroupId == Group)
963 {
964 ConioConsoleCtrlEvent(GenerateCtrlEvent->Event, current);
965 Status = STATUS_SUCCESS;
966 }
967 }
968
969 ConioUnlockConsole(Console);
970
971 return Status;
972 }
973
974 CSR_API(SrvGetConsoleSelectionInfo)
975 {
976 NTSTATUS Status;
977 PCSRSS_GET_CONSOLE_SELECTION_INFO GetConsoleSelectionInfo = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleSelectionInfo;
978 PCSRSS_CONSOLE Console;
979
980 Status = ConioConsoleFromProcessData(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console);
981 if (NT_SUCCESS(Status))
982 {
983 memset(&GetConsoleSelectionInfo->Info, 0, sizeof(CONSOLE_SELECTION_INFO));
984 if (Console->Selection.dwFlags != 0)
985 GetConsoleSelectionInfo->Info = Console->Selection;
986 ConioUnlockConsole(Console);
987 }
988
989 return Status;
990 }
991
992 /* EOF */