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