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