- Implement ReadConsoleInputW, PeekConsoleInputW, ReadConsoleOutputW, WriteConsoleOut...
[reactos.git] / reactos / subsys / csrss / win32csr / conio.c
1 /* $Id: conio.c,v 1.12 2004/08/22 20:52:28 navaraf Exp $
2 *
3 * reactos/subsys/csrss/win32csr/conio.c
4 *
5 * Console I/O functions
6 *
7 * ReactOS Operating System
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <string.h>
13 #include <windows.h>
14
15 #include <csrss/csrss.h>
16 #include <ntdll/rtl.h>
17 #include <ntdll/ldr.h>
18 #include <ddk/ntddblue.h>
19 #include <rosrtl/string.h>
20 #include <rosrtl/minmax.h>
21 #include "api.h"
22 #include "conio.h"
23 #include "desktopbg.h"
24 #include "guiconsole.h"
25 #include "tuiconsole.h"
26 #include "win32csr.h"
27
28 #define NDEBUG
29 #include <debug.h>
30
31 /* FIXME: Is there a way to create real aliasses with gcc? [CSH] */
32 #define ALIAS(Name, Target) typeof(Target) Name = Target
33
34 /* Private user32 routines for CSRSS, not defined in any header file */
35 extern VOID STDCALL PrivateCsrssRegisterPrimitive(VOID);
36 extern VOID STDCALL PrivateCsrssAcquireOrReleaseInputOwnership(BOOL Release);
37
38 /* GLOBALS *******************************************************************/
39
40 #define ConioInitRect(Rect, Top, Left, Bottom, Right) \
41 ((Rect)->top) = Top; \
42 ((Rect)->left) = Left; \
43 ((Rect)->bottom) = Bottom; \
44 ((Rect)->right) = Right
45
46 #define ConioIsRectEmpty(Rect) \
47 (((Rect)->left > (Rect)->right) || ((Rect)->top > (Rect)->bottom))
48
49 /* FUNCTIONS *****************************************************************/
50
51 STATIC NTSTATUS FASTCALL
52 ConioConsoleFromProcessData(PCSRSS_PROCESS_DATA ProcessData, PCSRSS_CONSOLE *Console)
53 {
54 if (NULL == ProcessData->Console)
55 {
56 *Console = NULL;
57 return STATUS_SUCCESS;
58 }
59
60 EnterCriticalSection(&(ProcessData->Console->Header.Lock));
61 *Console = ProcessData->Console;
62
63 return STATUS_SUCCESS;
64 }
65
66 STATIC VOID FASTCALL
67 CsrConsoleCtrlEvent(DWORD Event, PCSRSS_PROCESS_DATA ProcessData)
68 {
69 HANDLE Process, Thread;
70
71 DPRINT("CsrConsoleCtrlEvent Parent ProcessId = %x\n", ProcessData->ProcessId);
72
73 if (ProcessData->CtrlDispatcher)
74 {
75 Process = OpenProcess(PROCESS_DUP_HANDLE, FALSE, ProcessData->ProcessId);
76 if (NULL == Process)
77 {
78 DPRINT1("Failed for handle duplication\n");
79 return;
80 }
81
82 DPRINT("CsrConsoleCtrlEvent Process Handle = %x\n", Process);
83
84 Thread = CreateRemoteThread(Process, NULL, 0,
85 (LPTHREAD_START_ROUTINE) ProcessData->CtrlDispatcher,
86 (PVOID) Event, 0, NULL);
87 if (NULL == Thread)
88 {
89 DPRINT1("Failed thread creation\n");
90 CloseHandle(Process);
91 return;
92 }
93 CloseHandle(Thread);
94 CloseHandle(Process);
95 }
96 }
97
98 #define GET_CELL_BUFFER(b,o)\
99 (b)->Buffer[(o)++]
100
101 #define SET_CELL_BUFFER(b,o,c,a)\
102 (b)->Buffer[(o)++]=(c),\
103 (b)->Buffer[(o)++]=(a)
104
105 static VOID FASTCALL
106 ClearLineBuffer(PCSRSS_SCREEN_BUFFER Buff)
107 {
108 DWORD Offset = 2 * (Buff->CurrentY * Buff->MaxX);
109 UINT Pos;
110
111 for (Pos = 0; Pos < Buff->MaxX; Pos++)
112 {
113 /* Fill the cell: Offset is incremented by the macro */
114 SET_CELL_BUFFER(Buff, Offset, ' ', Buff->DefaultAttrib);
115 }
116 }
117
118 STATIC NTSTATUS FASTCALL
119 CsrInitConsoleScreenBuffer(PCSRSS_CONSOLE Console,
120 PCSRSS_SCREEN_BUFFER Buffer)
121 {
122 Buffer->Header.Type = CONIO_SCREEN_BUFFER_MAGIC;
123 Buffer->Header.ReferenceCount = 0;
124 Buffer->MaxX = Console->Size.X;
125 Buffer->MaxY = Console->Size.Y;
126 Buffer->ShowX = 0;
127 Buffer->ShowY = 0;
128 Buffer->Buffer = HeapAlloc(Win32CsrApiHeap, 0, Buffer->MaxX * Buffer->MaxY * 2);
129 if (NULL == Buffer->Buffer)
130 {
131 return STATUS_INSUFFICIENT_RESOURCES;
132 }
133 RtlInitializeCriticalSection(&Buffer->Header.Lock);
134 ConioInitScreenBuffer(Console, Buffer);
135 /* initialize buffer to be empty with default attributes */
136 for (Buffer->CurrentY = 0 ; Buffer->CurrentY < Buffer->MaxY; Buffer->CurrentY++)
137 {
138 ClearLineBuffer(Buffer);
139 }
140 Buffer->CursorInfo.bVisible = TRUE;
141 Buffer->CursorInfo.dwSize = 5;
142 Buffer->Mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
143 Buffer->CurrentX = 0;
144 Buffer->CurrentY = 0;
145
146 return STATUS_SUCCESS;
147 }
148
149 STATIC NTSTATUS STDCALL
150 CsrInitConsole(PCSRSS_CONSOLE Console)
151 {
152 NTSTATUS Status;
153 SECURITY_ATTRIBUTES SecurityAttributes;
154 PCSRSS_SCREEN_BUFFER NewBuffer;
155 BOOL GuiMode;
156
157 Console->Title.MaximumLength = Console->Title.Length = 0;
158 Console->Title.Buffer = NULL;
159
160 RtlCreateUnicodeString(&Console->Title, L"Command Prompt");
161
162 Console->Header.ReferenceCount = 0;
163 Console->WaitingChars = 0;
164 Console->WaitingLines = 0;
165 Console->EchoCount = 0;
166 Console->Header.Type = CONIO_CONSOLE_MAGIC;
167 Console->Mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT;
168 Console->EarlyReturn = FALSE;
169 Console->ActiveBuffer = NULL;
170 InitializeListHead(&Console->InputEvents);
171 InitializeListHead(&Console->ProcessList);
172
173 Console->CodePage = CP_OEMCP;
174 Console->OutputCodePage = CP_OEMCP;
175
176 SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
177 SecurityAttributes.lpSecurityDescriptor = NULL;
178 SecurityAttributes.bInheritHandle = TRUE;
179
180 Console->ActiveEvent = CreateEventW(&SecurityAttributes, FALSE, FALSE, NULL);
181 if (NULL == Console->ActiveEvent)
182 {
183 RtlFreeUnicodeString(&Console->Title);
184 return STATUS_UNSUCCESSFUL;
185 }
186 Console->PrivateData = NULL;
187 RtlInitializeCriticalSection(&Console->Header.Lock);
188 GuiMode = DtbgIsDesktopVisible();
189 if (! GuiMode)
190 {
191 Status = TuiInitConsole(Console);
192 if (! NT_SUCCESS(Status))
193 {
194 DPRINT1("Failed to open text-mode console, switching to gui-mode\n");
195 GuiMode = TRUE;
196 }
197 }
198 if (GuiMode)
199 {
200 Status = GuiInitConsole(Console);
201 if (! NT_SUCCESS(Status))
202 {
203 RtlFreeUnicodeString(&Console->Title);
204 RtlDeleteCriticalSection(&Console->Header.Lock);
205 CloseHandle(Console->ActiveEvent);
206 return Status;
207 }
208 }
209
210 NewBuffer = HeapAlloc(Win32CsrApiHeap, 0, sizeof(CSRSS_SCREEN_BUFFER));
211 if (NULL == NewBuffer)
212 {
213 RtlFreeUnicodeString(&Console->Title);
214 RtlDeleteCriticalSection(&Console->Header.Lock);
215 CloseHandle(Console->ActiveEvent);
216 return STATUS_INSUFFICIENT_RESOURCES;
217 }
218 Status = CsrInitConsoleScreenBuffer(Console, NewBuffer);
219 if (! NT_SUCCESS(Status))
220 {
221 RtlFreeUnicodeString(&Console->Title);
222 RtlDeleteCriticalSection(&Console->Header.Lock);
223 CloseHandle(Console->ActiveEvent);
224 HeapFree(Win32CsrApiHeap, 0, NewBuffer);
225 return Status;
226 }
227 Console->ActiveBuffer = NewBuffer;
228 /* add a reference count because the buffer is tied to the console */
229 Console->ActiveBuffer->Header.ReferenceCount++;
230 /* make console active, and insert into console list */
231 /* copy buffer contents to screen */
232 ConioDrawConsole(Console);
233
234 return STATUS_SUCCESS;
235 }
236
237
238 CSR_API(CsrAllocConsole)
239 {
240 PCSRSS_CONSOLE Console;
241 HANDLE Process;
242 NTSTATUS Status;
243
244 DPRINT("CsrAllocConsole\n");
245
246 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
247 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
248
249 if (ProcessData == NULL)
250 {
251 return Reply->Status = STATUS_INVALID_PARAMETER;
252 }
253
254 if (ProcessData->Console)
255 {
256 Reply->Status = STATUS_INVALID_PARAMETER;
257 return STATUS_INVALID_PARAMETER;
258 }
259
260 Reply->Status = STATUS_SUCCESS;
261 Console = HeapAlloc(Win32CsrApiHeap, 0, sizeof(CSRSS_CONSOLE));
262 if (NULL == Console)
263 {
264 Reply->Status = STATUS_NO_MEMORY;
265 return STATUS_NO_MEMORY;
266 }
267 Reply->Status = CsrInitConsole(Console);
268 if (! NT_SUCCESS(Reply->Status))
269 {
270 HeapFree(Win32CsrApiHeap, 0, Console);
271 return Reply->Status;
272 }
273 ProcessData->Console = Console;
274 Reply->Data.AllocConsoleReply.Console = Console;
275
276 /* add a reference count because the process is tied to the console */
277 Console->Header.ReferenceCount++;
278 Status = Win32CsrInsertObject(ProcessData, &Reply->Data.AllocConsoleReply.InputHandle, &Console->Header);
279 if (! NT_SUCCESS(Status))
280 {
281 ConioDeleteConsole((Object_t *) Console);
282 ProcessData->Console = 0;
283 return Reply->Status = Status;
284 }
285 Status = Win32CsrInsertObject(ProcessData, &Reply->Data.AllocConsoleReply.OutputHandle, &Console->ActiveBuffer->Header);
286 if (!NT_SUCCESS(Status))
287 {
288 Console->Header.ReferenceCount--;
289 Win32CsrReleaseObject(ProcessData, Reply->Data.AllocConsoleReply.InputHandle);
290 ProcessData->Console = 0;
291 return Reply->Status = Status;
292 }
293
294 Process = OpenProcess(PROCESS_DUP_HANDLE, FALSE, ProcessData->ProcessId);
295 if (NULL == Process)
296 {
297 DPRINT1("OpenProcess() failed for handle duplication\n");
298 Console->Header.ReferenceCount--;
299 ProcessData->Console = 0;
300 Win32CsrReleaseObject(ProcessData, Reply->Data.AllocConsoleReply.OutputHandle);
301 Win32CsrReleaseObject(ProcessData, Reply->Data.AllocConsoleReply.InputHandle);
302 Reply->Status = Status;
303 return Status;
304 }
305 if (! DuplicateHandle(GetCurrentProcess(), ProcessData->Console->ActiveEvent,
306 Process, &ProcessData->ConsoleEvent, EVENT_ALL_ACCESS, FALSE, 0))
307 {
308 DPRINT1("DuplicateHandle() failed: %d\n", GetLastError);
309 CloseHandle(Process);
310 Console->Header.ReferenceCount--;
311 Win32CsrReleaseObject(ProcessData, Reply->Data.AllocConsoleReply.OutputHandle);
312 Win32CsrReleaseObject(ProcessData, Reply->Data.AllocConsoleReply.InputHandle);
313 ProcessData->Console = 0;
314 Reply->Status = Status;
315 return Status;
316 }
317 CloseHandle(Process);
318 ProcessData->CtrlDispatcher = Request->Data.AllocConsoleRequest.CtrlDispatcher;
319 DPRINT("CSRSS:CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher);
320 InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ProcessEntry);
321
322 return STATUS_SUCCESS;
323 }
324
325 CSR_API(CsrFreeConsole)
326 {
327 PCSRSS_CONSOLE Console;
328
329 DPRINT("CsrFreeConsole\n");
330
331 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
332 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
333
334 if (ProcessData == NULL || ProcessData->Console == NULL)
335 {
336 return Reply->Status = STATUS_INVALID_PARAMETER;
337 }
338
339 Console = ProcessData->Console;
340 Console->Header.ReferenceCount--;
341 ProcessData->Console = NULL;
342 if (0 == Console->Header.ReferenceCount)
343 {
344 ConioDeleteConsole((Object_t *) Console);
345 }
346
347 return STATUS_SUCCESS;
348 }
349
350 STATIC VOID FASTCALL
351 ConioNextLine(PCSRSS_SCREEN_BUFFER Buff, RECT *UpdateRect, UINT *ScrolledLines)
352 {
353 /* slide the viewable screen */
354 if (((Buff->CurrentY - Buff->ShowY + Buff->MaxY) % Buff->MaxY) == Buff->MaxY - 1)
355 {
356 if (++Buff->ShowY == Buff->MaxY)
357 {
358 Buff->ShowY = 0;
359 }
360 (*ScrolledLines)++;
361 }
362 if (++Buff->CurrentY == Buff->MaxY)
363 {
364 Buff->CurrentY = 0;
365 }
366 ClearLineBuffer(Buff);
367 UpdateRect->left = 0;
368 UpdateRect->right = Buff->MaxX - 1;
369 if (UpdateRect->top == Buff->CurrentY)
370 {
371 if (++UpdateRect->top == Buff->MaxY)
372 {
373 UpdateRect->top = 0;
374 }
375 }
376 UpdateRect->bottom = Buff->CurrentY;
377 }
378
379 STATIC NTSTATUS FASTCALL
380 ConioWriteConsole(PCSRSS_CONSOLE Console, PCSRSS_SCREEN_BUFFER Buff,
381 CHAR *Buffer, DWORD Length, BOOL Attrib)
382 {
383 int i;
384 DWORD Offset;
385 RECT UpdateRect;
386 LONG CursorStartX, CursorStartY;
387 UINT ScrolledLines;
388
389 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY, &CursorStartX, &CursorStartY);
390 UpdateRect.left = Buff->MaxX;
391 UpdateRect.top = Buff->CurrentY;
392 UpdateRect.right = -1;
393 UpdateRect.bottom = Buff->CurrentY;
394 ScrolledLines = 0;
395
396 for (i = 0; i < Length; i++)
397 {
398 switch(Buffer[i])
399 {
400 /* --- LF --- */
401 case '\n':
402 Buff->CurrentX = 0;
403 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
404 break;
405
406 /* --- BS --- */
407 case '\b':
408 /* Only handle BS if we're not on the first pos of the first line */
409 if (0 != Buff->CurrentX || Buff->ShowY != Buff->CurrentY)
410 {
411 if (0 == Buff->CurrentX)
412 {
413 /* slide virtual position up */
414 Buff->CurrentX = Buff->MaxX - 1;
415 if (0 == Buff->CurrentY)
416 {
417 Buff->CurrentY = Buff->MaxY;
418 }
419 else
420 {
421 Buff->CurrentY--;
422 }
423 if ((0 == UpdateRect.top && UpdateRect.bottom < Buff->CurrentY)
424 || (0 != UpdateRect.top && Buff->CurrentY < UpdateRect.top))
425 {
426 UpdateRect.top = Buff->CurrentY;
427 }
428 }
429 else
430 {
431 Buff->CurrentX--;
432 }
433 Offset = 2 * ((Buff->CurrentY * Buff->MaxX) + Buff->CurrentX);
434 SET_CELL_BUFFER(Buff, Offset, ' ', Buff->DefaultAttrib);
435 UpdateRect.left = RtlRosMin(UpdateRect.left, Buff->CurrentX);
436 UpdateRect.right = RtlRosMax(UpdateRect.right, (LONG) Buff->CurrentX);
437 }
438 break;
439
440 /* --- CR --- */
441 case '\r':
442 Buff->CurrentX = 0;
443 UpdateRect.left = RtlRosMin(UpdateRect.left, Buff->CurrentX);
444 UpdateRect.right = RtlRosMax(UpdateRect.right, (LONG) Buff->CurrentX);
445 break;
446
447 /* --- TAB --- */
448 case '\t':
449 {
450 UINT EndX;
451
452 UpdateRect.left = RtlRosMin(UpdateRect.left, Buff->CurrentX);
453 EndX = 8 * ((Buff->CurrentX + 8) / 8);
454 if (Buff->MaxX < EndX)
455 {
456 EndX = Buff->MaxX;
457 }
458 Offset = 2 * (((Buff->CurrentY * Buff->MaxX)) + Buff->CurrentX);
459 while (Buff->CurrentX < EndX)
460 {
461 Buff->Buffer[Offset] = ' ';
462 Offset += 2;
463 Buff->CurrentX++;
464 }
465 UpdateRect.right = RtlRosMax(UpdateRect.right, (LONG) Buff->CurrentX - 1);
466 if (Buff->CurrentX == Buff->MaxX)
467 {
468 Buff->CurrentX = 0;
469 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
470 }
471 }
472 break;
473
474 /* --- */
475 default:
476 UpdateRect.left = RtlRosMin(UpdateRect.left, Buff->CurrentX);
477 UpdateRect.right = RtlRosMax(UpdateRect.right, (LONG) Buff->CurrentX);
478 Offset = 2 * (((Buff->CurrentY * Buff->MaxX)) + Buff->CurrentX);
479 Buff->Buffer[Offset++] = Buffer[i];
480 if (Attrib)
481 {
482 Buff->Buffer[Offset] = Buff->DefaultAttrib;
483 }
484 Buff->CurrentX++;
485 if (Buff->CurrentX == Buff->MaxX)
486 {
487 Buff->CurrentX = 0;
488 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
489 }
490 break;
491 }
492 }
493
494 ConioPhysicalToLogical(Buff, UpdateRect.left, UpdateRect.top, &(UpdateRect.left),
495 &(UpdateRect.top));
496 ConioPhysicalToLogical(Buff, UpdateRect.right, UpdateRect.bottom, &(UpdateRect.right),
497 &(UpdateRect.bottom));
498 if (! ConioIsRectEmpty(&UpdateRect) && NULL != Console && Buff == Console->ActiveBuffer)
499 {
500 ConioWriteStream(Console, &UpdateRect, CursorStartX, CursorStartY, ScrolledLines,
501 Buffer, Length);
502 }
503
504 return STATUS_SUCCESS;
505 }
506
507 CSR_API(CsrReadConsole)
508 {
509 PLIST_ENTRY CurrentEntry;
510 ConsoleInput *Input;
511 PCHAR Buffer;
512 int i;
513 ULONG nNumberOfCharsToRead;
514 PCSRSS_CONSOLE Console;
515 NTSTATUS Status;
516
517 DPRINT("CsrReadConsole\n");
518
519 /* truncate length to CSRSS_MAX_READ_CONSOLE_REQUEST */
520 nNumberOfCharsToRead = Request->Data.ReadConsoleRequest.NrCharactersToRead > CSRSS_MAX_READ_CONSOLE_REQUEST ? CSRSS_MAX_READ_CONSOLE_REQUEST : Request->Data.ReadConsoleRequest.NrCharactersToRead;
521 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
522 Reply->Header.DataSize = Reply->Header.MessageSize - LPC_MESSAGE_BASE_SIZE;
523
524 Buffer = Reply->Data.ReadConsoleReply.Buffer;
525 Status = ConioLockConsole(ProcessData, Request->Data.ReadConsoleRequest.ConsoleHandle,
526 &Console);
527 if (! NT_SUCCESS(Status))
528 {
529 return Reply->Status = Status;
530 }
531 Reply->Data.ReadConsoleReply.EventHandle = ProcessData->ConsoleEvent;
532 for (i = 0; i < nNumberOfCharsToRead && Console->InputEvents.Flink != &Console->InputEvents; i++)
533 {
534 /* remove input event from queue */
535 CurrentEntry = RemoveHeadList(&Console->InputEvents);
536 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
537
538 /* only pay attention to valid ascii chars, on key down */
539 if (KEY_EVENT == Input->InputEvent.EventType
540 && Input->InputEvent.Event.KeyEvent.bKeyDown
541 && Input->InputEvent.Event.KeyEvent.uChar.AsciiChar)
542 {
543 /* backspace handling */
544 if ('\b' == Input->InputEvent.Event.KeyEvent.uChar.AsciiChar)
545 {
546 /* echo if it has not already been done, and either we or the client has chars to be deleted */
547 if (! Input->Echoed
548 && (0 != i || Request->Data.ReadConsoleRequest.nCharsCanBeDeleted))
549 {
550 ConioWriteConsole(Console, Console->ActiveBuffer,
551 &Input->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE);
552 }
553 if (0 != i)
554 {
555 i -= 2; /* if we already have something to return, just back it up by 2 */
556 }
557 else
558 { /* otherwise, return STATUS_NOTIFY_CLEANUP to tell client to back up its buffer */
559 Reply->Data.ReadConsoleReply.NrCharactersRead = 0;
560 Reply->Status = STATUS_NOTIFY_CLEANUP;
561 Console->WaitingChars--;
562 HeapFree(Win32CsrApiHeap, 0, Input);
563 ConioUnlockConsole(Console);
564 return STATUS_NOTIFY_CLEANUP;
565 }
566 Request->Data.ReadConsoleRequest.nCharsCanBeDeleted--;
567 Input->Echoed = TRUE; /* mark as echoed so we don't echo it below */
568 }
569 /* do not copy backspace to buffer */
570 else
571 {
572 Buffer[i] = Input->InputEvent.Event.KeyEvent.uChar.AsciiChar;
573 }
574 /* echo to screen if enabled and we did not already echo the char */
575 if (0 != (Console->Mode & ENABLE_ECHO_INPUT)
576 && ! Input->Echoed
577 && '\r' != Input->InputEvent.Event.KeyEvent.uChar.AsciiChar)
578 {
579 ConioWriteConsole(Console, Console->ActiveBuffer,
580 &Input->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE);
581 }
582 }
583 else
584 {
585 i--;
586 }
587 Console->WaitingChars--;
588 HeapFree(Win32CsrApiHeap, 0, Input);
589 }
590 Reply->Data.ReadConsoleReply.NrCharactersRead = i;
591 if (0 == i)
592 {
593 Reply->Status = STATUS_PENDING; /* we didn't read anything */
594 }
595 else if (0 != (Console->Mode & ENABLE_LINE_INPUT))
596 {
597 if (0 == Console->WaitingLines || '\n' != Buffer[i - 1])
598 {
599 Reply->Status = STATUS_PENDING; /* line buffered, didn't get a complete line */
600 }
601 else
602 {
603 Console->WaitingLines--;
604 Reply->Status = STATUS_SUCCESS; /* line buffered, did get a complete line */
605 }
606 }
607 else
608 {
609 Reply->Status = STATUS_SUCCESS; /* not line buffered, did read something */
610 }
611
612 if (Reply->Status == STATUS_PENDING)
613 {
614 Console->EchoCount = nNumberOfCharsToRead - i;
615 }
616 else
617 {
618 Console->EchoCount = 0; /* if the client is no longer waiting on input, do not echo */
619 }
620 Reply->Header.MessageSize += i;
621
622 ConioUnlockConsole(Console);
623 return Reply->Status;
624 }
625
626 VOID FASTCALL
627 ConioPhysicalToLogical(PCSRSS_SCREEN_BUFFER Buff,
628 ULONG PhysicalX,
629 ULONG PhysicalY,
630 LONG *LogicalX,
631 LONG *LogicalY)
632 {
633 *LogicalX = PhysicalX;
634 if (PhysicalY < Buff->ShowY)
635 {
636 *LogicalY = Buff->MaxY - Buff->ShowY + PhysicalY;
637 }
638 else
639 {
640 *LogicalY = PhysicalY - Buff->ShowY;
641 }
642 }
643
644 inline BOOLEAN ConioIsEqualRect(
645 RECT *Rect1,
646 RECT *Rect2)
647 {
648 return ((Rect1->left == Rect2->left) && (Rect1->right == Rect2->right) &&
649 (Rect1->top == Rect2->top) && (Rect1->bottom == Rect2->bottom));
650 }
651
652 inline BOOLEAN ConioGetIntersection(
653 RECT *Intersection,
654 RECT *Rect1,
655 RECT *Rect2)
656 {
657 if (ConioIsRectEmpty(Rect1) ||
658 (ConioIsRectEmpty(Rect2)) ||
659 (Rect1->top > Rect2->bottom) ||
660 (Rect1->left > Rect2->right) ||
661 (Rect1->bottom < Rect2->top) ||
662 (Rect1->right < Rect2->left))
663 {
664 /* The rectangles do not intersect */
665 ConioInitRect(Intersection, 0, -1, 0, -1);
666 return FALSE;
667 }
668
669 ConioInitRect(Intersection,
670 RtlRosMax(Rect1->top, Rect2->top),
671 RtlRosMax(Rect1->left, Rect2->left),
672 RtlRosMin(Rect1->bottom, Rect2->bottom),
673 RtlRosMin(Rect1->right, Rect2->right));
674
675 return TRUE;
676 }
677
678 inline BOOLEAN ConioGetUnion(
679 RECT *Union,
680 RECT *Rect1,
681 RECT *Rect2)
682 {
683 if (ConioIsRectEmpty(Rect1))
684 {
685 if (ConioIsRectEmpty(Rect2))
686 {
687 ConioInitRect(Union, 0, -1, 0, -1);
688 return FALSE;
689 }
690 else
691 {
692 *Union = *Rect2;
693 }
694 }
695 else if (ConioIsRectEmpty(Rect2))
696 {
697 *Union = *Rect1;
698 }
699 else
700 {
701 ConioInitRect(Union,
702 RtlRosMin(Rect1->top, Rect2->top),
703 RtlRosMin(Rect1->left, Rect2->left),
704 RtlRosMax(Rect1->bottom, Rect2->bottom),
705 RtlRosMax(Rect1->right, Rect2->right));
706 }
707
708 return TRUE;
709 }
710
711 inline BOOLEAN ConioSubtractRect(
712 RECT *Subtraction,
713 RECT *Rect1,
714 RECT *Rect2)
715 {
716 RECT tmp;
717
718 if (ConioIsRectEmpty(Rect1))
719 {
720 ConioInitRect(Subtraction, 0, -1, 0, -1);
721 return FALSE;
722 }
723 *Subtraction = *Rect1;
724 if (ConioGetIntersection(&tmp, Rect1, Rect2))
725 {
726 if (ConioIsEqualRect(&tmp, Subtraction))
727 {
728 ConioInitRect(Subtraction, 0, -1, 0, -1);
729 return FALSE;
730 }
731 if ((tmp.top == Subtraction->top) && (tmp.bottom == Subtraction->bottom))
732 {
733 if (tmp.left == Subtraction->left)
734 {
735 Subtraction->left = tmp.right;
736 }
737 else if (tmp.right == Subtraction->right)
738 {
739 Subtraction->right = tmp.left;
740 }
741 }
742 else if ((tmp.left == Subtraction->left) && (tmp.right == Subtraction->right))
743 {
744 if (tmp.top == Subtraction->top)
745 {
746 Subtraction->top = tmp.bottom;
747 }
748 else if (tmp.bottom == Subtraction->bottom)
749 {
750 Subtraction->bottom = tmp.top;
751 }
752 }
753 }
754
755 return TRUE;
756 }
757
758 STATIC VOID FASTCALL
759 ConioCopyRegion(PCSRSS_SCREEN_BUFFER ScreenBuffer,
760 RECT *SrcRegion,
761 RECT *DstRegion)
762 {
763 SHORT SrcY, DstY;
764 DWORD SrcOffset;
765 DWORD DstOffset;
766 DWORD BytesPerLine;
767 ULONG i;
768
769 DstY = DstRegion->top;
770 BytesPerLine = ConioRectWidth(DstRegion) * 2;
771
772 SrcY = (SrcRegion->top + ScreenBuffer->ShowY) % ScreenBuffer->MaxY;
773 DstY = (DstRegion->top + ScreenBuffer->ShowY) % ScreenBuffer->MaxY;
774 SrcOffset = (SrcY * ScreenBuffer->MaxX + SrcRegion->left + ScreenBuffer->ShowX) * 2;
775 DstOffset = (DstY * ScreenBuffer->MaxX + DstRegion->left + ScreenBuffer->ShowX) * 2;
776
777 for (i = SrcRegion->top; i <= SrcRegion->bottom; i++)
778 {
779 RtlCopyMemory(
780 &ScreenBuffer->Buffer[DstOffset],
781 &ScreenBuffer->Buffer[SrcOffset],
782 BytesPerLine);
783
784 if (++DstY == ScreenBuffer->MaxY)
785 {
786 DstY = 0;
787 DstOffset = (DstRegion->left + ScreenBuffer->ShowX) * 2;
788 }
789 else
790 {
791 DstOffset += ScreenBuffer->MaxX * 2;
792 }
793
794 if (++SrcY == ScreenBuffer->MaxY)
795 {
796 SrcY = 0;
797 SrcOffset = (SrcRegion->left + ScreenBuffer->ShowX) * 2;
798 }
799 else
800 {
801 SrcOffset += ScreenBuffer->MaxX * 2;
802 }
803 }
804 }
805
806 STATIC VOID FASTCALL
807 ConioFillRegion(PCSRSS_SCREEN_BUFFER ScreenBuffer,
808 RECT *Region,
809 CHAR_INFO CharInfo)
810 {
811 SHORT X, Y;
812 DWORD Offset;
813 DWORD Delta;
814 ULONG i;
815
816 Y = (Region->top + ScreenBuffer->ShowY) % ScreenBuffer->MaxY;
817 Offset = (Y * ScreenBuffer->MaxX + Region->left + ScreenBuffer->ShowX) * 2;
818 Delta = (ScreenBuffer->MaxX - ConioRectWidth(Region)) * 2;
819
820 for (i = Region->top; i <= Region->bottom; i++)
821 {
822 for (X = Region->left; X <= Region->right; X++)
823 {
824 SET_CELL_BUFFER(ScreenBuffer, Offset, CharInfo.Char.AsciiChar, CharInfo.Attributes);
825 }
826 if (++Y == ScreenBuffer->MaxY)
827 {
828 Y = 0;
829 Offset = (Region->left + ScreenBuffer->ShowX) * 2;
830 }
831 else
832 {
833 Offset += Delta;
834 }
835 }
836 }
837
838 STATIC VOID FASTCALL
839 ConioInputEventToAnsi(PCSRSS_CONSOLE Console, PINPUT_RECORD InputEvent)
840 {
841 if (InputEvent->EventType == KEY_EVENT)
842 {
843 WideCharToMultiByte(Console->CodePage, 0,
844 &InputEvent->Event.KeyEvent.uChar.UnicodeChar, 1,
845 &InputEvent->Event.KeyEvent.uChar.AsciiChar, 1,
846 NULL, NULL);
847 }
848 }
849
850 CSR_API(CsrWriteConsole)
851 {
852 NTSTATUS Status;
853 BYTE *Buffer = Request->Data.WriteConsoleRequest.Buffer;
854 PCSRSS_SCREEN_BUFFER Buff;
855 PCSRSS_CONSOLE Console;
856
857 DPRINT("CsrWriteConsole\n");
858
859 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
860 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
861
862 if (Request->Header.DataSize
863 < sizeof(CSRSS_WRITE_CONSOLE_REQUEST) - 1
864 + Request->Data.WriteConsoleRequest.NrCharactersToWrite)
865 {
866 DPRINT1("Invalid request size\n");
867 return Reply->Status = STATUS_INVALID_PARAMETER;
868 }
869 Status = ConioConsoleFromProcessData(ProcessData, &Console);
870 if (! NT_SUCCESS(Status))
871 {
872 return Reply->Status = Status;
873 }
874
875 Status = ConioLockScreenBuffer(ProcessData, Request->Data.WriteConsoleRequest.ConsoleHandle, &Buff);
876 if (! NT_SUCCESS(Status))
877 {
878 if (NULL != Console)
879 {
880 ConioUnlockConsole(Console);
881 }
882 return Reply->Status = Status;
883 }
884
885 ConioWriteConsole(Console, Buff, Buffer,
886 Request->Data.WriteConsoleRequest.NrCharactersToWrite, TRUE);
887 ConioUnlockScreenBuffer(Buff);
888 if (NULL != Console)
889 {
890 ConioUnlockConsole(Console);
891 }
892
893 return Reply->Status = STATUS_SUCCESS;
894 }
895
896 VOID STDCALL
897 ConioDeleteScreenBuffer(Object_t *Object)
898 {
899 PCSRSS_SCREEN_BUFFER Buffer = (PCSRSS_SCREEN_BUFFER) Object;
900 RtlDeleteCriticalSection(&Buffer->Header.Lock);
901 HeapFree(Win32CsrApiHeap, 0, Buffer->Buffer);
902 HeapFree(Win32CsrApiHeap, 0, Buffer);
903 }
904
905 VOID FASTCALL
906 ConioDrawConsole(PCSRSS_CONSOLE Console)
907 {
908 RECT Region;
909
910 ConioInitRect(&Region, 0, 0, Console->Size.Y - 1, Console->Size.X - 1);
911
912 ConioDrawRegion(Console, &Region);
913 }
914
915
916 VOID STDCALL
917 ConioDeleteConsole(Object_t *Object)
918 {
919 PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) Object;
920 ConsoleInput *Event;
921
922 DPRINT("ConioDeleteConsole\n");
923
924 /* Drain input event queue */
925 while (Console->InputEvents.Flink != &Console->InputEvents)
926 {
927 Event = (ConsoleInput *) Console->InputEvents.Flink;
928 Console->InputEvents.Flink = Console->InputEvents.Flink->Flink;
929 Console->InputEvents.Flink->Flink->Blink = &Console->InputEvents;
930 HeapFree(Win32CsrApiHeap, 0, Event);
931 }
932
933 if (0 == --Console->ActiveBuffer->Header.ReferenceCount)
934 {
935 ConioDeleteScreenBuffer((Object_t *) Console->ActiveBuffer);
936 }
937
938 Console->ActiveBuffer = NULL;
939 ConioCleanupConsole(Console);
940
941 CloseHandle(Console->ActiveEvent);
942 RtlDeleteCriticalSection(&Console->Header.Lock);
943 RtlFreeUnicodeString(&Console->Title);
944 HeapFree(Win32CsrApiHeap, 0, Console);
945 }
946
947 VOID STDCALL
948 CsrInitConsoleSupport(VOID)
949 {
950 DPRINT("CSR: CsrInitConsoleSupport()\n");
951
952 /* Should call LoadKeyboardLayout */
953 }
954
955 STATIC VOID FASTCALL
956 ConioProcessChar(PCSRSS_CONSOLE Console,
957 ConsoleInput *KeyEventRecord)
958 {
959 BOOL updown;
960 BOOL bClientWake = FALSE;
961 ConsoleInput *TempInput;
962
963 /* process Ctrl-C and Ctrl-Break */
964 if (Console->Mode & ENABLE_PROCESSED_INPUT &&
965 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown &&
966 ((KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == VK_PAUSE) ||
967 (KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode == 'C')) &&
968 (KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)))
969 {
970 PCSRSS_PROCESS_DATA current;
971 PLIST_ENTRY current_entry;
972 DPRINT1("Console_Api Ctrl-C\n");
973 current_entry = Console->ProcessList.Flink;
974 while (current_entry != &Console->ProcessList)
975 {
976 current = CONTAINING_RECORD(current_entry, CSRSS_PROCESS_DATA, ProcessEntry);
977 current_entry = current_entry->Flink;
978 CsrConsoleCtrlEvent((DWORD)CTRL_C_EVENT, current);
979 }
980 HeapFree(Win32CsrApiHeap, 0, KeyEventRecord);
981 return;
982 }
983
984 if (0 != (KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState
985 & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
986 && (VK_UP == KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode
987 || VK_DOWN == KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode))
988 {
989 if (KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown)
990 {
991 /* scroll up or down */
992 if (NULL == Console)
993 {
994 DPRINT1("No Active Console!\n");
995 HeapFree(Win32CsrApiHeap, 0, KeyEventRecord);
996 return;
997 }
998 if (VK_UP == KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode)
999 {
1000 /* only scroll up if there is room to scroll up into */
1001 if (Console->ActiveBuffer->ShowY != ((Console->ActiveBuffer->CurrentY + 1) %
1002 Console->ActiveBuffer->MaxY))
1003 {
1004 Console->ActiveBuffer->ShowY = (Console->ActiveBuffer->ShowY +
1005 Console->ActiveBuffer->MaxY - 1) %
1006 Console->ActiveBuffer->MaxY;
1007 }
1008 }
1009 else if (Console->ActiveBuffer->ShowY != Console->ActiveBuffer->CurrentY)
1010 /* only scroll down if there is room to scroll down into */
1011 {
1012 if (Console->ActiveBuffer->ShowY % Console->ActiveBuffer->MaxY !=
1013 Console->ActiveBuffer->CurrentY)
1014 {
1015 if (((Console->ActiveBuffer->CurrentY + 1) % Console->ActiveBuffer->MaxY) !=
1016 (Console->ActiveBuffer->ShowY + Console->ActiveBuffer->MaxY) %
1017 Console->ActiveBuffer->MaxY)
1018 {
1019 Console->ActiveBuffer->ShowY = (Console->ActiveBuffer->ShowY + 1) %
1020 Console->ActiveBuffer->MaxY;
1021 }
1022 }
1023 }
1024 ConioDrawConsole(Console);
1025 }
1026 HeapFree(Win32CsrApiHeap, 0, KeyEventRecord);
1027 return;
1028 }
1029 if (NULL == Console)
1030 {
1031 DPRINT1("No Active Console!\n");
1032 HeapFree(Win32CsrApiHeap, 0, KeyEventRecord);
1033 return;
1034 }
1035
1036 if (0 != (Console->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT)))
1037 {
1038 switch(KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar)
1039 {
1040 case '\r':
1041 /* first add the \r */
1042 KeyEventRecord->InputEvent.EventType = KEY_EVENT;
1043 updown = KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown;
1044 KeyEventRecord->Echoed = FALSE;
1045 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
1046 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\r';
1047 InsertTailList(&Console->InputEvents, &KeyEventRecord->ListEntry);
1048 Console->WaitingChars++;
1049 KeyEventRecord = HeapAlloc(Win32CsrApiHeap, 0, sizeof(ConsoleInput));
1050 if (NULL == KeyEventRecord)
1051 {
1052 DPRINT1("Failed to allocate KeyEventRecord\n");
1053 return;
1054 }
1055 KeyEventRecord->InputEvent.EventType = KEY_EVENT;
1056 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown = updown;
1057 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode = 0;
1058 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualScanCode = 0;
1059 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\n';
1060 KeyEventRecord->Fake = TRUE;
1061 break;
1062 }
1063 }
1064 /* add event to the queue */
1065 InsertTailList(&Console->InputEvents, &KeyEventRecord->ListEntry);
1066 Console->WaitingChars++;
1067 /* if line input mode is enabled, only wake the client on enter key down */
1068 if (0 == (Console->Mode & ENABLE_LINE_INPUT)
1069 || Console->EarlyReturn
1070 || ('\n' == KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar
1071 && ! KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown))
1072 {
1073 if ('\n' == KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar)
1074 {
1075 Console->WaitingLines++;
1076 }
1077 bClientWake = TRUE;
1078 SetEvent(Console->ActiveEvent);
1079 }
1080 KeyEventRecord->Echoed = FALSE;
1081 if (0 != (Console->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT))
1082 && '\b' == KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar
1083 && KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown)
1084 {
1085 /* walk the input queue looking for a char to backspace */
1086 for (TempInput = (ConsoleInput *) Console->InputEvents.Blink;
1087 TempInput != (ConsoleInput *) &Console->InputEvents
1088 && (KEY_EVENT == TempInput->InputEvent.EventType
1089 || ! TempInput->InputEvent.Event.KeyEvent.bKeyDown
1090 || '\b' == TempInput->InputEvent.Event.KeyEvent.uChar.AsciiChar);
1091 TempInput = (ConsoleInput *) TempInput->ListEntry.Blink)
1092 {
1093 /* NOP */;
1094 }
1095 /* if we found one, delete it, otherwise, wake the client */
1096 if (TempInput != (ConsoleInput *) &Console->InputEvents)
1097 {
1098 /* delete previous key in queue, maybe echo backspace to screen, and do not place backspace on queue */
1099 RemoveEntryList(&TempInput->ListEntry);
1100 if (TempInput->Echoed)
1101 {
1102 ConioWriteConsole(Console, Console->ActiveBuffer,
1103 &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar,
1104 1, TRUE);
1105 }
1106 HeapFree(Win32CsrApiHeap, 0, TempInput);
1107 RemoveEntryList(&KeyEventRecord->ListEntry);
1108 HeapFree(Win32CsrApiHeap, 0, KeyEventRecord);
1109 Console->WaitingChars -= 2;
1110 }
1111 else
1112 {
1113 SetEvent(Console->ActiveEvent);
1114 }
1115 }
1116 else
1117 {
1118 /* echo chars if we are supposed to and client is waiting for some */
1119 if (0 != (Console->Mode & ENABLE_ECHO_INPUT) && Console->EchoCount
1120 && KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar
1121 && KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown
1122 && '\r' != KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar)
1123 {
1124 /* mark the char as already echoed */
1125 ConioWriteConsole(Console, Console->ActiveBuffer,
1126 &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar,
1127 1, TRUE);
1128 Console->EchoCount--;
1129 KeyEventRecord->Echoed = TRUE;
1130 }
1131 }
1132
1133 /* Console->WaitingChars++; */
1134 if (bClientWake || 0 == (Console->Mode & ENABLE_LINE_INPUT))
1135 {
1136 SetEvent(Console->ActiveEvent);
1137 }
1138 }
1139
1140 STATIC DWORD FASTCALL
1141 ConioGetShiftState(PBYTE KeyState)
1142 {
1143 DWORD ssOut = 0;
1144
1145 if (KeyState[VK_CAPITAL] & 1)
1146 ssOut |= CAPSLOCK_ON;
1147
1148 if (KeyState[VK_NUMLOCK] & 1)
1149 ssOut |= NUMLOCK_ON;
1150
1151 if (KeyState[VK_SCROLL] & 1)
1152 ssOut |= SCROLLLOCK_ON;
1153
1154 if (KeyState[VK_SHIFT] & 0x80)
1155 ssOut |= SHIFT_PRESSED;
1156
1157 if (KeyState[VK_LCONTROL] & 0x80)
1158 ssOut |= LEFT_CTRL_PRESSED;
1159 if (KeyState[VK_RCONTROL] & 0x80)
1160 ssOut |= RIGHT_CTRL_PRESSED;
1161
1162 if (KeyState[VK_LMENU] & 0x80)
1163 ssOut |= LEFT_ALT_PRESSED;
1164 if (KeyState[VK_RMENU] & 0x80)
1165 ssOut |= RIGHT_ALT_PRESSED;
1166
1167 return ssOut;
1168 }
1169
1170 VOID STDCALL
1171 ConioProcessKey(MSG *msg, PCSRSS_CONSOLE Console, BOOL TextMode)
1172 {
1173 static BYTE KeyState[256] = { 0 };
1174 /* MSDN mentions that you should use the last virtual key code received
1175 * when putting a virtual key identity to a WM_CHAR message since multiple
1176 * or translated keys may be involved. */
1177 static UINT LastVirtualKey = 0;
1178 DWORD ShiftState;
1179 ConsoleInput *ConInRec;
1180 UINT RepeatCount;
1181 CHAR AsciiChar;
1182 WCHAR UnicodeChar;
1183 UINT VirtualKeyCode;
1184 UINT VirtualScanCode;
1185 BOOL Down = FALSE;
1186 INPUT_RECORD er;
1187 ULONG ResultSize = 0;
1188
1189 RepeatCount = 1;
1190 VirtualScanCode = (msg->lParam >> 16) & 0xff;
1191 Down = msg->message == WM_KEYDOWN || msg->message == WM_CHAR ||
1192 msg->message == WM_SYSKEYDOWN || msg->message == WM_SYSCHAR;
1193
1194 GetKeyboardState(KeyState);
1195 ShiftState = ConioGetShiftState(KeyState);
1196
1197 if (msg->message == WM_CHAR || msg->message == WM_SYSCHAR)
1198 {
1199 VirtualKeyCode = LastVirtualKey;
1200 UnicodeChar = msg->wParam;
1201 }
1202 else
1203 {
1204 WCHAR Chars[2];
1205 INT RetChars = 0;
1206
1207 VirtualKeyCode = msg->wParam;
1208 RetChars = ToUnicodeEx(VirtualKeyCode,
1209 VirtualScanCode,
1210 KeyState,
1211 Chars,
1212 2,
1213 0,
1214 0);
1215 UnicodeChar = (1 == RetChars ? Chars[0] : 0);
1216 }
1217
1218 if (0 == ResultSize)
1219 {
1220 AsciiChar = 0;
1221 }
1222
1223 er.EventType = KEY_EVENT;
1224 er.Event.KeyEvent.bKeyDown = Down;
1225 er.Event.KeyEvent.wRepeatCount = RepeatCount;
1226 er.Event.KeyEvent.uChar.UnicodeChar = UnicodeChar;
1227 er.Event.KeyEvent.dwControlKeyState = ShiftState;
1228 er.Event.KeyEvent.wVirtualKeyCode = VirtualKeyCode;
1229 er.Event.KeyEvent.wVirtualScanCode = VirtualScanCode;
1230
1231 if (TextMode)
1232 {
1233 if (0 != (ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
1234 && VK_TAB == VirtualKeyCode)
1235 {
1236 if (Down)
1237 {
1238 TuiSwapConsole(ShiftState & SHIFT_PRESSED ? -1 : 1);
1239 }
1240
1241 return;
1242 }
1243 else if (VK_MENU == VirtualKeyCode && ! Down)
1244 {
1245 if (TuiSwapConsole(0))
1246 {
1247 return;
1248 }
1249 }
1250 }
1251
1252 if (NULL == Console)
1253 {
1254 return;
1255 }
1256
1257 ConInRec = HeapAlloc(Win32CsrApiHeap, 0, sizeof(ConsoleInput));
1258
1259 if (NULL == ConInRec)
1260 {
1261 return;
1262 }
1263
1264 ConInRec->InputEvent = er;
1265 ConInRec->Fake = UnicodeChar &&
1266 (msg->message != WM_CHAR && msg->message != WM_SYSCHAR &&
1267 msg->message != WM_KEYUP && msg->message != WM_SYSKEYUP);
1268 ConInRec->NotChar = (msg->message != WM_CHAR && msg->message != WM_SYSCHAR);
1269 ConInRec->Echoed = FALSE;
1270 if (ConInRec->NotChar)
1271 LastVirtualKey = msg->wParam;
1272
1273 DPRINT ("csrss: %s %s %s %s %02x %02x '%c' %04x\n",
1274 Down ? "down" : "up ",
1275 (msg->message == WM_CHAR || msg->message == WM_SYSCHAR) ?
1276 "char" : "key ",
1277 ConInRec->Fake ? "fake" : "real",
1278 ConInRec->NotChar ? "notc" : "char",
1279 VirtualScanCode,
1280 VirtualKeyCode,
1281 (AsciiChar >= ' ') ? AsciiChar : '.',
1282 ShiftState);
1283
1284 if (! ConInRec->Fake || ! ConInRec->NotChar)
1285 {
1286 ConioProcessChar(Console, ConInRec);
1287 }
1288 else
1289 {
1290 HeapFree(Win32CsrApiHeap, 0, ConInRec);
1291 }
1292 }
1293
1294 VOID
1295 Console_Api(DWORD RefreshEvent)
1296 {
1297 /* keep reading events from the keyboard and stuffing them into the current
1298 console's input queue */
1299 MSG msg;
1300
1301 /* This call establishes our message queue */
1302 PeekMessageW(&msg, 0, 0, 0, PM_NOREMOVE);
1303 /* This call registers our message queue */
1304 PrivateCsrssRegisterPrimitive();
1305 /* This call turns on the input system in win32k */
1306 PrivateCsrssAcquireOrReleaseInputOwnership(FALSE);
1307
1308 while (TRUE)
1309 {
1310 GetMessageW(&msg, 0, 0, 0);
1311 TranslateMessage(&msg);
1312
1313 if (msg.message == WM_CHAR || msg.message == WM_SYSCHAR ||
1314 msg.message == WM_KEYDOWN || msg.message == WM_KEYUP ||
1315 msg.message == WM_SYSKEYDOWN || msg.message == WM_SYSKEYUP)
1316 {
1317 ConioProcessKey(&msg, TuiGetFocusConsole(), TRUE);
1318 }
1319 }
1320
1321 PrivateCsrssAcquireOrReleaseInputOwnership(TRUE);
1322 }
1323
1324 CSR_API(CsrGetScreenBufferInfo)
1325 {
1326 NTSTATUS Status;
1327 PCSRSS_SCREEN_BUFFER Buff;
1328 PCONSOLE_SCREEN_BUFFER_INFO pInfo;
1329
1330 DPRINT("CsrGetScreenBufferInfo\n");
1331
1332 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1333 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
1334
1335 Status = ConioLockScreenBuffer(ProcessData, Request->Data.ScreenBufferInfoRequest.ConsoleHandle, &Buff);
1336 if (! NT_SUCCESS(Status))
1337 {
1338 return Reply->Status = Status;
1339 }
1340 pInfo = &Reply->Data.ScreenBufferInfoReply.Info;
1341 pInfo->dwSize.X = Buff->MaxX;
1342 pInfo->dwSize.Y = Buff->MaxY;
1343 pInfo->dwCursorPosition.X = Buff->CurrentX - Buff->ShowX;
1344 pInfo->dwCursorPosition.Y = (Buff->CurrentY + Buff->MaxY - Buff->ShowY) % Buff->MaxY;
1345 pInfo->wAttributes = Buff->DefaultAttrib;
1346 pInfo->srWindow.Left = 0;
1347 pInfo->srWindow.Right = Buff->MaxX - 1;
1348 pInfo->srWindow.Top = 0;
1349 pInfo->srWindow.Bottom = Buff->MaxY - 1;
1350 pInfo->dwMaximumWindowSize.X = Buff->MaxX;
1351 pInfo->dwMaximumWindowSize.Y = Buff->MaxY;
1352 ConioUnlockScreenBuffer(Buff);
1353
1354 Reply->Status = STATUS_SUCCESS;
1355
1356 return Reply->Status;
1357 }
1358
1359 CSR_API(CsrSetCursor)
1360 {
1361 NTSTATUS Status;
1362 PCSRSS_CONSOLE Console;
1363 PCSRSS_SCREEN_BUFFER Buff;
1364 LONG OldCursorX, OldCursorY;
1365
1366 DPRINT("CsrSetCursor\n");
1367
1368 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1369 if (! NT_SUCCESS(Status))
1370 {
1371 return Reply->Status = Status;
1372 }
1373
1374 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1375 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
1376
1377 Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetCursorRequest.ConsoleHandle, &Buff);
1378 if (! NT_SUCCESS(Status))
1379 {
1380 if (NULL != Console)
1381 {
1382 ConioUnlockConsole(Console);
1383 }
1384 return Reply->Status = Status;
1385 }
1386
1387 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY, &OldCursorX, &OldCursorY);
1388 Buff->CurrentX = Request->Data.SetCursorRequest.Position.X + Buff->ShowX;
1389 Buff->CurrentY = (Request->Data.SetCursorRequest.Position.Y + Buff->ShowY) % Buff->MaxY;
1390 if (NULL != Console && Buff == Console->ActiveBuffer)
1391 {
1392 if (! ConioSetScreenInfo(Console, Buff, OldCursorX, OldCursorY))
1393 {
1394 ConioUnlockScreenBuffer(Buff);
1395 return Reply->Status = STATUS_UNSUCCESSFUL;
1396 }
1397 }
1398
1399 ConioUnlockScreenBuffer(Buff);
1400 if (NULL != Console)
1401 {
1402 ConioUnlockConsole(Console);
1403 }
1404
1405 return Reply->Status = STATUS_SUCCESS;
1406 }
1407
1408 STATIC FASTCALL VOID
1409 ConioComputeUpdateRect(PCSRSS_SCREEN_BUFFER Buff, RECT *UpdateRect, COORD *Start, UINT Length)
1410 {
1411 if (Buff->MaxX <= Start->X + Length)
1412 {
1413 UpdateRect->left = 0;
1414 }
1415 else
1416 {
1417 UpdateRect->left = Start->X;
1418 }
1419 if (Buff->MaxX <= Start->X + Length)
1420 {
1421 UpdateRect->right = Buff->MaxX - 1;
1422 }
1423 else
1424 {
1425 UpdateRect->right = Start->X + Length - 1;
1426 }
1427 UpdateRect->top = Start->Y;
1428 UpdateRect->bottom = Start->Y+ (Start->X + Length - 1) / Buff->MaxX;
1429 if (Buff->MaxY <= UpdateRect->bottom)
1430 {
1431 UpdateRect->bottom = Buff->MaxY - 1;
1432 }
1433 }
1434
1435 CSR_API(CsrWriteConsoleOutputChar)
1436 {
1437 NTSTATUS Status;
1438 PBYTE String = Request->Data.WriteConsoleOutputCharRequest.String;
1439 PBYTE Buffer;
1440 PCSRSS_CONSOLE Console;
1441 PCSRSS_SCREEN_BUFFER Buff;
1442 DWORD X, Y, Length;
1443 RECT UpdateRect;
1444
1445 DPRINT("CsrWriteConsoleOutputChar\n");
1446
1447 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1448 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
1449
1450 if (Request->Header.DataSize
1451 < sizeof(CSRSS_WRITE_CONSOLE_OUTPUT_CHAR_REQUEST) - 1
1452 + Request->Data.WriteConsoleOutputCharRequest.Length)
1453 {
1454 DPRINT1("Invalid request size\n");
1455 return Reply->Status = STATUS_INVALID_PARAMETER;
1456 }
1457
1458 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1459 if (! NT_SUCCESS(Status))
1460 {
1461 return Reply->Status = Status;
1462 }
1463
1464 Status = ConioLockScreenBuffer(ProcessData,
1465 Request->Data.WriteConsoleOutputCharRequest.ConsoleHandle,
1466 &Buff);
1467 if (! NT_SUCCESS(Status))
1468 {
1469 if (NULL != Console)
1470 {
1471 ConioUnlockConsole(Console);
1472 }
1473 return Reply->Status = Status;
1474 }
1475
1476 X = Request->Data.WriteConsoleOutputCharRequest.Coord.X + Buff->ShowX;
1477 Y = (Request->Data.WriteConsoleOutputCharRequest.Coord.Y + Buff->ShowY) % Buff->MaxY;
1478 Length = Request->Data.WriteConsoleOutputCharRequest.Length;
1479 Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X)];
1480 while (Length--)
1481 {
1482 *Buffer = *String++;
1483 Buffer += 2;
1484 if (++X == Buff->MaxX)
1485 {
1486 if (++Y == Buff->MaxY)
1487 {
1488 Y = 0;
1489 Buffer = Buff->Buffer;
1490 }
1491 X = 0;
1492 }
1493 }
1494
1495 if (NULL != Console && Buff == Console->ActiveBuffer)
1496 {
1497 ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.WriteConsoleOutputCharRequest.Coord,
1498 Request->Data.WriteConsoleOutputCharRequest.Length);
1499 ConioDrawRegion(Console, &UpdateRect);
1500 }
1501
1502 Reply->Data.WriteConsoleOutputCharReply.EndCoord.X = X - Buff->ShowX;
1503 Reply->Data.WriteConsoleOutputCharReply.EndCoord.Y = (Y + Buff->MaxY - Buff->ShowY) % Buff->MaxY;
1504
1505 ConioUnlockScreenBuffer(Buff);
1506 if (NULL != Console)
1507 {
1508 ConioUnlockConsole(Console);
1509 }
1510
1511 return Reply->Status = STATUS_SUCCESS;
1512 }
1513
1514 CSR_API(CsrFillOutputChar)
1515 {
1516 NTSTATUS Status;
1517 PCSRSS_CONSOLE Console;
1518 PCSRSS_SCREEN_BUFFER Buff;
1519 DWORD X, Y, Length;
1520 BYTE Char;
1521 PBYTE Buffer;
1522 RECT UpdateRect;
1523
1524 DPRINT("CsrFillOutputChar\n");
1525
1526 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1527 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
1528
1529 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1530 if (! NT_SUCCESS(Status))
1531 {
1532 return Reply->Status = Status;
1533 }
1534
1535 Status = ConioLockScreenBuffer(ProcessData, Request->Data.FillOutputRequest.ConsoleHandle, &Buff);
1536 if (! NT_SUCCESS(Status))
1537 {
1538 if (NULL != Console)
1539 {
1540 ConioUnlockConsole(Console);
1541 }
1542 return Reply->Status = Status;
1543 }
1544
1545 X = Request->Data.FillOutputRequest.Position.X + Buff->ShowX;
1546 Y = (Request->Data.FillOutputRequest.Position.Y + Buff->ShowY) % Buff->MaxY;
1547 Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X)];
1548 Char = Request->Data.FillOutputRequest.Char;
1549 Length = Request->Data.FillOutputRequest.Length;
1550 while (Length--)
1551 {
1552 *Buffer = Char;
1553 Buffer += 2;
1554 if (++X == Buff->MaxX)
1555 {
1556 if (++Y == Buff->MaxY)
1557 {
1558 Y = 0;
1559 Buffer = Buff->Buffer;
1560 }
1561 X = 0;
1562 }
1563 }
1564
1565 if (NULL != Console && Buff == Console->ActiveBuffer)
1566 {
1567 ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.FillOutputRequest.Position,
1568 Request->Data.FillOutputRequest.Length);
1569 ConioDrawRegion(Console, &UpdateRect);
1570 }
1571
1572 ConioUnlockScreenBuffer(Buff);
1573 if (NULL != Console)
1574 {
1575 ConioUnlockConsole(Console);
1576 }
1577
1578 return Reply->Status;
1579 }
1580
1581 CSR_API(CsrReadInputEvent)
1582 {
1583 PLIST_ENTRY CurrentEntry;
1584 PCSRSS_CONSOLE Console;
1585 NTSTATUS Status;
1586 BOOLEAN Done = FALSE;
1587 ConsoleInput *Input;
1588
1589 DPRINT("CsrReadInputEvent\n");
1590
1591 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1592 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
1593 Reply->Data.ReadInputReply.Event = ProcessData->ConsoleEvent;
1594
1595 Status = ConioLockConsole(ProcessData, Request->Data.ReadInputRequest.ConsoleHandle, &Console);
1596 if (! NT_SUCCESS(Status))
1597 {
1598 return Reply->Status = Status;
1599 }
1600
1601 /* only get input if there is any */
1602 while (Console->InputEvents.Flink != &Console->InputEvents && ! Done)
1603 {
1604 CurrentEntry = RemoveHeadList(&Console->InputEvents);
1605 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
1606 Done = !Input->Fake;
1607 Reply->Data.ReadInputReply.Input = Input->InputEvent;
1608
1609 if (Request->Data.ReadInputRequest.Unicode == FALSE)
1610 {
1611 ConioInputEventToAnsi(Console, &Reply->Data.ReadInputReply.Input);
1612 }
1613
1614 if (Input->InputEvent.EventType == KEY_EVENT)
1615 {
1616 if (0 != (Console->Mode & ENABLE_LINE_INPUT)
1617 && Input->InputEvent.Event.KeyEvent.bKeyDown
1618 && '\r' == Input->InputEvent.Event.KeyEvent.uChar.AsciiChar)
1619 {
1620 Console->WaitingLines--;
1621 }
1622 Console->WaitingChars--;
1623 }
1624 HeapFree(Win32CsrApiHeap, 0, Input);
1625
1626 Reply->Data.ReadInputReply.MoreEvents = (Console->InputEvents.Flink != &Console->InputEvents);
1627 Status = STATUS_SUCCESS;
1628 Console->EarlyReturn = FALSE; /* clear early return */
1629 }
1630
1631 if (! Done)
1632 {
1633 Status = STATUS_PENDING;
1634 Console->EarlyReturn = TRUE; /* mark for early return */
1635 }
1636
1637 ConioUnlockConsole(Console);
1638
1639 return Reply->Status = Status;
1640 }
1641
1642 CSR_API(CsrWriteConsoleOutputAttrib)
1643 {
1644 PCSRSS_CONSOLE Console;
1645 PCSRSS_SCREEN_BUFFER Buff;
1646 PUCHAR Buffer, Attribute;
1647 int X, Y, Length;
1648 NTSTATUS Status;
1649 RECT UpdateRect;
1650
1651 DPRINT("CsrWriteConsoleOutputAttrib\n");
1652
1653 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1654 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
1655
1656 if (Request->Header.DataSize
1657 < sizeof(CSRSS_WRITE_CONSOLE_OUTPUT_ATTRIB_REQUEST) - 1
1658 + Request->Data.WriteConsoleOutputAttribRequest.Length)
1659 {
1660 DPRINT1("Invalid request size\n");
1661 return Reply->Status = STATUS_INVALID_PARAMETER;
1662 }
1663
1664 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1665 if (! NT_SUCCESS(Status))
1666 {
1667 return Reply->Status = Status;
1668 }
1669
1670 Status = ConioLockScreenBuffer(ProcessData,
1671 Request->Data.WriteConsoleOutputAttribRequest.ConsoleHandle,
1672 &Buff);
1673 if (! NT_SUCCESS(Status))
1674 {
1675 if (NULL != Console)
1676 {
1677 ConioUnlockConsole(Console);
1678 }
1679 return Reply->Status = Status;
1680 }
1681
1682 X = Request->Data.WriteConsoleOutputAttribRequest.Coord.X + Buff->ShowX;
1683 Y = (Request->Data.WriteConsoleOutputAttribRequest.Coord.Y + Buff->ShowY) % Buff->MaxY;
1684 Length = Request->Data.WriteConsoleOutputAttribRequest.Length;
1685 Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X) + 1];
1686 Attribute = Request->Data.WriteConsoleOutputAttribRequest.String;
1687 while (Length--)
1688 {
1689 *Buffer = *Attribute++;
1690 Buffer += 2;
1691 if (++X == Buff->MaxX)
1692 {
1693 if (++Y == Buff->MaxY)
1694 {
1695 Y = 0;
1696 Buffer = Buff->Buffer + 1;
1697 }
1698 X = 0;
1699 }
1700 }
1701
1702 if (NULL != Console && Buff == Console->ActiveBuffer)
1703 {
1704 ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.WriteConsoleOutputAttribRequest.Coord,
1705 Request->Data.WriteConsoleOutputAttribRequest.Length);
1706 ConioDrawRegion(Console, &UpdateRect);
1707 }
1708
1709 if (NULL != Console)
1710 {
1711 ConioUnlockConsole(Console);
1712 }
1713
1714 Reply->Data.WriteConsoleOutputAttribReply.EndCoord.X = Buff->CurrentX - Buff->ShowX;
1715 Reply->Data.WriteConsoleOutputAttribReply.EndCoord.Y = (Buff->CurrentY + Buff->MaxY - Buff->ShowY) % Buff->MaxY;
1716
1717 ConioUnlockScreenBuffer(Buff);
1718
1719 return Reply->Status = STATUS_SUCCESS;
1720 }
1721
1722 CSR_API(CsrFillOutputAttrib)
1723 {
1724 PCSRSS_SCREEN_BUFFER Buff;
1725 PCHAR Buffer;
1726 NTSTATUS Status;
1727 int X, Y, Length;
1728 UCHAR Attr;
1729 RECT UpdateRect;
1730 PCSRSS_CONSOLE Console;
1731
1732 DPRINT("CsrFillOutputAttrib\n");
1733
1734 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1735 if (! NT_SUCCESS(Status))
1736 {
1737 return Reply->Status = Status;
1738 }
1739
1740 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1741 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
1742 Status = ConioLockScreenBuffer(ProcessData, Request->Data.FillOutputAttribRequest.ConsoleHandle, &Buff);
1743 if (! NT_SUCCESS(Status))
1744 {
1745 if (NULL != Console)
1746 {
1747 ConioUnlockConsole(Console);
1748 }
1749 return Reply->Status = Status;
1750 }
1751
1752 X = Request->Data.FillOutputAttribRequest.Coord.X + Buff->ShowX;
1753 Y = (Request->Data.FillOutputAttribRequest.Coord.Y + Buff->ShowY) % Buff->MaxY;
1754 Length = Request->Data.FillOutputAttribRequest.Length;
1755 Attr = Request->Data.FillOutputAttribRequest.Attribute;
1756 Buffer = &Buff->Buffer[(Y * Buff->MaxX * 2) + (X * 2) + 1];
1757 while (Length--)
1758 {
1759 *Buffer = Attr;
1760 Buffer += 2;
1761 if (++X == Buff->MaxX)
1762 {
1763 if (++Y == Buff->MaxY)
1764 {
1765 Y = 0;
1766 Buffer = Buff->Buffer + 1;
1767 }
1768 X = 0;
1769 }
1770 }
1771
1772 if (NULL != Console && Buff == Console->ActiveBuffer)
1773 {
1774 ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.FillOutputAttribRequest.Coord,
1775 Request->Data.FillOutputAttribRequest.Length);
1776 ConioDrawRegion(Console, &UpdateRect);
1777 }
1778
1779 ConioUnlockScreenBuffer(Buff);
1780 if (NULL != Console)
1781 {
1782 ConioUnlockConsole(Console);
1783 }
1784
1785 return Reply->Status = STATUS_SUCCESS;
1786 }
1787
1788
1789 CSR_API(CsrGetCursorInfo)
1790 {
1791 PCSRSS_SCREEN_BUFFER Buff;
1792 NTSTATUS Status;
1793
1794 DPRINT("CsrGetCursorInfo\n");
1795
1796 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1797 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
1798
1799 Status = ConioLockScreenBuffer(ProcessData, Request->Data.GetCursorInfoRequest.ConsoleHandle, &Buff);
1800 if (! NT_SUCCESS(Status))
1801 {
1802 return Reply->Status = Status;
1803 }
1804 Reply->Data.GetCursorInfoReply.Info = Buff->CursorInfo;
1805 ConioUnlockScreenBuffer(Buff);
1806
1807 return Reply->Status = STATUS_SUCCESS;
1808 }
1809
1810 CSR_API(CsrSetCursorInfo)
1811 {
1812 PCSRSS_CONSOLE Console;
1813 PCSRSS_SCREEN_BUFFER Buff;
1814 DWORD Size;
1815 BOOL Visible;
1816 NTSTATUS Status;
1817
1818 DPRINT("CsrSetCursorInfo\n");
1819
1820 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1821 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
1822
1823 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1824 if (! NT_SUCCESS(Status))
1825 {
1826 return Reply->Status = Status;
1827 }
1828
1829 Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetCursorInfoRequest.ConsoleHandle, &Buff);
1830 if (! NT_SUCCESS(Status))
1831 {
1832 if (NULL != Console)
1833 {
1834 ConioUnlockConsole(Console);
1835 }
1836 return Reply->Status = Status;
1837 }
1838
1839 Size = Request->Data.SetCursorInfoRequest.Info.dwSize;
1840 Visible = Request->Data.SetCursorInfoRequest.Info.bVisible;
1841 if (Size < 1)
1842 {
1843 Size = 1;
1844 }
1845 if (100 < Size)
1846 {
1847 Size = 100;
1848 }
1849
1850 if (Size != Buff->CursorInfo.dwSize
1851 || (Visible && ! Buff->CursorInfo.bVisible) || (! Visible && Buff->CursorInfo.bVisible))
1852 {
1853 Buff->CursorInfo.dwSize = Size;
1854 Buff->CursorInfo.bVisible = Visible;
1855
1856 if (NULL != Console && ! ConioSetCursorInfo(Console, Buff))
1857 {
1858 ConioUnlockScreenBuffer(Buff);
1859 ConioUnlockConsole(Console);
1860 return Reply->Status = STATUS_UNSUCCESSFUL;
1861 }
1862 }
1863
1864 ConioUnlockScreenBuffer(Buff);
1865 if (NULL != Console)
1866 {
1867 ConioUnlockConsole(Console);
1868 }
1869
1870 return Reply->Status = STATUS_SUCCESS;
1871 }
1872
1873 CSR_API(CsrSetTextAttrib)
1874 {
1875 NTSTATUS Status;
1876 PCSRSS_CONSOLE Console;
1877 PCSRSS_SCREEN_BUFFER Buff;
1878 LONG OldCursorX, OldCursorY;
1879
1880 DPRINT("CsrSetTextAttrib\n");
1881
1882 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1883 if (! NT_SUCCESS(Status))
1884 {
1885 return Reply->Status = Status;
1886 }
1887
1888 Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetCursorRequest.ConsoleHandle, &Buff);
1889 if (! NT_SUCCESS(Status))
1890 {
1891 if (NULL != Console)
1892 {
1893 ConioUnlockConsole(Console);
1894 }
1895 return Reply->Status = Status;
1896 }
1897
1898 ConioPhysicalToLogical(Buff, Buff->CurrentX, Buff->CurrentY, &OldCursorX, &OldCursorY);
1899
1900 Buff->DefaultAttrib = Request->Data.SetAttribRequest.Attrib;
1901 if (NULL != Console && Buff == Console->ActiveBuffer)
1902 {
1903 if (! ConioSetScreenInfo(Console, Buff, OldCursorX, OldCursorY))
1904 {
1905 ConioUnlockScreenBuffer(Buff);
1906 ConioUnlockConsole(Console);
1907 return Reply->Status = STATUS_UNSUCCESSFUL;
1908 }
1909 }
1910
1911 ConioUnlockScreenBuffer(Buff);
1912 if (NULL != Console)
1913 {
1914 ConioUnlockConsole(Console);
1915 }
1916
1917 return Reply->Status = STATUS_SUCCESS;
1918 }
1919
1920 CSR_API(CsrSetConsoleMode)
1921 {
1922 NTSTATUS Status;
1923 PCSRSS_CONSOLE Console;
1924 PCSRSS_SCREEN_BUFFER Buff;
1925
1926 DPRINT("CsrSetConsoleMode\n");
1927
1928 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1929 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
1930 Status = Win32CsrGetObject(ProcessData,
1931 Request->Data.SetConsoleModeRequest.ConsoleHandle,
1932 (Object_t **) &Console);
1933 if (! NT_SUCCESS(Status))
1934 {
1935 return Reply->Status = Status;
1936 }
1937
1938 Buff = (PCSRSS_SCREEN_BUFFER)Console;
1939 if (CONIO_CONSOLE_MAGIC == Console->Header.Type)
1940 {
1941 Console->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_INPUT_MODE_VALID;
1942 }
1943 else if (CONIO_SCREEN_BUFFER_MAGIC == Console->Header.Type)
1944 {
1945 Buff->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_OUTPUT_MODE_VALID;
1946 }
1947 else
1948 {
1949 return Reply->Status = STATUS_INVALID_HANDLE;
1950 }
1951
1952 Reply->Status = STATUS_SUCCESS;
1953
1954 return Reply->Status;
1955 }
1956
1957 CSR_API(CsrGetConsoleMode)
1958 {
1959 NTSTATUS Status;
1960 PCSRSS_CONSOLE Console;
1961 PCSRSS_SCREEN_BUFFER Buff; /* gee, I really wish I could use an anonymous union here */
1962
1963 DPRINT("CsrGetConsoleMode\n");
1964
1965 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
1966 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
1967 Status = Win32CsrGetObject(ProcessData, Request->Data.GetConsoleModeRequest.ConsoleHandle,
1968 (Object_t **) &Console);
1969 if (! NT_SUCCESS(Status))
1970 {
1971 return Reply->Status = Status;
1972 }
1973 Reply->Status = STATUS_SUCCESS;
1974 Buff = (PCSRSS_SCREEN_BUFFER) Console;
1975 if (CONIO_CONSOLE_MAGIC == Console->Header.Type)
1976 {
1977 Reply->Data.GetConsoleModeReply.ConsoleMode = Console->Mode;
1978 }
1979 else if (CONIO_SCREEN_BUFFER_MAGIC == Buff->Header.Type)
1980 {
1981 Reply->Data.GetConsoleModeReply.ConsoleMode = Buff->Mode;
1982 }
1983 else
1984 {
1985 Reply->Status = STATUS_INVALID_HANDLE;
1986 }
1987
1988 return Reply->Status;
1989 }
1990
1991 CSR_API(CsrCreateScreenBuffer)
1992 {
1993 PCSRSS_CONSOLE Console;
1994 PCSRSS_SCREEN_BUFFER Buff;
1995 NTSTATUS Status;
1996
1997 DPRINT("CsrCreateScreenBuffer\n");
1998
1999 if (ProcessData == NULL)
2000 {
2001 return Reply->Status = STATUS_INVALID_PARAMETER;
2002 }
2003
2004 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2005 if (! NT_SUCCESS(Status))
2006 {
2007 return Reply->Status = Status;
2008 }
2009 if (NULL == Console)
2010 {
2011 return Reply->Status = STATUS_INVALID_HANDLE;
2012 }
2013
2014 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2015 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
2016
2017 Buff = HeapAlloc(Win32CsrApiHeap, 0, sizeof(CSRSS_SCREEN_BUFFER));
2018 if (NULL == Buff)
2019 {
2020 Reply->Status = STATUS_INSUFFICIENT_RESOURCES;
2021 }
2022
2023 Status = CsrInitConsoleScreenBuffer(Console, Buff);
2024 if(! NT_SUCCESS(Status))
2025 {
2026 Reply->Status = Status;
2027 }
2028 else
2029 {
2030 Reply->Status = Win32CsrInsertObject(ProcessData, &Reply->Data.CreateScreenBufferReply.OutputHandle, &Buff->Header);
2031 }
2032
2033 ConioUnlockConsole(Console);
2034
2035 return Reply->Status;
2036 }
2037
2038 CSR_API(CsrSetScreenBuffer)
2039 {
2040 NTSTATUS Status;
2041 PCSRSS_CONSOLE Console;
2042 PCSRSS_SCREEN_BUFFER Buff;
2043
2044 DPRINT("CsrSetScreenBuffer\n");
2045
2046 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2047 if (! NT_SUCCESS(Status))
2048 {
2049 return Reply->Status = Status;
2050 }
2051 if (NULL == Console)
2052 {
2053 DPRINT1("Trying to set screen buffer for app without console\n");
2054 return Reply->Status = STATUS_INVALID_HANDLE;
2055 }
2056
2057 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2058 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
2059
2060 Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetScreenBufferRequest.OutputHandle, &Buff);
2061 if (! NT_SUCCESS(Status))
2062 {
2063 ConioUnlockConsole(Console);
2064 return Reply->Status;
2065 }
2066
2067 if (Buff == Console->ActiveBuffer)
2068 {
2069 ConioUnlockScreenBuffer(Buff);
2070 ConioUnlockConsole(Console);
2071 return STATUS_SUCCESS;
2072 }
2073
2074 /* drop reference to old buffer, maybe delete */
2075 if (! InterlockedDecrement(&Console->ActiveBuffer->Header.ReferenceCount))
2076 {
2077 ConioDeleteScreenBuffer((Object_t *) Console->ActiveBuffer);
2078 }
2079 /* tie console to new buffer */
2080 Console->ActiveBuffer = Buff;
2081 /* inc ref count on new buffer */
2082 InterlockedIncrement(&Buff->Header.ReferenceCount);
2083 /* Redraw the console */
2084 ConioDrawConsole(Console);
2085
2086 ConioUnlockScreenBuffer(Buff);
2087 ConioUnlockConsole(Console);
2088
2089 return Reply->Status = STATUS_SUCCESS;
2090 }
2091
2092 CSR_API(CsrSetTitle)
2093 {
2094 NTSTATUS Status;
2095 PCSRSS_CONSOLE Console;
2096
2097 DPRINT("CsrSetTitle\n");
2098
2099 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2100 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
2101
2102 if (Request->Header.DataSize
2103 < sizeof(CSRSS_SET_TITLE_REQUEST) - 1
2104 + Request->Data.SetTitleRequest.Length)
2105 {
2106 DPRINT1("Invalid request size\n");
2107 return Reply->Status = STATUS_INVALID_PARAMETER;
2108 }
2109
2110 Status = ConioLockConsole(ProcessData, Request->Data.SetTitleRequest.Console, &Console);
2111 if(! NT_SUCCESS(Status))
2112 {
2113 Reply->Status = Status;
2114 }
2115 else
2116 {
2117 /* copy title to console */
2118 RtlFreeUnicodeString(&Console->Title);
2119 RtlCreateUnicodeString(&Console->Title, Request->Data.SetTitleRequest.Title);
2120 if (! ConioChangeTitle(Console))
2121 {
2122 Reply->Status = STATUS_UNSUCCESSFUL;
2123 }
2124 else
2125 {
2126 Reply->Status = STATUS_SUCCESS;
2127 }
2128 }
2129 ConioUnlockConsole(Console);
2130
2131 return Reply->Status;
2132 }
2133
2134 CSR_API(CsrGetTitle)
2135 {
2136 NTSTATUS Status;
2137 PCSRSS_CONSOLE Console;
2138
2139 DPRINT("CsrGetTitle\n");
2140
2141 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2142 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
2143 Status = ConioLockConsole(ProcessData,
2144 Request->Data.GetTitleRequest.ConsoleHandle,
2145 &Console);
2146 if (! NT_SUCCESS(Status))
2147 {
2148 DPRINT1("Can't get console\n");
2149 return Reply->Status = Status;
2150 }
2151
2152 /* Copy title of the console to the user title buffer */
2153 RtlZeroMemory(&Reply->Data.GetTitleReply, sizeof(CSRSS_GET_TITLE_REPLY));
2154 Reply->Data.GetTitleReply.ConsoleHandle = Request->Data.GetTitleRequest.ConsoleHandle;
2155 Reply->Data.GetTitleReply.Length = Console->Title.Length;
2156 wcscpy (Reply->Data.GetTitleReply.Title, Console->Title.Buffer);
2157 Reply->Header.MessageSize += Console->Title.Length;
2158 Reply->Header.DataSize += Console->Title.Length;
2159 Reply->Status = STATUS_SUCCESS;
2160
2161 ConioUnlockConsole(Console);
2162
2163 return Reply->Status;
2164 }
2165
2166 CSR_API(CsrWriteConsoleOutput)
2167 {
2168 SHORT i, X, Y, SizeX, SizeY;
2169 PCSRSS_CONSOLE Console;
2170 PCSRSS_SCREEN_BUFFER Buff;
2171 RECT ScreenBuffer;
2172 CHAR_INFO* CurCharInfo;
2173 RECT WriteRegion;
2174 CHAR_INFO* CharInfo;
2175 COORD BufferCoord;
2176 COORD BufferSize;
2177 NTSTATUS Status;
2178 DWORD Offset;
2179 DWORD PSize;
2180
2181 DPRINT("CsrWriteConsoleOutput\n");
2182
2183 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2184 if (! NT_SUCCESS(Status))
2185 {
2186 return Reply->Status = Status;
2187 }
2188
2189 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2190 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
2191 Status = ConioLockScreenBuffer(ProcessData,
2192 Request->Data.WriteConsoleOutputRequest.ConsoleHandle,
2193 &Buff);
2194 if (! NT_SUCCESS(Status))
2195 {
2196 if (NULL != Console)
2197 {
2198 ConioUnlockConsole(Console);
2199 }
2200 return Reply->Status = Status;
2201 }
2202
2203 BufferSize = Request->Data.WriteConsoleOutputRequest.BufferSize;
2204 PSize = BufferSize.X * BufferSize.Y * sizeof(CHAR_INFO);
2205 BufferCoord = Request->Data.WriteConsoleOutputRequest.BufferCoord;
2206 CharInfo = Request->Data.WriteConsoleOutputRequest.CharInfo;
2207 if (((PVOID)CharInfo < ProcessData->CsrSectionViewBase) ||
2208 (((PVOID)CharInfo + PSize) >
2209 (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2210 {
2211 ConioUnlockScreenBuffer(Buff);
2212 ConioUnlockConsole(Console);
2213 return Reply->Status = STATUS_ACCESS_VIOLATION;
2214 }
2215 WriteRegion.left = Request->Data.WriteConsoleOutputRequest.WriteRegion.Left;
2216 WriteRegion.top = Request->Data.WriteConsoleOutputRequest.WriteRegion.Top;
2217 WriteRegion.right = Request->Data.WriteConsoleOutputRequest.WriteRegion.Right;
2218 WriteRegion.bottom = Request->Data.WriteConsoleOutputRequest.WriteRegion.Bottom;
2219
2220 SizeY = RtlRosMin(BufferSize.Y - BufferCoord.Y, ConioRectHeight(&WriteRegion));
2221 SizeX = RtlRosMin(BufferSize.X - BufferCoord.X, ConioRectWidth(&WriteRegion));
2222 WriteRegion.bottom = WriteRegion.top + SizeY - 1;
2223 WriteRegion.right = WriteRegion.left + SizeX - 1;
2224
2225 /* Make sure WriteRegion is inside the screen buffer */
2226 ConioInitRect(&ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
2227 if (! ConioGetIntersection(&WriteRegion, &ScreenBuffer, &WriteRegion))
2228 {
2229 ConioUnlockScreenBuffer(Buff);
2230 ConioUnlockConsole(Console);
2231
2232 /* It is okay to have a WriteRegion completely outside the screen buffer.
2233 No data is written then. */
2234 return Reply->Status = STATUS_SUCCESS;
2235 }
2236
2237 for (i = 0, Y = WriteRegion.top; Y <= WriteRegion.bottom; i++, Y++)
2238 {
2239 CurCharInfo = CharInfo + (i + BufferCoord.Y) * BufferSize.X + BufferCoord.X;
2240 Offset = (((Y + Buff->ShowY) % Buff->MaxY) * Buff->MaxX + WriteRegion.left) * 2;
2241 for (X = WriteRegion.left; X <= WriteRegion.right; X++)
2242 {
2243 if (Request->Data.WriteConsoleOutputRequest.Unicode)
2244 {
2245 CHAR AsciiChar;
2246 WideCharToMultiByte(Console->OutputCodePage, 0,
2247 &CurCharInfo->Char.UnicodeChar, 1,
2248 &AsciiChar, 1, NULL, NULL);
2249 SET_CELL_BUFFER(Buff, Offset, AsciiChar, CurCharInfo->Attributes);
2250 }
2251 else
2252 {
2253 SET_CELL_BUFFER(Buff, Offset, CurCharInfo->Char.AsciiChar, CurCharInfo->Attributes);
2254 }
2255 CurCharInfo++;
2256 }
2257 }
2258
2259 if (NULL != Console)
2260 {
2261 ConioDrawRegion(Console, &WriteRegion);
2262 }
2263
2264 ConioUnlockScreenBuffer(Buff);
2265 ConioUnlockConsole(Console);
2266
2267 Reply->Data.WriteConsoleOutputReply.WriteRegion.Right = WriteRegion.left + SizeX - 1;
2268 Reply->Data.WriteConsoleOutputReply.WriteRegion.Bottom = WriteRegion.top + SizeY - 1;
2269 Reply->Data.WriteConsoleOutputReply.WriteRegion.Left = WriteRegion.left;
2270 Reply->Data.WriteConsoleOutputReply.WriteRegion.Top = WriteRegion.top;
2271
2272 return Reply->Status = STATUS_SUCCESS;
2273 }
2274
2275 CSR_API(CsrFlushInputBuffer)
2276 {
2277 PLIST_ENTRY CurrentEntry;
2278 PCSRSS_CONSOLE Console;
2279 ConsoleInput* Input;
2280 NTSTATUS Status;
2281
2282 DPRINT("CsrFlushInputBuffer\n");
2283
2284 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2285 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
2286 Status = ConioLockConsole(ProcessData,
2287 Request->Data.FlushInputBufferRequest.ConsoleInput,
2288 &Console);
2289 if(! NT_SUCCESS(Status))
2290 {
2291 return Reply->Status = Status;
2292 }
2293
2294 /* Discard all entries in the input event queue */
2295 while (!IsListEmpty(&Console->InputEvents))
2296 {
2297 CurrentEntry = RemoveHeadList(&Console->InputEvents);
2298 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
2299 /* Destroy the event */
2300 HeapFree(Win32CsrApiHeap, 0, Input);
2301 }
2302 Console->WaitingChars=0;
2303
2304 ConioUnlockConsole(Console);
2305
2306 return Reply->Status = STATUS_SUCCESS;
2307 }
2308
2309 CSR_API(CsrScrollConsoleScreenBuffer)
2310 {
2311 PCSRSS_CONSOLE Console;
2312 PCSRSS_SCREEN_BUFFER Buff;
2313 RECT ScreenBuffer;
2314 RECT SrcRegion;
2315 RECT DstRegion;
2316 RECT FillRegion;
2317 RECT ScrollRectangle;
2318 RECT ClipRectangle;
2319 NTSTATUS Status;
2320 BOOLEAN DoFill;
2321
2322 DPRINT("CsrScrollConsoleScreenBuffer\n");
2323
2324 ALIAS(ConsoleHandle,Request->Data.ScrollConsoleScreenBufferRequest.ConsoleHandle);
2325 ALIAS(UseClipRectangle,Request->Data.ScrollConsoleScreenBufferRequest.UseClipRectangle);
2326 ALIAS(DestinationOrigin,Request->Data.ScrollConsoleScreenBufferRequest.DestinationOrigin);
2327 ALIAS(Fill,Request->Data.ScrollConsoleScreenBufferRequest.Fill);
2328
2329 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2330 if (! NT_SUCCESS(Status))
2331 {
2332 return Reply->Status = Status;
2333 }
2334
2335 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2336 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
2337 Status = ConioLockScreenBuffer(ProcessData, ConsoleHandle, &Buff);
2338 if (! NT_SUCCESS(Status))
2339 {
2340 if (NULL != Console)
2341 {
2342 ConioUnlockConsole(Console);
2343 }
2344 return Reply->Status = Status;
2345 }
2346
2347 ScrollRectangle.left = Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle.Left;
2348 ScrollRectangle.top = Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle.Top;
2349 ScrollRectangle.right = Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle.Right;
2350 ScrollRectangle.bottom = Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle.Bottom;
2351 ClipRectangle.left = Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle.Left;
2352 ClipRectangle.top = Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle.Top;
2353 ClipRectangle.right = Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle.Right;
2354 ClipRectangle.bottom = Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle.Bottom;
2355
2356 /* Make sure source rectangle is inside the screen buffer */
2357 ConioInitRect(&ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
2358 if (! ConioGetIntersection(&SrcRegion, &ScreenBuffer, &ScrollRectangle))
2359 {
2360 ConioUnlockScreenBuffer(Buff);
2361 return Reply->Status = STATUS_INVALID_PARAMETER;
2362 }
2363
2364 if (UseClipRectangle && ! ConioGetIntersection(&SrcRegion, &SrcRegion, &ClipRectangle))
2365 {
2366 ConioUnlockScreenBuffer(Buff);
2367 return Reply->Status = STATUS_SUCCESS;
2368 }
2369
2370
2371 ConioInitRect(&DstRegion,
2372 DestinationOrigin.Y,
2373 DestinationOrigin.X,
2374 DestinationOrigin.Y + ConioRectHeight(&ScrollRectangle) - 1,
2375 DestinationOrigin.X + ConioRectWidth(&ScrollRectangle) - 1);
2376
2377 /* Make sure destination rectangle is inside the screen buffer */
2378 if (! ConioGetIntersection(&DstRegion, &DstRegion, &ScreenBuffer))
2379 {
2380 ConioUnlockScreenBuffer(Buff);
2381 return Reply->Status = STATUS_INVALID_PARAMETER;
2382 }
2383
2384 ConioCopyRegion(Buff, &SrcRegion, &DstRegion);
2385
2386 /* Get the region that should be filled with the specified character and attributes */
2387
2388 DoFill = FALSE;
2389
2390 ConioGetUnion(&FillRegion, &SrcRegion, &DstRegion);
2391
2392 if (ConioSubtractRect(&FillRegion, &FillRegion, &DstRegion))
2393 {
2394 /* FIXME: The subtracted rectangle is off by one line */
2395 FillRegion.top += 1;
2396
2397 ConioFillRegion(Buff, &FillRegion, Fill);
2398 DoFill = TRUE;
2399 }
2400
2401 if (NULL != Console && Buff == Console->ActiveBuffer)
2402 {
2403 /* Draw destination region */
2404 ConioDrawRegion(Console, &DstRegion);
2405
2406 if (DoFill)
2407 {
2408 /* Draw filled region */
2409 ConioDrawRegion(Console, &FillRegion);
2410 }
2411 }
2412
2413 ConioUnlockScreenBuffer(Buff);
2414 if (NULL != Console)
2415 {
2416 ConioUnlockConsole(Console);
2417 }
2418
2419 return Reply->Status = STATUS_SUCCESS;
2420 }
2421
2422 CSR_API(CsrReadConsoleOutputChar)
2423 {
2424 NTSTATUS Status;
2425 PCSRSS_SCREEN_BUFFER Buff;
2426 DWORD Xpos, Ypos;
2427 BYTE* ReadBuffer;
2428 DWORD i;
2429
2430 DPRINT("CsrReadConsoleOutputChar\n");
2431
2432 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2433 Reply->Header.DataSize = Reply->Header.MessageSize - LPC_MESSAGE_BASE_SIZE;
2434 ReadBuffer = Reply->Data.ReadConsoleOutputCharReply.String;
2435
2436 Status = ConioLockScreenBuffer(ProcessData, Request->Data.ReadConsoleOutputCharRequest.ConsoleHandle, &Buff);
2437 if (! NT_SUCCESS(Status))
2438 {
2439 return Reply->Status = Status;
2440 }
2441
2442 Xpos = Request->Data.ReadConsoleOutputCharRequest.ReadCoord.X + Buff->ShowX;
2443 Ypos = (Request->Data.ReadConsoleOutputCharRequest.ReadCoord.Y + Buff->ShowY) % Buff->MaxY;
2444
2445 for (i = 0; i < Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead; ++i)
2446 {
2447 *ReadBuffer = Buff->Buffer[(Xpos * 2) + (Ypos * 2 * Buff->MaxX)];
2448
2449 ReadBuffer++;
2450 Xpos++;
2451
2452 if (Xpos == Buff->MaxX)
2453 {
2454 Xpos = 0;
2455 Ypos++;
2456
2457 if (Ypos == Buff->MaxY)
2458 {
2459 Ypos = 0;
2460 }
2461 }
2462 }
2463
2464 *ReadBuffer = 0;
2465 Reply->Status = STATUS_SUCCESS;
2466 Reply->Data.ReadConsoleOutputCharReply.EndCoord.X = Xpos - Buff->ShowX;
2467 Reply->Data.ReadConsoleOutputCharReply.EndCoord.Y = (Ypos - Buff->ShowY + Buff->MaxY) % Buff->MaxY;
2468 Reply->Header.MessageSize += Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead;
2469 Reply->Header.DataSize += Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead;
2470
2471 ConioUnlockScreenBuffer(Buff);
2472
2473 return Reply->Status;
2474 }
2475
2476
2477 CSR_API(CsrReadConsoleOutputAttrib)
2478 {
2479 NTSTATUS Status;
2480 PCSRSS_SCREEN_BUFFER Buff;
2481 DWORD Xpos, Ypos;
2482 CHAR* ReadBuffer;
2483 DWORD i;
2484
2485 DPRINT("CsrReadConsoleOutputAttrib\n");
2486
2487 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2488 Reply->Header.DataSize = Reply->Header.MessageSize - LPC_MESSAGE_BASE_SIZE;
2489 ReadBuffer = Reply->Data.ReadConsoleOutputAttribReply.String;
2490
2491 Status = ConioLockScreenBuffer(ProcessData, Request->Data.ReadConsoleOutputAttribRequest.ConsoleHandle, &Buff);
2492 if (! NT_SUCCESS(Status))
2493 {
2494 return Reply->Status = Status;
2495 }
2496
2497 Xpos = Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.X + Buff->ShowX;
2498 Ypos = (Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.Y + Buff->ShowY) % Buff->MaxY;
2499
2500 for (i = 0; i < Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead; ++i)
2501 {
2502 *ReadBuffer = Buff->Buffer[(Xpos * 2) + (Ypos * 2 * Buff->MaxX) + 1];
2503
2504 ReadBuffer++;
2505 Xpos++;
2506
2507 if (Xpos == Buff->MaxX)
2508 {
2509 Xpos = 0;
2510 Ypos++;
2511
2512 if (Ypos == Buff->MaxY)
2513 {
2514 Ypos = 0;
2515 }
2516 }
2517 }
2518
2519 *ReadBuffer = 0;
2520
2521 Reply->Status = STATUS_SUCCESS;
2522 Reply->Data.ReadConsoleOutputAttribReply.EndCoord.X = Xpos - Buff->ShowX;
2523 Reply->Data.ReadConsoleOutputAttribReply.EndCoord.Y = (Ypos - Buff->ShowY + Buff->MaxY) % Buff->MaxY;
2524 Reply->Header.MessageSize += Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead;
2525 Reply->Header.DataSize += Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead;
2526
2527 ConioUnlockScreenBuffer(Buff);
2528
2529 return Reply->Status;
2530 }
2531
2532
2533 CSR_API(CsrGetNumberOfConsoleInputEvents)
2534 {
2535 NTSTATUS Status;
2536 PCSRSS_CONSOLE Console;
2537 PLIST_ENTRY CurrentItem;
2538 DWORD NumEvents;
2539 ConsoleInput *Input;
2540
2541 DPRINT("CsrGetNumberOfConsoleInputEvents\n");
2542
2543 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2544 Reply->Header.DataSize = Reply->Header.MessageSize - LPC_MESSAGE_BASE_SIZE;
2545
2546 Status = ConioLockConsole(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, &Console);
2547 if (! NT_SUCCESS(Status))
2548 {
2549 return Reply->Status = Status;
2550 }
2551
2552 CurrentItem = Console->InputEvents.Flink;
2553 NumEvents = 0;
2554
2555 /* If there are any events ... */
2556 while (CurrentItem != &Console->InputEvents)
2557 {
2558 Input = CONTAINING_RECORD(CurrentItem, ConsoleInput, ListEntry);
2559 CurrentItem = CurrentItem->Flink;
2560 if (!Input->Fake)
2561 {
2562 NumEvents++;
2563 }
2564 }
2565
2566 ConioUnlockConsole(Console);
2567
2568 Reply->Status = STATUS_SUCCESS;
2569 Reply->Data.GetNumInputEventsReply.NumInputEvents = NumEvents;
2570
2571 return Reply->Status;
2572 }
2573
2574
2575 CSR_API(CsrPeekConsoleInput)
2576 {
2577 NTSTATUS Status;
2578 PCSRSS_CONSOLE Console;
2579 DWORD Size;
2580 DWORD Length;
2581 PLIST_ENTRY CurrentItem;
2582 PINPUT_RECORD InputRecord;
2583 ConsoleInput* Item;
2584 UINT NumItems;
2585
2586 DPRINT("CsrPeekConsoleInput\n");
2587
2588 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2589 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
2590
2591 Status = ConioLockConsole(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, &Console);
2592 if(! NT_SUCCESS(Status))
2593 {
2594 return Reply->Status = Status;
2595 }
2596
2597 InputRecord = Request->Data.PeekConsoleInputRequest.InputRecord;
2598 Length = Request->Data.PeekConsoleInputRequest.Length;
2599 Size = Length * sizeof(INPUT_RECORD);
2600
2601 if (((PVOID)InputRecord < ProcessData->CsrSectionViewBase)
2602 || (((PVOID)InputRecord + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2603 {
2604 ConioUnlockConsole(Console);
2605 Reply->Status = STATUS_ACCESS_VIOLATION;
2606 return Reply->Status ;
2607 }
2608
2609 NumItems = 0;
2610
2611 if (! IsListEmpty(&Console->InputEvents))
2612 {
2613 CurrentItem = Console->InputEvents.Flink;
2614
2615 while (CurrentItem != &Console->InputEvents && NumItems < Length)
2616 {
2617 Item = CONTAINING_RECORD(CurrentItem, ConsoleInput, ListEntry);
2618
2619 if (Item->Fake)
2620 {
2621 CurrentItem = CurrentItem->Flink;
2622 continue;
2623 }
2624
2625 ++NumItems;
2626 *InputRecord = Item->InputEvent;
2627
2628 if (Request->Data.ReadInputRequest.Unicode == FALSE)
2629 {
2630 ConioInputEventToAnsi(Console, InputRecord);
2631 }
2632
2633 InputRecord++;
2634 CurrentItem = CurrentItem->Flink;
2635 }
2636 }
2637
2638 ConioUnlockConsole(Console);
2639
2640 Reply->Status = STATUS_SUCCESS;
2641 Reply->Data.PeekConsoleInputReply.Length = NumItems;
2642
2643 return Reply->Status;
2644 }
2645
2646
2647 CSR_API(CsrReadConsoleOutput)
2648 {
2649 PCHAR_INFO CharInfo;
2650 PCHAR_INFO CurCharInfo;
2651 PCSRSS_SCREEN_BUFFER Buff;
2652 DWORD Size;
2653 DWORD Length;
2654 DWORD SizeX, SizeY;
2655 NTSTATUS Status;
2656 COORD BufferSize;
2657 COORD BufferCoord;
2658 RECT ReadRegion;
2659 RECT ScreenRect;
2660 DWORD i, Y, X, Offset;
2661 UINT CodePage;
2662
2663 DPRINT("CsrReadConsoleOutput\n");
2664
2665 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2666 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
2667
2668 Status = ConioLockScreenBuffer(ProcessData, Request->Data.ReadConsoleOutputRequest.ConsoleHandle, &Buff);
2669 if (! NT_SUCCESS(Status))
2670 {
2671 return Reply->Status = Status;
2672 }
2673
2674 CharInfo = Request->Data.ReadConsoleOutputRequest.CharInfo;
2675 ReadRegion.left = Request->Data.ReadConsoleOutputRequest.ReadRegion.Left;
2676 ReadRegion.top = Request->Data.ReadConsoleOutputRequest.ReadRegion.Top;
2677 ReadRegion.right = Request->Data.ReadConsoleOutputRequest.ReadRegion.Right;
2678 ReadRegion.bottom = Request->Data.ReadConsoleOutputRequest.ReadRegion.Bottom;
2679 BufferSize = Request->Data.ReadConsoleOutputRequest.BufferSize;
2680 BufferCoord = Request->Data.ReadConsoleOutputRequest.BufferCoord;
2681 Length = BufferSize.X * BufferSize.Y;
2682 Size = Length * sizeof(CHAR_INFO);
2683
2684 /* FIXME: Is this correct? */
2685 CodePage = ProcessData->Console->OutputCodePage;
2686
2687 if (((PVOID)CharInfo < ProcessData->CsrSectionViewBase)
2688 || (((PVOID)CharInfo + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2689 {
2690 ConioUnlockScreenBuffer(Buff);
2691 Reply->Status = STATUS_ACCESS_VIOLATION;
2692 return Reply->Status ;
2693 }
2694
2695 SizeY = RtlRosMin(BufferSize.Y - BufferCoord.Y, ConioRectHeight(&ReadRegion));
2696 SizeX = RtlRosMin(BufferSize.X - BufferCoord.X, ConioRectWidth(&ReadRegion));
2697 ReadRegion.bottom = ReadRegion.top + SizeY;
2698 ReadRegion.right = ReadRegion.left + SizeX;
2699
2700 ConioInitRect(&ScreenRect, 0, 0, Buff->MaxY, Buff->MaxX);
2701 if (! ConioGetIntersection(&ReadRegion, &ScreenRect, &ReadRegion))
2702 {
2703 ConioUnlockScreenBuffer(Buff);
2704 Reply->Status = STATUS_SUCCESS;
2705 return Reply->Status;
2706 }
2707
2708 for (i = 0, Y = ReadRegion.top; Y < ReadRegion.bottom; ++i, ++Y)
2709 {
2710 CurCharInfo = CharInfo + (i * BufferSize.X);
2711
2712 Offset = (((Y + Buff->ShowY) % Buff->MaxY) * Buff->MaxX + ReadRegion.left) * 2;
2713 for (X = ReadRegion.left; X < ReadRegion.right; ++X)
2714 {
2715 if (Request->Data.ReadConsoleOutputRequest.Unicode)
2716 {
2717 MultiByteToWideChar(CodePage, 0,
2718 &GET_CELL_BUFFER(Buff, Offset), 1,
2719 &CurCharInfo->Char.UnicodeChar, 1);
2720 }
2721 else
2722 {
2723 CurCharInfo->Char.AsciiChar = GET_CELL_BUFFER(Buff, Offset);
2724 }
2725 CurCharInfo->Attributes = GET_CELL_BUFFER(Buff, Offset);
2726 ++CurCharInfo;
2727 }
2728 }
2729
2730 ConioUnlockScreenBuffer(Buff);
2731
2732 Reply->Status = STATUS_SUCCESS;
2733 Reply->Data.ReadConsoleOutputReply.ReadRegion.Right = ReadRegion.left + SizeX - 1;
2734 Reply->Data.ReadConsoleOutputReply.ReadRegion.Bottom = ReadRegion.top + SizeY - 1;
2735 Reply->Data.ReadConsoleOutputReply.ReadRegion.Left = ReadRegion.left;
2736 Reply->Data.ReadConsoleOutputReply.ReadRegion.Top = ReadRegion.top;
2737
2738 return Reply->Status;
2739 }
2740
2741
2742 CSR_API(CsrWriteConsoleInput)
2743 {
2744 PINPUT_RECORD InputRecord;
2745 PCSRSS_CONSOLE Console;
2746 NTSTATUS Status;
2747 DWORD Length;
2748 DWORD Size;
2749 DWORD i;
2750 ConsoleInput* Record;
2751
2752 DPRINT("CsrWriteConsoleInput\n");
2753
2754 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2755 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
2756
2757 Status = ConioLockConsole(ProcessData, Request->Data.WriteConsoleInputRequest.ConsoleHandle, &Console);
2758 if (! NT_SUCCESS(Status))
2759 {
2760 return Reply->Status = Status;
2761 }
2762
2763 InputRecord = Request->Data.WriteConsoleInputRequest.InputRecord;
2764 Length = Request->Data.WriteConsoleInputRequest.Length;
2765 Size = Length * sizeof(INPUT_RECORD);
2766
2767 if (((PVOID)InputRecord < ProcessData->CsrSectionViewBase)
2768 || (((PVOID)InputRecord + Size) > (ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2769 {
2770 ConioUnlockConsole(Console);
2771 Reply->Status = STATUS_ACCESS_VIOLATION;
2772 return Reply->Status ;
2773 }
2774
2775 for (i = 0; i < Length; i++)
2776 {
2777 Record = HeapAlloc(Win32CsrApiHeap, 0, sizeof(ConsoleInput));
2778 if (NULL == Record)
2779 {
2780 ConioUnlockConsole(Console);
2781 Reply->Status = STATUS_INSUFFICIENT_RESOURCES;
2782 return Reply->Status;
2783 }
2784
2785 Record->Echoed = FALSE;
2786 Record->Fake = FALSE;
2787 Record->InputEvent = *InputRecord++;
2788 if (KEY_EVENT == Record->InputEvent.EventType)
2789 {
2790 ConioProcessChar(Console, Record);
2791 }
2792 }
2793
2794 ConioUnlockConsole(Console);
2795
2796 Reply->Status = STATUS_SUCCESS;
2797 Reply->Data.WriteConsoleInputReply.Length = i;
2798
2799 return Reply->Status;
2800 }
2801
2802 /**********************************************************************
2803 * HardwareStateProperty
2804 *
2805 * DESCRIPTION
2806 * Set/Get the value of the HardwareState and switch
2807 * between direct video buffer ouput and GDI windowed
2808 * output.
2809 * ARGUMENTS
2810 * Client hands us a CSRSS_CONSOLE_HARDWARE_STATE
2811 * object. We use the same object to reply.
2812 * NOTE
2813 * ConsoleHwState has the correct size to be compatible
2814 * with NT's, but values are not.
2815 */
2816 STATIC NTSTATUS FASTCALL
2817 SetConsoleHardwareState (PCSRSS_CONSOLE Console, DWORD ConsoleHwState)
2818 {
2819 DPRINT1("Console Hardware State: %d\n", ConsoleHwState);
2820
2821 if ((CONSOLE_HARDWARE_STATE_GDI_MANAGED == ConsoleHwState)
2822 ||(CONSOLE_HARDWARE_STATE_DIRECT == ConsoleHwState))
2823 {
2824 if (Console->HardwareState != ConsoleHwState)
2825 {
2826 /* TODO: implement switching from full screen to windowed mode */
2827 /* TODO: or back; now simply store the hardware state */
2828 Console->HardwareState = ConsoleHwState;
2829 }
2830
2831 return STATUS_SUCCESS;
2832 }
2833
2834 return STATUS_INVALID_PARAMETER_3; /* Client: (handle, set_get, [mode]) */
2835 }
2836
2837 CSR_API(CsrHardwareStateProperty)
2838 {
2839 PCSRSS_CONSOLE Console;
2840 NTSTATUS Status;
2841
2842 DPRINT("CsrHardwareStateProperty\n");
2843
2844 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2845 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
2846
2847 Status = ConioLockConsole(ProcessData,
2848 Request->Data.ConsoleHardwareStateRequest.ConsoleHandle,
2849 &Console);
2850 if (! NT_SUCCESS(Status))
2851 {
2852 DPRINT1("Failed to get console handle in SetConsoleHardwareState\n");
2853 return Reply->Status = Status;
2854 }
2855
2856 switch (Request->Data.ConsoleHardwareStateRequest.SetGet)
2857 {
2858 case CONSOLE_HARDWARE_STATE_GET:
2859 Reply->Data.ConsoleHardwareStateReply.State = Console->HardwareState;
2860 break;
2861
2862 case CONSOLE_HARDWARE_STATE_SET:
2863 DPRINT("Setting console hardware state.\n");
2864 Reply->Status = SetConsoleHardwareState(Console, Request->Data.ConsoleHardwareStateRequest.State);
2865 break;
2866
2867 default:
2868 Reply->Status = STATUS_INVALID_PARAMETER_2; /* Client: (handle, [set_get], mode) */
2869 break;
2870 }
2871
2872 ConioUnlockConsole(Console);
2873
2874 return Reply->Status;
2875 }
2876
2877 CSR_API(CsrGetConsoleWindow)
2878 {
2879 PCSRSS_CONSOLE Console;
2880 NTSTATUS Status;
2881
2882 DPRINT("CsrGetConsoleWindow\n");
2883
2884 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2885 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
2886
2887 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2888 if (! NT_SUCCESS(Status))
2889 {
2890 return Reply->Status = Status;
2891 }
2892
2893 Reply->Data.GetConsoleWindowReply.WindowHandle = Console->hWindow;
2894 ConioUnlockConsole(Console);
2895
2896 return Reply->Status = STATUS_SUCCESS;
2897 }
2898
2899 CSR_API(CsrSetConsoleIcon)
2900 {
2901 PCSRSS_CONSOLE Console;
2902 NTSTATUS Status;
2903
2904 DPRINT("CsrSetConsoleIcon\n");
2905
2906 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2907 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
2908
2909 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2910 if (! NT_SUCCESS(Status))
2911 {
2912 return Reply->Status = Status;
2913 }
2914
2915 Console->hWindowIcon = Request->Data.SetConsoleIconRequest.WindowIcon;
2916 Reply->Status = (ConioChangeIcon(Console) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
2917 ConioUnlockConsole(Console);
2918
2919 return Reply->Status;
2920 }
2921
2922 CSR_API(CsrGetConsoleCodePage)
2923 {
2924 PCSRSS_CONSOLE Console;
2925 NTSTATUS Status;
2926
2927 DPRINT("CsrGetConsoleCodePage\n");
2928
2929 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2930 if (! NT_SUCCESS(Status))
2931 {
2932 return Reply->Status = Status;
2933 }
2934
2935 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2936 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
2937 Reply->Data.GetConsoleCodePage.CodePage = Console->CodePage;
2938 ConioUnlockConsole(Console);
2939 return Reply->Status = STATUS_SUCCESS;
2940 }
2941
2942 CSR_API(CsrSetConsoleCodePage)
2943 {
2944 PCSRSS_CONSOLE Console;
2945 NTSTATUS Status;
2946
2947 DPRINT("CsrSetConsoleCodePage\n");
2948
2949 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2950 if (! NT_SUCCESS(Status))
2951 {
2952 return Reply->Status = Status;
2953 }
2954
2955 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2956 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
2957 if (IsValidCodePage(Request->Data.SetConsoleCodePage.CodePage))
2958 {
2959 Console->CodePage = Request->Data.SetConsoleCodePage.CodePage;
2960 ConioUnlockConsole(Console);
2961 return Reply->Status = STATUS_SUCCESS;
2962 }
2963 ConioUnlockConsole(Console);
2964 return Reply->Status = STATUS_UNSUCCESSFUL;
2965 }
2966
2967 CSR_API(CsrGetConsoleOutputCodePage)
2968 {
2969 PCSRSS_CONSOLE Console;
2970 NTSTATUS Status;
2971
2972 DPRINT("CsrGetConsoleOutputCodePage\n");
2973
2974 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2975 if (! NT_SUCCESS(Status))
2976 {
2977 return Reply->Status = Status;
2978 }
2979
2980 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
2981 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
2982 Reply->Data.GetConsoleOutputCodePage.CodePage = Console->OutputCodePage;
2983 ConioUnlockConsole(Console);
2984 return Reply->Status = STATUS_SUCCESS;
2985 }
2986
2987 CSR_API(CsrSetConsoleOutputCodePage)
2988 {
2989 PCSRSS_CONSOLE Console;
2990 NTSTATUS Status;
2991
2992 DPRINT("CsrSetConsoleOutputCodePage\n");
2993
2994 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2995 if (! NT_SUCCESS(Status))
2996 {
2997 return Reply->Status = Status;
2998 }
2999
3000 Reply->Header.MessageSize = sizeof(CSRSS_API_REPLY);
3001 Reply->Header.DataSize = sizeof(CSRSS_API_REPLY) - LPC_MESSAGE_BASE_SIZE;
3002 if (IsValidCodePage(Request->Data.SetConsoleOutputCodePage.CodePage))
3003 {
3004 Console->OutputCodePage = Request->Data.SetConsoleOutputCodePage.CodePage;
3005 ConioUnlockConsole(Console);
3006 return Reply->Status = STATUS_SUCCESS;
3007 }
3008 ConioUnlockConsole(Console);
3009 return Reply->Status = STATUS_UNSUCCESSFUL;
3010 }
3011
3012 /* EOF */