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