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