[FORMATTING] Standardize win32csr to 4-space indents. Based on a patch by Adam Kachwa...
[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 {
609 /* otherwise, return STATUS_NOTIFY_CLEANUP to tell client to back up its buffer */
610 Console->WaitingChars--;
611 ConioUnlockConsole(Console);
612 HeapFree(Win32CsrApiHeap, 0, Input);
613 Request->Data.ReadConsoleRequest.NrCharactersRead = 0;
614 return STATUS_NOTIFY_CLEANUP;
615
616 }
617 Request->Data.ReadConsoleRequest.nCharsCanBeDeleted--;
618 Input->Echoed = TRUE; /* mark as echoed so we don't echo it below */
619 }
620 /* do not copy backspace to buffer */
621 else
622 {
623 if(Request->Data.ReadConsoleRequest.Unicode)
624 ConsoleInputAnsiCharToUnicodeChar(Console, &UnicodeBuffer[i], &Input->InputEvent.Event.KeyEvent.uChar.AsciiChar);
625 else
626 Buffer[i] = Input->InputEvent.Event.KeyEvent.uChar.AsciiChar;
627 }
628 /* echo to screen if enabled and we did not already echo the char */
629 if (0 != (Console->Mode & ENABLE_ECHO_INPUT)
630 && ! Input->Echoed
631 && '\r' != Input->InputEvent.Event.KeyEvent.uChar.AsciiChar)
632 {
633 ConioWriteConsole(Console, Console->ActiveBuffer,
634 &Input->InputEvent.Event.KeyEvent.uChar.AsciiChar, 1, TRUE);
635 }
636 }
637 else
638 {
639 i--;
640 }
641 Console->WaitingChars--;
642 HeapFree(Win32CsrApiHeap, 0, Input);
643 }
644 Request->Data.ReadConsoleRequest.NrCharactersRead = i;
645 if (0 == i)
646 {
647 Status = STATUS_PENDING; /* we didn't read anything */
648 }
649 else if (0 != (Console->Mode & ENABLE_LINE_INPUT))
650 {
651 if (0 == Console->WaitingLines ||
652 (Request->Data.ReadConsoleRequest.Unicode ? (L'\n' != UnicodeBuffer[i - 1]) : ('\n' != Buffer[i - 1])))
653 {
654 Status = STATUS_PENDING; /* line buffered, didn't get a complete line */
655 }
656 else
657 {
658 Console->WaitingLines--;
659 Status = STATUS_SUCCESS; /* line buffered, did get a complete line */
660 }
661 }
662 else
663 {
664 Status = STATUS_SUCCESS; /* not line buffered, did read something */
665 }
666
667 if (Status == STATUS_PENDING)
668 {
669 Console->EchoCount = nNumberOfCharsToRead - i;
670 }
671 else
672 {
673 Console->EchoCount = 0; /* if the client is no longer waiting on input, do not echo */
674 }
675
676 ConioUnlockConsole(Console);
677
678 if (CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE) + i * CharSize > sizeof(CSR_API_MESSAGE))
679 {
680 Request->Header.u1.s1.TotalLength = CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE) + i * CharSize;
681 Request->Header.u1.s1.DataLength = Request->Header.u1.s1.TotalLength - sizeof(PORT_MESSAGE);
682 }
683
684 return Status;
685 }
686
687 __inline BOOLEAN ConioGetIntersection(
688 SMALL_RECT *Intersection,
689 SMALL_RECT *Rect1,
690 SMALL_RECT *Rect2)
691 {
692 if (ConioIsRectEmpty(Rect1) ||
693 (ConioIsRectEmpty(Rect2)) ||
694 (Rect1->Top > Rect2->Bottom) ||
695 (Rect1->Left > Rect2->Right) ||
696 (Rect1->Bottom < Rect2->Top) ||
697 (Rect1->Right < Rect2->Left))
698 {
699 /* The rectangles do not intersect */
700 ConioInitRect(Intersection, 0, -1, 0, -1);
701 return FALSE;
702 }
703
704 ConioInitRect(Intersection,
705 max(Rect1->Top, Rect2->Top),
706 max(Rect1->Left, Rect2->Left),
707 min(Rect1->Bottom, Rect2->Bottom),
708 min(Rect1->Right, Rect2->Right));
709
710 return TRUE;
711 }
712
713 __inline BOOLEAN ConioGetUnion(
714 SMALL_RECT *Union,
715 SMALL_RECT *Rect1,
716 SMALL_RECT *Rect2)
717 {
718 if (ConioIsRectEmpty(Rect1))
719 {
720 if (ConioIsRectEmpty(Rect2))
721 {
722 ConioInitRect(Union, 0, -1, 0, -1);
723 return FALSE;
724 }
725 else
726 {
727 *Union = *Rect2;
728 }
729 }
730 else if (ConioIsRectEmpty(Rect2))
731 {
732 *Union = *Rect1;
733 }
734 else
735 {
736 ConioInitRect(Union,
737 min(Rect1->Top, Rect2->Top),
738 min(Rect1->Left, Rect2->Left),
739 max(Rect1->Bottom, Rect2->Bottom),
740 max(Rect1->Right, Rect2->Right));
741 }
742
743 return TRUE;
744 }
745
746 /* Move from one rectangle to another. We must be careful about the order that
747 * this is done, to avoid overwriting parts of the source before they are moved. */
748 static VOID FASTCALL
749 ConioMoveRegion(PCSRSS_SCREEN_BUFFER ScreenBuffer,
750 SMALL_RECT *SrcRegion,
751 SMALL_RECT *DstRegion,
752 SMALL_RECT *ClipRegion,
753 WORD Fill)
754 {
755 int Width = ConioRectWidth(SrcRegion);
756 int Height = ConioRectHeight(SrcRegion);
757 int SX, SY;
758 int DX, DY;
759 int XDelta, YDelta;
760 int i, j;
761
762 SY = SrcRegion->Top;
763 DY = DstRegion->Top;
764 YDelta = 1;
765 if (SY < DY)
766 {
767 /* Moving down: work from bottom up */
768 SY = SrcRegion->Bottom;
769 DY = DstRegion->Bottom;
770 YDelta = -1;
771 }
772 for (i = 0; i < Height; i++)
773 {
774 PWORD SRow = (PWORD)ConioCoordToPointer(ScreenBuffer, 0, SY);
775 PWORD DRow = (PWORD)ConioCoordToPointer(ScreenBuffer, 0, DY);
776
777 SX = SrcRegion->Left;
778 DX = DstRegion->Left;
779 XDelta = 1;
780 if (SX < DX)
781 {
782 /* Moving right: work from right to left */
783 SX = SrcRegion->Right;
784 DX = DstRegion->Right;
785 XDelta = -1;
786 }
787 for (j = 0; j < Width; j++)
788 {
789 WORD Cell = SRow[SX];
790 if (SX >= ClipRegion->Left && SX <= ClipRegion->Right
791 && SY >= ClipRegion->Top && SY <= ClipRegion->Bottom)
792 {
793 SRow[SX] = Fill;
794 }
795 if (DX >= ClipRegion->Left && DX <= ClipRegion->Right
796 && DY >= ClipRegion->Top && DY <= ClipRegion->Bottom)
797 {
798 DRow[DX] = Cell;
799 }
800 SX += XDelta;
801 DX += XDelta;
802 }
803 SY += YDelta;
804 DY += YDelta;
805 }
806 }
807
808 static VOID FASTCALL
809 ConioInputEventToAnsi(PCSRSS_CONSOLE Console, PINPUT_RECORD InputEvent)
810 {
811 if (InputEvent->EventType == KEY_EVENT)
812 {
813 WCHAR UnicodeChar = InputEvent->Event.KeyEvent.uChar.UnicodeChar;
814 InputEvent->Event.KeyEvent.uChar.UnicodeChar = 0;
815 ConsoleInputUnicodeCharToAnsiChar(Console,
816 &InputEvent->Event.KeyEvent.uChar.AsciiChar,
817 &UnicodeChar);
818 }
819 }
820
821 CSR_API(CsrWriteConsole)
822 {
823 NTSTATUS Status;
824 PCHAR Buffer;
825 PCSRSS_SCREEN_BUFFER Buff;
826 PCSRSS_CONSOLE Console;
827 DWORD Written = 0;
828 ULONG Length;
829 ULONG CharSize = (Request->Data.WriteConsoleRequest.Unicode ? sizeof(WCHAR) : sizeof(CHAR));
830
831 DPRINT("CsrWriteConsole\n");
832
833 if (Request->Header.u1.s1.TotalLength
834 < CSR_API_MESSAGE_HEADER_SIZE(CSRSS_WRITE_CONSOLE)
835 + (Request->Data.WriteConsoleRequest.NrCharactersToWrite * CharSize))
836 {
837 DPRINT1("Invalid request size\n");
838 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
839 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
840 return STATUS_INVALID_PARAMETER;
841 }
842
843 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
844 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
845
846 Status = ConioLockScreenBuffer(ProcessData, Request->Data.WriteConsoleRequest.ConsoleHandle, &Buff, GENERIC_WRITE);
847 if (! NT_SUCCESS(Status))
848 {
849 return Status;
850 }
851 Console = Buff->Header.Console;
852
853 if (Console->UnpauseEvent)
854 {
855 Status = NtDuplicateObject(GetCurrentProcess(), Console->UnpauseEvent,
856 ProcessData->Process, &Request->Data.WriteConsoleRequest.UnpauseEvent,
857 SYNCHRONIZE, 0, 0);
858 ConioUnlockScreenBuffer(Buff);
859 return NT_SUCCESS(Status) ? STATUS_PENDING : Status;
860 }
861
862 if(Request->Data.WriteConsoleRequest.Unicode)
863 {
864 Length = WideCharToMultiByte(Console->OutputCodePage, 0,
865 (PWCHAR)Request->Data.WriteConsoleRequest.Buffer,
866 Request->Data.WriteConsoleRequest.NrCharactersToWrite,
867 NULL, 0, NULL, NULL);
868 Buffer = RtlAllocateHeap(GetProcessHeap(), 0, Length);
869 if (Buffer)
870 {
871 WideCharToMultiByte(Console->OutputCodePage, 0,
872 (PWCHAR)Request->Data.WriteConsoleRequest.Buffer,
873 Request->Data.WriteConsoleRequest.NrCharactersToWrite,
874 Buffer, Length, NULL, NULL);
875 }
876 else
877 {
878 Status = STATUS_NO_MEMORY;
879 }
880 }
881 else
882 {
883 Buffer = (PCHAR)Request->Data.WriteConsoleRequest.Buffer;
884 }
885
886 if (Buffer)
887 {
888 if (NT_SUCCESS(Status))
889 {
890 Status = ConioWriteConsole(Console, Buff, Buffer,
891 Request->Data.WriteConsoleRequest.NrCharactersToWrite, TRUE);
892 if (NT_SUCCESS(Status))
893 {
894 Written = Request->Data.WriteConsoleRequest.NrCharactersToWrite;
895 }
896 }
897 if (Request->Data.WriteConsoleRequest.Unicode)
898 {
899 RtlFreeHeap(GetProcessHeap(), 0, Buffer);
900 }
901 }
902 ConioUnlockScreenBuffer(Buff);
903
904 Request->Data.WriteConsoleRequest.NrCharactersWritten = Written;
905
906 return Status;
907 }
908
909 VOID WINAPI
910 ConioDeleteScreenBuffer(PCSRSS_SCREEN_BUFFER Buffer)
911 {
912 PCSRSS_CONSOLE Console = Buffer->Header.Console;
913
914 RemoveEntryList(&Buffer->ListEntry);
915 if (Buffer == Console->ActiveBuffer)
916 {
917 /* Deleted active buffer; switch to most recently created */
918 Console->ActiveBuffer = NULL;
919 if (!IsListEmpty(&Console->BufferList))
920 {
921 Console->ActiveBuffer = CONTAINING_RECORD(Console->BufferList.Flink, CSRSS_SCREEN_BUFFER, ListEntry);
922 ConioDrawConsole(Console);
923 }
924 }
925
926 HeapFree(Win32CsrApiHeap, 0, Buffer->Buffer);
927 HeapFree(Win32CsrApiHeap, 0, Buffer);
928 }
929
930 VOID FASTCALL
931 ConioDrawConsole(PCSRSS_CONSOLE Console)
932 {
933 SMALL_RECT Region;
934
935 ConioInitRect(&Region, 0, 0, Console->Size.Y - 1, Console->Size.X - 1);
936
937 ConioDrawRegion(Console, &Region);
938 }
939
940
941 VOID WINAPI
942 ConioDeleteConsole(Object_t *Object)
943 {
944 PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) Object;
945 ConsoleInput *Event;
946
947 DPRINT("ConioDeleteConsole\n");
948
949 /* Drain input event queue */
950 while (Console->InputEvents.Flink != &Console->InputEvents)
951 {
952 Event = (ConsoleInput *) Console->InputEvents.Flink;
953 Console->InputEvents.Flink = Console->InputEvents.Flink->Flink;
954 Console->InputEvents.Flink->Flink->Blink = &Console->InputEvents;
955 HeapFree(Win32CsrApiHeap, 0, Event);
956 }
957
958 ConioCleanupConsole(Console);
959 ConioDeleteScreenBuffer(Console->ActiveBuffer);
960 if (!IsListEmpty(&Console->BufferList))
961 {
962 DPRINT1("BUG: screen buffer list not empty\n");
963 }
964
965 CloseHandle(Console->ActiveEvent);
966 if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent);
967 DeleteCriticalSection(&Console->Lock);
968 RtlFreeUnicodeString(&Console->Title);
969 IntDeleteAllAliases(Console->Aliases);
970 HeapFree(Win32CsrApiHeap, 0, Console);
971 }
972
973 VOID WINAPI
974 CsrInitConsoleSupport(VOID)
975 {
976 DPRINT("CSR: CsrInitConsoleSupport()\n");
977
978 /* Should call LoadKeyboardLayout */
979 }
980
981 VOID FASTCALL
982 ConioPause(PCSRSS_CONSOLE Console, UINT Flags)
983 {
984 Console->PauseFlags |= Flags;
985 if (!Console->UnpauseEvent)
986 Console->UnpauseEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
987 }
988
989 VOID FASTCALL
990 ConioUnpause(PCSRSS_CONSOLE Console, UINT Flags)
991 {
992 Console->PauseFlags &= ~Flags;
993 if (Console->PauseFlags == 0 && Console->UnpauseEvent)
994 {
995 SetEvent(Console->UnpauseEvent);
996 CloseHandle(Console->UnpauseEvent);
997 Console->UnpauseEvent = NULL;
998 }
999 }
1000
1001 static VOID FASTCALL
1002 ConioProcessChar(PCSRSS_CONSOLE Console,
1003 ConsoleInput *KeyEventRecord)
1004 {
1005 BOOL updown;
1006 ConsoleInput *TempInput;
1007
1008 if (KeyEventRecord->InputEvent.EventType == KEY_EVENT &&
1009 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown)
1010 {
1011 WORD vk = KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode;
1012 if (!(Console->PauseFlags & PAUSED_FROM_KEYBOARD))
1013 {
1014 DWORD cks = KeyEventRecord->InputEvent.Event.KeyEvent.dwControlKeyState;
1015 if (Console->Mode & ENABLE_LINE_INPUT &&
1016 (vk == VK_PAUSE || (vk == 'S' &&
1017 (cks & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) &&
1018 !(cks & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)))))
1019 {
1020 ConioPause(Console, PAUSED_FROM_KEYBOARD);
1021 HeapFree(Win32CsrApiHeap, 0, KeyEventRecord);
1022 return;
1023 }
1024 }
1025 else
1026 {
1027 if ((vk < VK_SHIFT || vk > VK_CAPITAL) && vk != VK_LWIN &&
1028 vk != VK_RWIN && vk != VK_NUMLOCK && vk != VK_SCROLL)
1029 {
1030 ConioUnpause(Console, PAUSED_FROM_KEYBOARD);
1031 HeapFree(Win32CsrApiHeap, 0, KeyEventRecord);
1032 return;
1033 }
1034 }
1035 }
1036
1037 if (0 != (Console->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT)))
1038 {
1039 switch(KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar)
1040 {
1041 case '\r':
1042 /* first add the \r */
1043 KeyEventRecord->InputEvent.EventType = KEY_EVENT;
1044 updown = KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown;
1045 KeyEventRecord->Echoed = FALSE;
1046 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
1047 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\r';
1048 InsertTailList(&Console->InputEvents, &KeyEventRecord->ListEntry);
1049 Console->WaitingChars++;
1050 KeyEventRecord = HeapAlloc(Win32CsrApiHeap, 0, sizeof(ConsoleInput));
1051 if (NULL == KeyEventRecord)
1052 {
1053 DPRINT1("Failed to allocate KeyEventRecord\n");
1054 return;
1055 }
1056 KeyEventRecord->InputEvent.EventType = KEY_EVENT;
1057 KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown = updown;
1058 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualKeyCode = 0;
1059 KeyEventRecord->InputEvent.Event.KeyEvent.wVirtualScanCode = 0;
1060 KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar = '\n';
1061 KeyEventRecord->Fake = TRUE;
1062 break;
1063 }
1064 }
1065 /* add event to the queue */
1066 InsertTailList(&Console->InputEvents, &KeyEventRecord->ListEntry);
1067 Console->WaitingChars++;
1068 /* if line input mode is enabled, only wake the client on enter key down */
1069 if (0 == (Console->Mode & ENABLE_LINE_INPUT)
1070 || Console->EarlyReturn
1071 || ('\n' == KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar
1072 && KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown))
1073 {
1074 if ('\n' == KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar)
1075 {
1076 Console->WaitingLines++;
1077 }
1078 }
1079 KeyEventRecord->Echoed = FALSE;
1080 if (0 != (Console->Mode & (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT))
1081 && '\b' == KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar
1082 && KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown)
1083 {
1084 /* walk the input queue looking for a char to backspace */
1085 for (TempInput = (ConsoleInput *) Console->InputEvents.Blink;
1086 TempInput != (ConsoleInput *) &Console->InputEvents
1087 && (KEY_EVENT == TempInput->InputEvent.EventType
1088 || ! TempInput->InputEvent.Event.KeyEvent.bKeyDown
1089 || '\b' == TempInput->InputEvent.Event.KeyEvent.uChar.AsciiChar);
1090 TempInput = (ConsoleInput *) TempInput->ListEntry.Blink)
1091 {
1092 /* NOP */;
1093 }
1094 /* if we found one, delete it, otherwise, wake the client */
1095 if (TempInput != (ConsoleInput *) &Console->InputEvents)
1096 {
1097 /* delete previous key in queue, maybe echo backspace to screen, and do not place backspace on queue */
1098 RemoveEntryList(&TempInput->ListEntry);
1099 if (TempInput->Echoed)
1100 {
1101 ConioWriteConsole(Console, Console->ActiveBuffer,
1102 &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar,
1103 1, TRUE);
1104 }
1105 HeapFree(Win32CsrApiHeap, 0, TempInput);
1106 RemoveEntryList(&KeyEventRecord->ListEntry);
1107 HeapFree(Win32CsrApiHeap, 0, KeyEventRecord);
1108 Console->WaitingChars -= 2;
1109 return;
1110 }
1111 }
1112 else
1113 {
1114 /* echo chars if we are supposed to and client is waiting for some */
1115 if (0 != (Console->Mode & ENABLE_ECHO_INPUT) && Console->EchoCount
1116 && KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar
1117 && KeyEventRecord->InputEvent.Event.KeyEvent.bKeyDown
1118 && '\r' != KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar)
1119 {
1120 /* mark the char as already echoed */
1121 ConioWriteConsole(Console, Console->ActiveBuffer,
1122 &KeyEventRecord->InputEvent.Event.KeyEvent.uChar.AsciiChar,
1123 1, TRUE);
1124 Console->EchoCount--;
1125 KeyEventRecord->Echoed = TRUE;
1126 }
1127 }
1128
1129 /* Console->WaitingChars++; */
1130 SetEvent(Console->ActiveEvent);
1131 }
1132
1133 static DWORD FASTCALL
1134 ConioGetShiftState(PBYTE KeyState)
1135 {
1136 DWORD ssOut = 0;
1137
1138 if (KeyState[VK_CAPITAL] & 1)
1139 ssOut |= CAPSLOCK_ON;
1140
1141 if (KeyState[VK_NUMLOCK] & 1)
1142 ssOut |= NUMLOCK_ON;
1143
1144 if (KeyState[VK_SCROLL] & 1)
1145 ssOut |= SCROLLLOCK_ON;
1146
1147 if (KeyState[VK_SHIFT] & 0x80)
1148 ssOut |= SHIFT_PRESSED;
1149
1150 if (KeyState[VK_LCONTROL] & 0x80)
1151 ssOut |= LEFT_CTRL_PRESSED;
1152 if (KeyState[VK_RCONTROL] & 0x80)
1153 ssOut |= RIGHT_CTRL_PRESSED;
1154
1155 if (KeyState[VK_LMENU] & 0x80)
1156 ssOut |= LEFT_ALT_PRESSED;
1157 if (KeyState[VK_RMENU] & 0x80)
1158 ssOut |= RIGHT_ALT_PRESSED;
1159
1160 return ssOut;
1161 }
1162
1163 VOID WINAPI
1164 ConioProcessKey(MSG *msg, PCSRSS_CONSOLE Console, BOOL TextMode)
1165 {
1166 static BYTE KeyState[256] = { 0 };
1167 /* MSDN mentions that you should use the last virtual key code received
1168 * when putting a virtual key identity to a WM_CHAR message since multiple
1169 * or translated keys may be involved. */
1170 static UINT LastVirtualKey = 0;
1171 DWORD ShiftState;
1172 ConsoleInput *ConInRec;
1173 UINT RepeatCount;
1174 CHAR AsciiChar;
1175 WCHAR UnicodeChar;
1176 UINT VirtualKeyCode;
1177 UINT VirtualScanCode;
1178 BOOL Down = FALSE;
1179 INPUT_RECORD er;
1180 ULONG ResultSize = 0;
1181
1182 RepeatCount = 1;
1183 VirtualScanCode = (msg->lParam >> 16) & 0xff;
1184 Down = msg->message == WM_KEYDOWN || msg->message == WM_CHAR ||
1185 msg->message == WM_SYSKEYDOWN || msg->message == WM_SYSCHAR;
1186
1187 GetKeyboardState(KeyState);
1188 ShiftState = ConioGetShiftState(KeyState);
1189
1190 if (msg->message == WM_CHAR || msg->message == WM_SYSCHAR)
1191 {
1192 VirtualKeyCode = LastVirtualKey;
1193 UnicodeChar = msg->wParam;
1194 }
1195 else
1196 {
1197 WCHAR Chars[2];
1198 INT RetChars = 0;
1199
1200 VirtualKeyCode = msg->wParam;
1201 RetChars = ToUnicodeEx(VirtualKeyCode,
1202 VirtualScanCode,
1203 KeyState,
1204 Chars,
1205 2,
1206 0,
1207 0);
1208 UnicodeChar = (1 == RetChars ? Chars[0] : 0);
1209 }
1210
1211 if (0 == ResultSize)
1212 {
1213 AsciiChar = 0;
1214 }
1215
1216 er.EventType = KEY_EVENT;
1217 er.Event.KeyEvent.bKeyDown = Down;
1218 er.Event.KeyEvent.wRepeatCount = RepeatCount;
1219 er.Event.KeyEvent.uChar.UnicodeChar = UnicodeChar;
1220 er.Event.KeyEvent.dwControlKeyState = ShiftState;
1221 er.Event.KeyEvent.wVirtualKeyCode = VirtualKeyCode;
1222 er.Event.KeyEvent.wVirtualScanCode = VirtualScanCode;
1223
1224 if (TextMode)
1225 {
1226 if (0 != (ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
1227 && VK_TAB == VirtualKeyCode)
1228 {
1229 if (Down)
1230 {
1231 TuiSwapConsole(ShiftState & SHIFT_PRESSED ? -1 : 1);
1232 }
1233
1234 return;
1235 }
1236 else if (VK_MENU == VirtualKeyCode && ! Down)
1237 {
1238 if (TuiSwapConsole(0))
1239 {
1240 return;
1241 }
1242 }
1243 }
1244
1245 if (NULL == Console)
1246 {
1247 DPRINT1("No Active Console!\n");
1248 return;
1249 }
1250
1251 ConInRec = HeapAlloc(Win32CsrApiHeap, 0, sizeof(ConsoleInput));
1252
1253 if (NULL == ConInRec)
1254 {
1255 return;
1256 }
1257
1258 ConInRec->InputEvent = er;
1259 ConInRec->Fake = UnicodeChar &&
1260 (msg->message != WM_CHAR && msg->message != WM_SYSCHAR &&
1261 msg->message != WM_KEYUP && msg->message != WM_SYSKEYUP);
1262 ConInRec->NotChar = (msg->message != WM_CHAR && msg->message != WM_SYSCHAR);
1263 ConInRec->Echoed = FALSE;
1264 if (ConInRec->NotChar)
1265 LastVirtualKey = msg->wParam;
1266
1267 DPRINT ("csrss: %s %s %s %s %02x %02x '%c' %04x\n",
1268 Down ? "down" : "up ",
1269 (msg->message == WM_CHAR || msg->message == WM_SYSCHAR) ?
1270 "char" : "key ",
1271 ConInRec->Fake ? "fake" : "real",
1272 ConInRec->NotChar ? "notc" : "char",
1273 VirtualScanCode,
1274 VirtualKeyCode,
1275 (AsciiChar >= ' ') ? AsciiChar : '.',
1276 ShiftState);
1277
1278 if (ConInRec->Fake && ConInRec->NotChar)
1279 {
1280 HeapFree(Win32CsrApiHeap, 0, ConInRec);
1281 return;
1282 }
1283
1284 /* process Ctrl-C and Ctrl-Break */
1285 if (Console->Mode & ENABLE_PROCESSED_INPUT &&
1286 er.Event.KeyEvent.bKeyDown &&
1287 ((er.Event.KeyEvent.wVirtualKeyCode == VK_PAUSE) ||
1288 (er.Event.KeyEvent.wVirtualKeyCode == 'C')) &&
1289 (er.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)))
1290 {
1291 PCSRSS_PROCESS_DATA current;
1292 PLIST_ENTRY current_entry;
1293 DPRINT1("Console_Api Ctrl-C\n");
1294 current_entry = Console->ProcessList.Flink;
1295 while (current_entry != &Console->ProcessList)
1296 {
1297 current = CONTAINING_RECORD(current_entry, CSRSS_PROCESS_DATA, ProcessEntry);
1298 current_entry = current_entry->Flink;
1299 ConioConsoleCtrlEvent((DWORD)CTRL_C_EVENT, current);
1300 }
1301 HeapFree(Win32CsrApiHeap, 0, ConInRec);
1302 return;
1303 }
1304
1305 if (0 != (er.Event.KeyEvent.dwControlKeyState
1306 & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
1307 && (VK_UP == er.Event.KeyEvent.wVirtualKeyCode
1308 || VK_DOWN == er.Event.KeyEvent.wVirtualKeyCode))
1309 {
1310 if (er.Event.KeyEvent.bKeyDown)
1311 {
1312 /* scroll up or down */
1313 if (VK_UP == er.Event.KeyEvent.wVirtualKeyCode)
1314 {
1315 /* only scroll up if there is room to scroll up into */
1316 if (Console->ActiveBuffer->CurrentY != Console->ActiveBuffer->MaxY - 1)
1317 {
1318 Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY +
1319 Console->ActiveBuffer->MaxY - 1) %
1320 Console->ActiveBuffer->MaxY;
1321 Console->ActiveBuffer->CurrentY++;
1322 }
1323 }
1324 else
1325 {
1326 /* only scroll down if there is room to scroll down into */
1327 if (Console->ActiveBuffer->CurrentY != 0)
1328 {
1329 Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY + 1) %
1330 Console->ActiveBuffer->MaxY;
1331 Console->ActiveBuffer->CurrentY--;
1332 }
1333 }
1334 ConioDrawConsole(Console);
1335 }
1336 HeapFree(Win32CsrApiHeap, 0, ConInRec);
1337 return;
1338 }
1339 /* FIXME - convert to ascii */
1340 ConioProcessChar(Console, ConInRec);
1341 }
1342
1343 CSR_API(CsrGetScreenBufferInfo)
1344 {
1345 NTSTATUS Status;
1346 PCSRSS_CONSOLE Console;
1347 PCSRSS_SCREEN_BUFFER Buff;
1348 PCONSOLE_SCREEN_BUFFER_INFO pInfo;
1349
1350 DPRINT("CsrGetScreenBufferInfo\n");
1351
1352 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1353 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1354
1355 Status = ConioLockScreenBuffer(ProcessData, Request->Data.ScreenBufferInfoRequest.ConsoleHandle, &Buff, GENERIC_READ);
1356 if (! NT_SUCCESS(Status))
1357 {
1358 return Status;
1359 }
1360 Console = Buff->Header.Console;
1361 pInfo = &Request->Data.ScreenBufferInfoRequest.Info;
1362 pInfo->dwSize.X = Buff->MaxX;
1363 pInfo->dwSize.Y = Buff->MaxY;
1364 pInfo->dwCursorPosition.X = Buff->CurrentX;
1365 pInfo->dwCursorPosition.Y = Buff->CurrentY;
1366 pInfo->wAttributes = Buff->DefaultAttrib;
1367 pInfo->srWindow.Left = Buff->ShowX;
1368 pInfo->srWindow.Right = Buff->ShowX + Console->Size.X - 1;
1369 pInfo->srWindow.Top = Buff->ShowY;
1370 pInfo->srWindow.Bottom = Buff->ShowY + Console->Size.Y - 1;
1371 pInfo->dwMaximumWindowSize.X = Buff->MaxX;
1372 pInfo->dwMaximumWindowSize.Y = Buff->MaxY;
1373 ConioUnlockScreenBuffer(Buff);
1374
1375 return STATUS_SUCCESS;
1376 }
1377
1378 CSR_API(CsrSetCursor)
1379 {
1380 NTSTATUS Status;
1381 PCSRSS_CONSOLE Console;
1382 PCSRSS_SCREEN_BUFFER Buff;
1383 LONG OldCursorX, OldCursorY;
1384 LONG NewCursorX, NewCursorY;
1385
1386 DPRINT("CsrSetCursor\n");
1387
1388 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1389 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1390
1391 Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetCursorRequest.ConsoleHandle, &Buff, GENERIC_WRITE);
1392 if (! NT_SUCCESS(Status))
1393 {
1394 return Status;
1395 }
1396 Console = Buff->Header.Console;
1397
1398 NewCursorX = Request->Data.SetCursorRequest.Position.X;
1399 NewCursorY = Request->Data.SetCursorRequest.Position.Y;
1400 if (NewCursorX < 0 || NewCursorX >= Buff->MaxX ||
1401 NewCursorY < 0 || NewCursorY >= Buff->MaxY)
1402 {
1403 ConioUnlockScreenBuffer(Buff);
1404 return STATUS_INVALID_PARAMETER;
1405 }
1406 OldCursorX = Buff->CurrentX;
1407 OldCursorY = Buff->CurrentY;
1408 Buff->CurrentX = NewCursorX;
1409 Buff->CurrentY = NewCursorY;
1410 if (Buff == Console->ActiveBuffer)
1411 {
1412 if (! ConioSetScreenInfo(Console, Buff, OldCursorX, OldCursorY))
1413 {
1414 ConioUnlockScreenBuffer(Buff);
1415 return STATUS_UNSUCCESSFUL;
1416 }
1417 }
1418
1419 ConioUnlockScreenBuffer(Buff);
1420
1421 return STATUS_SUCCESS;
1422 }
1423
1424 static VOID FASTCALL
1425 ConioComputeUpdateRect(PCSRSS_SCREEN_BUFFER Buff, SMALL_RECT *UpdateRect, COORD *Start, UINT Length)
1426 {
1427 if (Buff->MaxX <= Start->X + Length)
1428 {
1429 UpdateRect->Left = 0;
1430 }
1431 else
1432 {
1433 UpdateRect->Left = Start->X;
1434 }
1435 if (Buff->MaxX <= Start->X + Length)
1436 {
1437 UpdateRect->Right = Buff->MaxX - 1;
1438 }
1439 else
1440 {
1441 UpdateRect->Right = Start->X + Length - 1;
1442 }
1443 UpdateRect->Top = Start->Y;
1444 UpdateRect->Bottom = Start->Y+ (Start->X + Length - 1) / Buff->MaxX;
1445 if (Buff->MaxY <= UpdateRect->Bottom)
1446 {
1447 UpdateRect->Bottom = Buff->MaxY - 1;
1448 }
1449 }
1450
1451 CSR_API(CsrWriteConsoleOutputChar)
1452 {
1453 NTSTATUS Status;
1454 PCHAR String, tmpString = NULL;
1455 PBYTE Buffer;
1456 PCSRSS_CONSOLE Console;
1457 PCSRSS_SCREEN_BUFFER Buff;
1458 DWORD X, Y, Length, CharSize, Written = 0;
1459 SMALL_RECT UpdateRect;
1460
1461 DPRINT("CsrWriteConsoleOutputChar\n");
1462
1463 CharSize = (Request->Data.WriteConsoleOutputCharRequest.Unicode ? sizeof(WCHAR) : sizeof(CHAR));
1464
1465 if (Request->Header.u1.s1.TotalLength
1466 < CSR_API_MESSAGE_HEADER_SIZE(CSRSS_WRITE_CONSOLE_OUTPUT_CHAR)
1467 + (Request->Data.WriteConsoleOutputCharRequest.Length * CharSize))
1468 {
1469 DPRINT1("Invalid request size\n");
1470 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1471 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1472 return STATUS_INVALID_PARAMETER;
1473 }
1474
1475 Status = ConioLockScreenBuffer(ProcessData,
1476 Request->Data.WriteConsoleOutputCharRequest.ConsoleHandle,
1477 &Buff,
1478 GENERIC_WRITE);
1479 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1480 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1481 if (NT_SUCCESS(Status))
1482 {
1483 Console = Buff->Header.Console;
1484 if(Request->Data.WriteConsoleOutputCharRequest.Unicode)
1485 {
1486 Length = WideCharToMultiByte(Console->OutputCodePage, 0,
1487 (PWCHAR)Request->Data.WriteConsoleOutputCharRequest.String,
1488 Request->Data.WriteConsoleOutputCharRequest.Length,
1489 NULL, 0, NULL, NULL);
1490 tmpString = String = RtlAllocateHeap(GetProcessHeap(), 0, Length);
1491 if (String)
1492 {
1493 WideCharToMultiByte(Console->OutputCodePage, 0,
1494 (PWCHAR)Request->Data.WriteConsoleOutputCharRequest.String,
1495 Request->Data.WriteConsoleOutputCharRequest.Length,
1496 String, Length, NULL, NULL);
1497 }
1498 else
1499 {
1500 Status = STATUS_NO_MEMORY;
1501 }
1502 }
1503 else
1504 {
1505 String = (PCHAR)Request->Data.WriteConsoleOutputCharRequest.String;
1506 }
1507
1508 if (String)
1509 {
1510 if (NT_SUCCESS(Status))
1511 {
1512 X = Request->Data.WriteConsoleOutputCharRequest.Coord.X;
1513 Y = (Request->Data.WriteConsoleOutputCharRequest.Coord.Y + Buff->VirtualY) % Buff->MaxY;
1514 Length = Request->Data.WriteConsoleOutputCharRequest.Length;
1515 Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X)];
1516 while (Length--)
1517 {
1518 *Buffer = *String++;
1519 Written++;
1520 Buffer += 2;
1521 if (++X == Buff->MaxX)
1522 {
1523 if (++Y == Buff->MaxY)
1524 {
1525 Y = 0;
1526 Buffer = Buff->Buffer;
1527 }
1528 X = 0;
1529 }
1530 }
1531 if (Buff == Console->ActiveBuffer)
1532 {
1533 ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.WriteConsoleOutputCharRequest.Coord,
1534 Request->Data.WriteConsoleOutputCharRequest.Length);
1535 ConioDrawRegion(Console, &UpdateRect);
1536 }
1537
1538 Request->Data.WriteConsoleOutputCharRequest.EndCoord.X = X;
1539 Request->Data.WriteConsoleOutputCharRequest.EndCoord.Y = (Y + Buff->MaxY - Buff->VirtualY) % Buff->MaxY;
1540
1541 }
1542 if (Request->Data.WriteConsoleRequest.Unicode)
1543 {
1544 RtlFreeHeap(GetProcessHeap(), 0, tmpString);
1545 }
1546 }
1547 ConioUnlockScreenBuffer(Buff);
1548 }
1549 Request->Data.WriteConsoleOutputCharRequest.NrCharactersWritten = Written;
1550 return Status;
1551 }
1552
1553 CSR_API(CsrFillOutputChar)
1554 {
1555 NTSTATUS Status;
1556 PCSRSS_CONSOLE Console;
1557 PCSRSS_SCREEN_BUFFER Buff;
1558 DWORD X, Y, Length, Written = 0;
1559 CHAR Char;
1560 PBYTE Buffer;
1561 SMALL_RECT UpdateRect;
1562
1563 DPRINT("CsrFillOutputChar\n");
1564
1565 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1566 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1567
1568 Status = ConioLockScreenBuffer(ProcessData, Request->Data.FillOutputRequest.ConsoleHandle, &Buff, GENERIC_WRITE);
1569 if (! NT_SUCCESS(Status))
1570 {
1571 return Status;
1572 }
1573 Console = Buff->Header.Console;
1574
1575 X = Request->Data.FillOutputRequest.Position.X;
1576 Y = (Request->Data.FillOutputRequest.Position.Y + Buff->VirtualY) % Buff->MaxY;
1577 Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X)];
1578 if(Request->Data.FillOutputRequest.Unicode)
1579 ConsoleUnicodeCharToAnsiChar(Console, &Char, &Request->Data.FillOutputRequest.Char.UnicodeChar);
1580 else
1581 Char = Request->Data.FillOutputRequest.Char.AsciiChar;
1582 Length = Request->Data.FillOutputRequest.Length;
1583 while (Length--)
1584 {
1585 *Buffer = Char;
1586 Buffer += 2;
1587 Written++;
1588 if (++X == Buff->MaxX)
1589 {
1590 if (++Y == Buff->MaxY)
1591 {
1592 Y = 0;
1593 Buffer = Buff->Buffer;
1594 }
1595 X = 0;
1596 }
1597 }
1598
1599 if (Buff == Console->ActiveBuffer)
1600 {
1601 ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.FillOutputRequest.Position,
1602 Request->Data.FillOutputRequest.Length);
1603 ConioDrawRegion(Console, &UpdateRect);
1604 }
1605
1606 ConioUnlockScreenBuffer(Buff);
1607 Length = Request->Data.FillOutputRequest.Length;
1608 Request->Data.FillOutputRequest.NrCharactersWritten = Length;
1609 return STATUS_SUCCESS;
1610 }
1611
1612 CSR_API(CsrReadInputEvent)
1613 {
1614 PLIST_ENTRY CurrentEntry;
1615 PCSRSS_CONSOLE Console;
1616 NTSTATUS Status;
1617 BOOLEAN Done = FALSE;
1618 ConsoleInput *Input;
1619
1620 DPRINT("CsrReadInputEvent\n");
1621
1622 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1623 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1624 Request->Data.ReadInputRequest.Event = ProcessData->ConsoleEvent;
1625
1626 Status = ConioLockConsole(ProcessData, Request->Data.ReadInputRequest.ConsoleHandle, &Console, GENERIC_READ);
1627 if (! NT_SUCCESS(Status))
1628 {
1629 return Status;
1630 }
1631
1632 /* only get input if there is any */
1633 CurrentEntry = Console->InputEvents.Flink;
1634 while (CurrentEntry != &Console->InputEvents)
1635 {
1636 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
1637 CurrentEntry = CurrentEntry->Flink;
1638
1639 if (Done && !Input->Fake)
1640 {
1641 Request->Data.ReadInputRequest.MoreEvents = TRUE;
1642 break;
1643 }
1644
1645 RemoveEntryList(&Input->ListEntry);
1646
1647 if (!Done && !Input->Fake)
1648 {
1649 Request->Data.ReadInputRequest.Input = Input->InputEvent;
1650 if (Request->Data.ReadInputRequest.Unicode == FALSE)
1651 {
1652 ConioInputEventToAnsi(Console, &Request->Data.ReadInputRequest.Input);
1653 }
1654 Done = TRUE;
1655 }
1656
1657 if (Input->InputEvent.EventType == KEY_EVENT)
1658 {
1659 if (0 != (Console->Mode & ENABLE_LINE_INPUT)
1660 && Input->InputEvent.Event.KeyEvent.bKeyDown
1661 && '\r' == Input->InputEvent.Event.KeyEvent.uChar.AsciiChar)
1662 {
1663 Console->WaitingLines--;
1664 }
1665 Console->WaitingChars--;
1666 }
1667 HeapFree(Win32CsrApiHeap, 0, Input);
1668 }
1669
1670 if (Done)
1671 {
1672 Status = STATUS_SUCCESS;
1673 Console->EarlyReturn = FALSE;
1674 }
1675 else
1676 {
1677 Status = STATUS_PENDING;
1678 Console->EarlyReturn = TRUE; /* mark for early return */
1679 }
1680
1681 if (IsListEmpty(&Console->InputEvents))
1682 {
1683 ResetEvent(Console->ActiveEvent);
1684 }
1685
1686 ConioUnlockConsole(Console);
1687
1688 return Status;
1689 }
1690
1691 CSR_API(CsrWriteConsoleOutputAttrib)
1692 {
1693 PCSRSS_CONSOLE Console;
1694 PCSRSS_SCREEN_BUFFER Buff;
1695 PUCHAR Buffer;
1696 PWORD Attribute;
1697 int X, Y, Length;
1698 NTSTATUS Status;
1699 SMALL_RECT UpdateRect;
1700
1701 DPRINT("CsrWriteConsoleOutputAttrib\n");
1702
1703 if (Request->Header.u1.s1.TotalLength
1704 < CSR_API_MESSAGE_HEADER_SIZE(CSRSS_WRITE_CONSOLE_OUTPUT_ATTRIB)
1705 + Request->Data.WriteConsoleOutputAttribRequest.Length * sizeof(WORD))
1706 {
1707 DPRINT1("Invalid request size\n");
1708 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1709 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1710 return STATUS_INVALID_PARAMETER;
1711 }
1712
1713 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1714 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1715
1716 Status = ConioLockScreenBuffer(ProcessData,
1717 Request->Data.WriteConsoleOutputAttribRequest.ConsoleHandle,
1718 &Buff,
1719 GENERIC_WRITE);
1720 if (! NT_SUCCESS(Status))
1721 {
1722 return Status;
1723 }
1724 Console = Buff->Header.Console;
1725
1726 X = Request->Data.WriteConsoleOutputAttribRequest.Coord.X;
1727 Y = (Request->Data.WriteConsoleOutputAttribRequest.Coord.Y + Buff->VirtualY) % Buff->MaxY;
1728 Length = Request->Data.WriteConsoleOutputAttribRequest.Length;
1729 Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X) + 1];
1730 Attribute = Request->Data.WriteConsoleOutputAttribRequest.Attribute;
1731 while (Length--)
1732 {
1733 *Buffer = (UCHAR)(*Attribute++);
1734 Buffer += 2;
1735 if (++X == Buff->MaxX)
1736 {
1737 if (++Y == Buff->MaxY)
1738 {
1739 Y = 0;
1740 Buffer = Buff->Buffer + 1;
1741 }
1742 X = 0;
1743 }
1744 }
1745
1746 if (Buff == Console->ActiveBuffer)
1747 {
1748 ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.WriteConsoleOutputAttribRequest.Coord,
1749 Request->Data.WriteConsoleOutputAttribRequest.Length);
1750 ConioDrawRegion(Console, &UpdateRect);
1751 }
1752
1753 Request->Data.WriteConsoleOutputAttribRequest.EndCoord.X = X;
1754 Request->Data.WriteConsoleOutputAttribRequest.EndCoord.Y = (Y + Buff->MaxY - Buff->VirtualY) % Buff->MaxY;
1755
1756 ConioUnlockScreenBuffer(Buff);
1757
1758 return STATUS_SUCCESS;
1759 }
1760
1761 CSR_API(CsrFillOutputAttrib)
1762 {
1763 PCSRSS_SCREEN_BUFFER Buff;
1764 PUCHAR Buffer;
1765 NTSTATUS Status;
1766 int X, Y, Length;
1767 UCHAR Attr;
1768 SMALL_RECT UpdateRect;
1769 PCSRSS_CONSOLE Console;
1770
1771 DPRINT("CsrFillOutputAttrib\n");
1772
1773 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1774 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1775 Status = ConioLockScreenBuffer(ProcessData, Request->Data.FillOutputAttribRequest.ConsoleHandle, &Buff, GENERIC_WRITE);
1776 if (! NT_SUCCESS(Status))
1777 {
1778 return Status;
1779 }
1780 Console = Buff->Header.Console;
1781
1782 X = Request->Data.FillOutputAttribRequest.Coord.X;
1783 Y = (Request->Data.FillOutputAttribRequest.Coord.Y + Buff->VirtualY) % Buff->MaxY;
1784 Length = Request->Data.FillOutputAttribRequest.Length;
1785 Attr = Request->Data.FillOutputAttribRequest.Attribute;
1786 Buffer = &Buff->Buffer[(Y * Buff->MaxX * 2) + (X * 2) + 1];
1787 while (Length--)
1788 {
1789 *Buffer = Attr;
1790 Buffer += 2;
1791 if (++X == Buff->MaxX)
1792 {
1793 if (++Y == Buff->MaxY)
1794 {
1795 Y = 0;
1796 Buffer = Buff->Buffer + 1;
1797 }
1798 X = 0;
1799 }
1800 }
1801
1802 if (Buff == Console->ActiveBuffer)
1803 {
1804 ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.FillOutputAttribRequest.Coord,
1805 Request->Data.FillOutputAttribRequest.Length);
1806 ConioDrawRegion(Console, &UpdateRect);
1807 }
1808
1809 ConioUnlockScreenBuffer(Buff);
1810
1811 return STATUS_SUCCESS;
1812 }
1813
1814
1815 CSR_API(CsrGetCursorInfo)
1816 {
1817 PCSRSS_SCREEN_BUFFER Buff;
1818 NTSTATUS Status;
1819
1820 DPRINT("CsrGetCursorInfo\n");
1821
1822 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1823 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1824
1825 Status = ConioLockScreenBuffer(ProcessData, Request->Data.GetCursorInfoRequest.ConsoleHandle, &Buff, GENERIC_READ);
1826 if (! NT_SUCCESS(Status))
1827 {
1828 return Status;
1829 }
1830 Request->Data.GetCursorInfoRequest.Info.bVisible = Buff->CursorInfo.bVisible;
1831 Request->Data.GetCursorInfoRequest.Info.dwSize = Buff->CursorInfo.dwSize;
1832 ConioUnlockScreenBuffer(Buff);
1833
1834 return STATUS_SUCCESS;
1835 }
1836
1837 CSR_API(CsrSetCursorInfo)
1838 {
1839 PCSRSS_CONSOLE Console;
1840 PCSRSS_SCREEN_BUFFER Buff;
1841 DWORD Size;
1842 BOOL Visible;
1843 NTSTATUS Status;
1844
1845 DPRINT("CsrSetCursorInfo\n");
1846
1847 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1848 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1849
1850 Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetCursorInfoRequest.ConsoleHandle, &Buff, GENERIC_WRITE);
1851 if (! NT_SUCCESS(Status))
1852 {
1853 return Status;
1854 }
1855 Console = Buff->Header.Console;
1856
1857 Size = Request->Data.SetCursorInfoRequest.Info.dwSize;
1858 Visible = Request->Data.SetCursorInfoRequest.Info.bVisible;
1859 if (Size < 1)
1860 {
1861 Size = 1;
1862 }
1863 if (100 < Size)
1864 {
1865 Size = 100;
1866 }
1867
1868 if (Size != Buff->CursorInfo.dwSize
1869 || (Visible && ! Buff->CursorInfo.bVisible) || (! Visible && Buff->CursorInfo.bVisible))
1870 {
1871 Buff->CursorInfo.dwSize = Size;
1872 Buff->CursorInfo.bVisible = Visible;
1873
1874 if (! ConioSetCursorInfo(Console, Buff))
1875 {
1876 ConioUnlockScreenBuffer(Buff);
1877 return STATUS_UNSUCCESSFUL;
1878 }
1879 }
1880
1881 ConioUnlockScreenBuffer(Buff);
1882
1883 return STATUS_SUCCESS;
1884 }
1885
1886 CSR_API(CsrSetTextAttrib)
1887 {
1888 NTSTATUS Status;
1889 PCSRSS_CONSOLE Console;
1890 PCSRSS_SCREEN_BUFFER Buff;
1891
1892 DPRINT("CsrSetTextAttrib\n");
1893
1894 Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetCursorRequest.ConsoleHandle, &Buff, GENERIC_WRITE);
1895 if (! NT_SUCCESS(Status))
1896 {
1897 return Status;
1898 }
1899 Console = Buff->Header.Console;
1900
1901 Buff->DefaultAttrib = Request->Data.SetAttribRequest.Attrib;
1902 if (Buff == Console->ActiveBuffer)
1903 {
1904 if (! ConioUpdateScreenInfo(Console, Buff))
1905 {
1906 ConioUnlockScreenBuffer(Buff);
1907 return STATUS_UNSUCCESSFUL;
1908 }
1909 }
1910
1911 ConioUnlockScreenBuffer(Buff);
1912
1913 return STATUS_SUCCESS;
1914 }
1915
1916 CSR_API(CsrSetConsoleMode)
1917 {
1918 NTSTATUS Status;
1919 PCSRSS_CONSOLE Console;
1920 PCSRSS_SCREEN_BUFFER Buff;
1921
1922 DPRINT("CsrSetConsoleMode\n");
1923
1924 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1925 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1926 Status = Win32CsrLockObject(ProcessData,
1927 Request->Data.SetConsoleModeRequest.ConsoleHandle,
1928 (Object_t **) &Console, GENERIC_WRITE, 0);
1929 if (! NT_SUCCESS(Status))
1930 {
1931 return Status;
1932 }
1933
1934 Buff = (PCSRSS_SCREEN_BUFFER)Console;
1935 if (CONIO_CONSOLE_MAGIC == Console->Header.Type)
1936 {
1937 Console->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_INPUT_MODE_VALID;
1938 }
1939 else if (CONIO_SCREEN_BUFFER_MAGIC == Console->Header.Type)
1940 {
1941 Buff->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_OUTPUT_MODE_VALID;
1942 }
1943 else
1944 {
1945 Status = STATUS_INVALID_HANDLE;
1946 }
1947
1948 Win32CsrUnlockObject((Object_t *)Console);
1949
1950 return Status;
1951 }
1952
1953 CSR_API(CsrGetConsoleMode)
1954 {
1955 NTSTATUS Status;
1956 PCSRSS_CONSOLE Console;
1957 PCSRSS_SCREEN_BUFFER Buff; /* gee, I really wish I could use an anonymous union here */
1958
1959 DPRINT("CsrGetConsoleMode\n");
1960
1961 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1962 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1963 Status = Win32CsrLockObject(ProcessData, Request->Data.GetConsoleModeRequest.ConsoleHandle,
1964 (Object_t **) &Console, GENERIC_READ, 0);
1965 if (! NT_SUCCESS(Status))
1966 {
1967 return Status;
1968 }
1969 Status = STATUS_SUCCESS;
1970 Buff = (PCSRSS_SCREEN_BUFFER) Console;
1971 if (CONIO_CONSOLE_MAGIC == Console->Header.Type)
1972 {
1973 Request->Data.GetConsoleModeRequest.ConsoleMode = Console->Mode;
1974 }
1975 else if (CONIO_SCREEN_BUFFER_MAGIC == Buff->Header.Type)
1976 {
1977 Request->Data.GetConsoleModeRequest.ConsoleMode = Buff->Mode;
1978 }
1979 else
1980 {
1981 Status = STATUS_INVALID_HANDLE;
1982 }
1983
1984 Win32CsrUnlockObject((Object_t *)Console);
1985 return Status;
1986 }
1987
1988 CSR_API(CsrCreateScreenBuffer)
1989 {
1990 PCSRSS_CONSOLE Console;
1991 PCSRSS_SCREEN_BUFFER Buff;
1992 NTSTATUS Status;
1993
1994 DPRINT("CsrCreateScreenBuffer\n");
1995
1996 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
1997 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1998 if (! NT_SUCCESS(Status))
1999 {
2000 return Status;
2001 }
2002
2003 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2004 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2005
2006 Buff = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY, sizeof(CSRSS_SCREEN_BUFFER));
2007
2008 if (Buff != NULL)
2009 {
2010 if (Console->ActiveBuffer)
2011 {
2012 Buff->MaxX = Console->ActiveBuffer->MaxX;
2013 Buff->MaxY = Console->ActiveBuffer->MaxY;
2014 Buff->CursorInfo.bVisible = Console->ActiveBuffer->CursorInfo.bVisible;
2015 Buff->CursorInfo.dwSize = Console->ActiveBuffer->CursorInfo.dwSize;
2016 }
2017 else
2018 {
2019 Buff->CursorInfo.bVisible = TRUE;
2020 Buff->CursorInfo.dwSize = CSR_DEFAULT_CURSOR_SIZE;
2021 }
2022
2023 if (Buff->MaxX == 0)
2024 {
2025 Buff->MaxX = 80;
2026 }
2027
2028 if (Buff->MaxY == 0)
2029 {
2030 Buff->MaxY = 25;
2031 }
2032
2033 Status = CsrInitConsoleScreenBuffer(Console, Buff);
2034 if (NT_SUCCESS(Status))
2035 {
2036 Status = Win32CsrInsertObject(ProcessData,
2037 &Request->Data.CreateScreenBufferRequest.OutputHandle,
2038 &Buff->Header,
2039 Request->Data.CreateScreenBufferRequest.Access,
2040 Request->Data.CreateScreenBufferRequest.Inheritable,
2041 Request->Data.CreateScreenBufferRequest.ShareMode);
2042 }
2043 }
2044 else
2045 {
2046 Status = STATUS_INSUFFICIENT_RESOURCES;
2047 }
2048
2049 ConioUnlockConsole(Console);
2050 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
2051 return Status;
2052 }
2053
2054 CSR_API(CsrSetScreenBuffer)
2055 {
2056 NTSTATUS Status;
2057 PCSRSS_CONSOLE Console;
2058 PCSRSS_SCREEN_BUFFER Buff;
2059
2060 DPRINT("CsrSetScreenBuffer\n");
2061
2062 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2063 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2064
2065 Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetScreenBufferRequest.OutputHandle, &Buff, GENERIC_WRITE);
2066 if (! NT_SUCCESS(Status))
2067 {
2068 return Status;
2069 }
2070 Console = Buff->Header.Console;
2071
2072 if (Buff == Console->ActiveBuffer)
2073 {
2074 ConioUnlockScreenBuffer(Buff);
2075 return STATUS_SUCCESS;
2076 }
2077
2078 /* If old buffer has no handles, it's now unreferenced */
2079 if (Console->ActiveBuffer->Header.HandleCount == 0)
2080 {
2081 ConioDeleteScreenBuffer(Console->ActiveBuffer);
2082 }
2083 /* tie console to new buffer */
2084 Console->ActiveBuffer = Buff;
2085 /* Redraw the console */
2086 ConioDrawConsole(Console);
2087
2088 ConioUnlockScreenBuffer(Buff);
2089
2090 return STATUS_SUCCESS;
2091 }
2092
2093 CSR_API(CsrSetTitle)
2094 {
2095 NTSTATUS Status;
2096 PCSRSS_CONSOLE Console;
2097 PWCHAR Buffer;
2098
2099 DPRINT("CsrSetTitle\n");
2100
2101 if (Request->Header.u1.s1.TotalLength
2102 < CSR_API_MESSAGE_HEADER_SIZE(CSRSS_SET_TITLE)
2103 + Request->Data.SetTitleRequest.Length)
2104 {
2105 DPRINT1("Invalid request size\n");
2106 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2107 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2108 return STATUS_INVALID_PARAMETER;
2109 }
2110
2111 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2112 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2113 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2114 if(NT_SUCCESS(Status))
2115 {
2116 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Request->Data.SetTitleRequest.Length);
2117 if (Buffer)
2118 {
2119 /* copy title to console */
2120 RtlFreeUnicodeString(&Console->Title);
2121 Console->Title.Buffer = Buffer;
2122 Console->Title.Length = Console->Title.MaximumLength = Request->Data.SetTitleRequest.Length;
2123 memcpy(Console->Title.Buffer, Request->Data.SetTitleRequest.Title, Console->Title.Length);
2124 if (! ConioChangeTitle(Console))
2125 {
2126 Status = STATUS_UNSUCCESSFUL;
2127 }
2128 else
2129 {
2130 Status = STATUS_SUCCESS;
2131 }
2132 }
2133 else
2134 {
2135 Status = STATUS_NO_MEMORY;
2136 }
2137 ConioUnlockConsole(Console);
2138 }
2139
2140 return Status;
2141 }
2142
2143 CSR_API(CsrGetTitle)
2144 {
2145 NTSTATUS Status;
2146 PCSRSS_CONSOLE Console;
2147 DWORD Length;
2148
2149 DPRINT("CsrGetTitle\n");
2150
2151 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2152 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2153 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2154 if (! NT_SUCCESS(Status))
2155 {
2156 DPRINT1("Can't get console\n");
2157 return Status;
2158 }
2159
2160 /* Copy title of the console to the user title buffer */
2161 RtlZeroMemory(&Request->Data.GetTitleRequest, sizeof(CSRSS_GET_TITLE));
2162 Request->Data.GetTitleRequest.Length = Console->Title.Length;
2163 memcpy (Request->Data.GetTitleRequest.Title, Console->Title.Buffer,
2164 Console->Title.Length);
2165 Length = CSR_API_MESSAGE_HEADER_SIZE(CSRSS_SET_TITLE) + Console->Title.Length;
2166
2167 ConioUnlockConsole(Console);
2168
2169 if (Length > sizeof(CSR_API_MESSAGE))
2170 {
2171 Request->Header.u1.s1.TotalLength = Length;
2172 Request->Header.u1.s1.DataLength = Length - sizeof(PORT_MESSAGE);
2173 }
2174 return STATUS_SUCCESS;
2175 }
2176
2177 CSR_API(CsrWriteConsoleOutput)
2178 {
2179 SHORT i, X, Y, SizeX, SizeY;
2180 PCSRSS_CONSOLE Console;
2181 PCSRSS_SCREEN_BUFFER Buff;
2182 SMALL_RECT ScreenBuffer;
2183 CHAR_INFO* CurCharInfo;
2184 SMALL_RECT WriteRegion;
2185 CHAR_INFO* CharInfo;
2186 COORD BufferCoord;
2187 COORD BufferSize;
2188 NTSTATUS Status;
2189 PBYTE Ptr;
2190 DWORD PSize;
2191
2192 DPRINT("CsrWriteConsoleOutput\n");
2193
2194 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2195 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2196 Status = ConioLockScreenBuffer(ProcessData,
2197 Request->Data.WriteConsoleOutputRequest.ConsoleHandle,
2198 &Buff,
2199 GENERIC_WRITE);
2200 if (! NT_SUCCESS(Status))
2201 {
2202 return Status;
2203 }
2204 Console = Buff->Header.Console;
2205
2206 BufferSize = Request->Data.WriteConsoleOutputRequest.BufferSize;
2207 PSize = BufferSize.X * BufferSize.Y * sizeof(CHAR_INFO);
2208 BufferCoord = Request->Data.WriteConsoleOutputRequest.BufferCoord;
2209 CharInfo = Request->Data.WriteConsoleOutputRequest.CharInfo;
2210 if (((PVOID)CharInfo < ProcessData->CsrSectionViewBase) ||
2211 (((ULONG_PTR)CharInfo + PSize) >
2212 ((ULONG_PTR)ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2213 {
2214 ConioUnlockScreenBuffer(Buff);
2215 return STATUS_ACCESS_VIOLATION;
2216 }
2217 WriteRegion = Request->Data.WriteConsoleOutputRequest.WriteRegion;
2218
2219 SizeY = min(BufferSize.Y - BufferCoord.Y, ConioRectHeight(&WriteRegion));
2220 SizeX = min(BufferSize.X - BufferCoord.X, ConioRectWidth(&WriteRegion));
2221 WriteRegion.Bottom = WriteRegion.Top + SizeY - 1;
2222 WriteRegion.Right = WriteRegion.Left + SizeX - 1;
2223
2224 /* Make sure WriteRegion is inside the screen buffer */
2225 ConioInitRect(&ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
2226 if (! ConioGetIntersection(&WriteRegion, &ScreenBuffer, &WriteRegion))
2227 {
2228 ConioUnlockScreenBuffer(Buff);
2229
2230 /* It is okay to have a WriteRegion completely outside the screen buffer.
2231 No data is written then. */
2232 return STATUS_SUCCESS;
2233 }
2234
2235 for (i = 0, Y = WriteRegion.Top; Y <= WriteRegion.Bottom; i++, Y++)
2236 {
2237 CurCharInfo = CharInfo + (i + BufferCoord.Y) * BufferSize.X + BufferCoord.X;
2238 Ptr = ConioCoordToPointer(Buff, WriteRegion.Left, Y);
2239 for (X = WriteRegion.Left; X <= WriteRegion.Right; X++)
2240 {
2241 CHAR AsciiChar;
2242 if (Request->Data.WriteConsoleOutputRequest.Unicode)
2243 {
2244 ConsoleUnicodeCharToAnsiChar(Console, &AsciiChar, &CurCharInfo->Char.UnicodeChar);
2245 }
2246 else
2247 {
2248 AsciiChar = CurCharInfo->Char.AsciiChar;
2249 }
2250 *Ptr++ = AsciiChar;
2251 *Ptr++ = CurCharInfo->Attributes;
2252 CurCharInfo++;
2253 }
2254 }
2255
2256 ConioDrawRegion(Console, &WriteRegion);
2257
2258 ConioUnlockScreenBuffer(Buff);
2259
2260 Request->Data.WriteConsoleOutputRequest.WriteRegion.Right = WriteRegion.Left + SizeX - 1;
2261 Request->Data.WriteConsoleOutputRequest.WriteRegion.Bottom = WriteRegion.Top + SizeY - 1;
2262 Request->Data.WriteConsoleOutputRequest.WriteRegion.Left = WriteRegion.Left;
2263 Request->Data.WriteConsoleOutputRequest.WriteRegion.Top = WriteRegion.Top;
2264
2265 return STATUS_SUCCESS;
2266 }
2267
2268 CSR_API(CsrFlushInputBuffer)
2269 {
2270 PLIST_ENTRY CurrentEntry;
2271 PCSRSS_CONSOLE Console;
2272 ConsoleInput* Input;
2273 NTSTATUS Status;
2274
2275 DPRINT("CsrFlushInputBuffer\n");
2276
2277 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2278 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2279 Status = ConioLockConsole(ProcessData,
2280 Request->Data.FlushInputBufferRequest.ConsoleInput,
2281 &Console,
2282 GENERIC_WRITE);
2283 if(! NT_SUCCESS(Status))
2284 {
2285 return Status;
2286 }
2287
2288 /* Discard all entries in the input event queue */
2289 while (!IsListEmpty(&Console->InputEvents))
2290 {
2291 CurrentEntry = RemoveHeadList(&Console->InputEvents);
2292 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
2293 /* Destroy the event */
2294 HeapFree(Win32CsrApiHeap, 0, Input);
2295 }
2296 ResetEvent(Console->ActiveEvent);
2297 Console->WaitingChars=0;
2298
2299 ConioUnlockConsole(Console);
2300
2301 return STATUS_SUCCESS;
2302 }
2303
2304 CSR_API(CsrScrollConsoleScreenBuffer)
2305 {
2306 PCSRSS_CONSOLE Console;
2307 PCSRSS_SCREEN_BUFFER Buff;
2308 SMALL_RECT ScreenBuffer;
2309 SMALL_RECT SrcRegion;
2310 SMALL_RECT DstRegion;
2311 SMALL_RECT UpdateRegion;
2312 SMALL_RECT ScrollRectangle;
2313 SMALL_RECT ClipRectangle;
2314 NTSTATUS Status;
2315 HANDLE ConsoleHandle;
2316 BOOLEAN UseClipRectangle;
2317 COORD DestinationOrigin;
2318 CHAR_INFO Fill;
2319 CHAR FillChar;
2320
2321 DPRINT("CsrScrollConsoleScreenBuffer\n");
2322
2323 ConsoleHandle = Request->Data.ScrollConsoleScreenBufferRequest.ConsoleHandle;
2324 UseClipRectangle = Request->Data.ScrollConsoleScreenBufferRequest.UseClipRectangle;
2325 DestinationOrigin = Request->Data.ScrollConsoleScreenBufferRequest.DestinationOrigin;
2326 Fill = Request->Data.ScrollConsoleScreenBufferRequest.Fill;
2327
2328 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2329 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2330 Status = ConioLockScreenBuffer(ProcessData, ConsoleHandle, &Buff, GENERIC_WRITE);
2331 if (! NT_SUCCESS(Status))
2332 {
2333 return Status;
2334 }
2335 Console = Buff->Header.Console;
2336
2337 ScrollRectangle = Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle;
2338
2339 /* Make sure source rectangle is inside the screen buffer */
2340 ConioInitRect(&ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
2341 if (! ConioGetIntersection(&SrcRegion, &ScreenBuffer, &ScrollRectangle))
2342 {
2343 ConioUnlockScreenBuffer(Buff);
2344 return STATUS_SUCCESS;
2345 }
2346
2347 /* If the source was clipped on the left or top, adjust the destination accordingly */
2348 if (ScrollRectangle.Left < 0)
2349 {
2350 DestinationOrigin.X -= ScrollRectangle.Left;
2351 }
2352 if (ScrollRectangle.Top < 0)
2353 {
2354 DestinationOrigin.Y -= ScrollRectangle.Top;
2355 }
2356
2357 if (UseClipRectangle)
2358 {
2359 ClipRectangle = Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle;
2360 if (!ConioGetIntersection(&ClipRectangle, &ClipRectangle, &ScreenBuffer))
2361 {
2362 ConioUnlockScreenBuffer(Buff);
2363 return STATUS_SUCCESS;
2364 }
2365 }
2366 else
2367 {
2368 ClipRectangle = ScreenBuffer;
2369 }
2370
2371 ConioInitRect(&DstRegion,
2372 DestinationOrigin.Y,
2373 DestinationOrigin.X,
2374 DestinationOrigin.Y + ConioRectHeight(&SrcRegion) - 1,
2375 DestinationOrigin.X + ConioRectWidth(&SrcRegion) - 1);
2376
2377 if (Request->Data.ScrollConsoleScreenBufferRequest.Unicode)
2378 ConsoleUnicodeCharToAnsiChar(Console, &FillChar, &Fill.Char.UnicodeChar);
2379 else
2380 FillChar = Fill.Char.AsciiChar;
2381
2382 ConioMoveRegion(Buff, &SrcRegion, &DstRegion, &ClipRectangle, Fill.Attributes << 8 | (BYTE)FillChar);
2383
2384 if (Buff == Console->ActiveBuffer)
2385 {
2386 ConioGetUnion(&UpdateRegion, &SrcRegion, &DstRegion);
2387 if (ConioGetIntersection(&UpdateRegion, &UpdateRegion, &ClipRectangle))
2388 {
2389 /* Draw update region */
2390 ConioDrawRegion(Console, &UpdateRegion);
2391 }
2392 }
2393
2394 ConioUnlockScreenBuffer(Buff);
2395
2396 return STATUS_SUCCESS;
2397 }
2398
2399 CSR_API(CsrReadConsoleOutputChar)
2400 {
2401 NTSTATUS Status;
2402 PCSRSS_CONSOLE Console;
2403 PCSRSS_SCREEN_BUFFER Buff;
2404 DWORD Xpos, Ypos;
2405 PCHAR ReadBuffer;
2406 DWORD i;
2407 ULONG CharSize;
2408 CHAR Char;
2409
2410 DPRINT("CsrReadConsoleOutputChar\n");
2411
2412 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2413 Request->Header.u1.s1.DataLength = Request->Header.u1.s1.TotalLength - sizeof(PORT_MESSAGE);
2414 ReadBuffer = Request->Data.ReadConsoleOutputCharRequest.String;
2415
2416 CharSize = (Request->Data.ReadConsoleOutputCharRequest.Unicode ? sizeof(WCHAR) : sizeof(CHAR));
2417
2418 Status = ConioLockScreenBuffer(ProcessData, Request->Data.ReadConsoleOutputCharRequest.ConsoleHandle, &Buff, GENERIC_READ);
2419 if (! NT_SUCCESS(Status))
2420 {
2421 return Status;
2422 }
2423 Console = Buff->Header.Console;
2424
2425 Xpos = Request->Data.ReadConsoleOutputCharRequest.ReadCoord.X;
2426 Ypos = (Request->Data.ReadConsoleOutputCharRequest.ReadCoord.Y + Buff->VirtualY) % Buff->MaxY;
2427
2428 for (i = 0; i < Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead; ++i)
2429 {
2430 Char = Buff->Buffer[(Xpos * 2) + (Ypos * 2 * Buff->MaxX)];
2431
2432 if(Request->Data.ReadConsoleOutputCharRequest.Unicode)
2433 {
2434 ConsoleAnsiCharToUnicodeChar(Console, (WCHAR*)ReadBuffer, &Char);
2435 ReadBuffer += sizeof(WCHAR);
2436 }
2437 else
2438 *(ReadBuffer++) = Char;
2439
2440 Xpos++;
2441
2442 if (Xpos == Buff->MaxX)
2443 {
2444 Xpos = 0;
2445 Ypos++;
2446
2447 if (Ypos == Buff->MaxY)
2448 {
2449 Ypos = 0;
2450 }
2451 }
2452 }
2453
2454 *ReadBuffer = 0;
2455 Request->Data.ReadConsoleOutputCharRequest.EndCoord.X = Xpos;
2456 Request->Data.ReadConsoleOutputCharRequest.EndCoord.Y = (Ypos - Buff->VirtualY + Buff->MaxY) % Buff->MaxY;
2457
2458 ConioUnlockScreenBuffer(Buff);
2459
2460 Request->Data.ReadConsoleOutputCharRequest.CharsRead = (DWORD)((ULONG_PTR)ReadBuffer - (ULONG_PTR)Request->Data.ReadConsoleOutputCharRequest.String) / CharSize;
2461 if (Request->Data.ReadConsoleOutputCharRequest.CharsRead * CharSize + CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE_OUTPUT_CHAR) > sizeof(CSR_API_MESSAGE))
2462 {
2463 Request->Header.u1.s1.TotalLength = Request->Data.ReadConsoleOutputCharRequest.CharsRead * CharSize + CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE_OUTPUT_CHAR);
2464 Request->Header.u1.s1.DataLength = Request->Header.u1.s1.TotalLength - sizeof(PORT_MESSAGE);
2465 }
2466
2467 return STATUS_SUCCESS;
2468 }
2469
2470
2471 CSR_API(CsrReadConsoleOutputAttrib)
2472 {
2473 NTSTATUS Status;
2474 PCSRSS_SCREEN_BUFFER Buff;
2475 DWORD Xpos, Ypos;
2476 PWORD ReadBuffer;
2477 DWORD i;
2478 DWORD CurrentLength;
2479
2480 DPRINT("CsrReadConsoleOutputAttrib\n");
2481
2482 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2483 Request->Header.u1.s1.DataLength = Request->Header.u1.s1.TotalLength - sizeof(PORT_MESSAGE);
2484 ReadBuffer = Request->Data.ReadConsoleOutputAttribRequest.Attribute;
2485
2486 Status = ConioLockScreenBuffer(ProcessData, Request->Data.ReadConsoleOutputAttribRequest.ConsoleHandle, &Buff, GENERIC_READ);
2487 if (! NT_SUCCESS(Status))
2488 {
2489 return Status;
2490 }
2491
2492 Xpos = Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.X;
2493 Ypos = (Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.Y + Buff->VirtualY) % Buff->MaxY;
2494
2495 for (i = 0; i < Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead; ++i)
2496 {
2497 *ReadBuffer = Buff->Buffer[(Xpos * 2) + (Ypos * 2 * Buff->MaxX) + 1];
2498
2499 ReadBuffer++;
2500 Xpos++;
2501
2502 if (Xpos == Buff->MaxX)
2503 {
2504 Xpos = 0;
2505 Ypos++;
2506
2507 if (Ypos == Buff->MaxY)
2508 {
2509 Ypos = 0;
2510 }
2511 }
2512 }
2513
2514 *ReadBuffer = 0;
2515
2516 Request->Data.ReadConsoleOutputAttribRequest.EndCoord.X = Xpos;
2517 Request->Data.ReadConsoleOutputAttribRequest.EndCoord.Y = (Ypos - Buff->VirtualY + Buff->MaxY) % Buff->MaxY;
2518
2519 ConioUnlockScreenBuffer(Buff);
2520
2521 CurrentLength = CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE_OUTPUT_ATTRIB)
2522 + Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead * sizeof(WORD);
2523 if (CurrentLength > sizeof(CSR_API_MESSAGE))
2524 {
2525 Request->Header.u1.s1.TotalLength = CurrentLength;
2526 Request->Header.u1.s1.DataLength = CurrentLength - sizeof(PORT_MESSAGE);
2527 }
2528
2529 return STATUS_SUCCESS;
2530 }
2531
2532
2533 CSR_API(CsrGetNumberOfConsoleInputEvents)
2534 {
2535 NTSTATUS Status;
2536 PCSRSS_CONSOLE Console;
2537 PLIST_ENTRY CurrentItem;
2538 DWORD NumEvents;
2539 ConsoleInput *Input;
2540
2541 DPRINT("CsrGetNumberOfConsoleInputEvents\n");
2542
2543 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2544 Request->Header.u1.s1.DataLength = Request->Header.u1.s1.TotalLength - sizeof(PORT_MESSAGE);
2545
2546 Status = ConioLockConsole(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, &Console, GENERIC_READ);
2547 if (! NT_SUCCESS(Status))
2548 {
2549 return Status;
2550 }
2551
2552 CurrentItem = Console->InputEvents.Flink;
2553 NumEvents = 0;
2554
2555 /* If there are any events ... */
2556 while (CurrentItem != &Console->InputEvents)
2557 {
2558 Input = CONTAINING_RECORD(CurrentItem, ConsoleInput, ListEntry);
2559 CurrentItem = CurrentItem->Flink;
2560 if (!Input->Fake)
2561 {
2562 NumEvents++;
2563 }
2564 }
2565
2566 ConioUnlockConsole(Console);
2567
2568 Request->Data.GetNumInputEventsRequest.NumInputEvents = NumEvents;
2569
2570 return STATUS_SUCCESS;
2571 }
2572
2573
2574 CSR_API(CsrPeekConsoleInput)
2575 {
2576 NTSTATUS Status;
2577 PCSRSS_CONSOLE Console;
2578 DWORD Size;
2579 DWORD Length;
2580 PLIST_ENTRY CurrentItem;
2581 PINPUT_RECORD InputRecord;
2582 ConsoleInput* Item;
2583 UINT NumItems;
2584
2585 DPRINT("CsrPeekConsoleInput\n");
2586
2587 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2588 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2589
2590 Status = ConioLockConsole(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, &Console, GENERIC_READ);
2591 if(! NT_SUCCESS(Status))
2592 {
2593 return Status;
2594 }
2595
2596 InputRecord = Request->Data.PeekConsoleInputRequest.InputRecord;
2597 Length = Request->Data.PeekConsoleInputRequest.Length;
2598 Size = Length * sizeof(INPUT_RECORD);
2599
2600 if (((PVOID)InputRecord < ProcessData->CsrSectionViewBase)
2601 || (((ULONG_PTR)InputRecord + Size) > ((ULONG_PTR)ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2602 {
2603 ConioUnlockConsole(Console);
2604 return STATUS_ACCESS_VIOLATION;
2605 }
2606
2607 NumItems = 0;
2608
2609 if (! IsListEmpty(&Console->InputEvents))
2610 {
2611 CurrentItem = Console->InputEvents.Flink;
2612
2613 while (CurrentItem != &Console->InputEvents && NumItems < Length)
2614 {
2615 Item = CONTAINING_RECORD(CurrentItem, ConsoleInput, ListEntry);
2616
2617 if (Item->Fake)
2618 {
2619 CurrentItem = CurrentItem->Flink;
2620 continue;
2621 }
2622
2623 ++NumItems;
2624 *InputRecord = Item->InputEvent;
2625
2626 if (Request->Data.ReadInputRequest.Unicode == FALSE)
2627 {
2628 ConioInputEventToAnsi(Console, InputRecord);
2629 }
2630
2631 InputRecord++;
2632 CurrentItem = CurrentItem->Flink;
2633 }
2634 }
2635
2636 ConioUnlockConsole(Console);
2637
2638 Request->Data.PeekConsoleInputRequest.Length = NumItems;
2639
2640 return STATUS_SUCCESS;
2641 }
2642
2643
2644 CSR_API(CsrReadConsoleOutput)
2645 {
2646 PCHAR_INFO CharInfo;
2647 PCHAR_INFO CurCharInfo;
2648 PCSRSS_SCREEN_BUFFER Buff;
2649 DWORD Size;
2650 DWORD Length;
2651 DWORD SizeX, SizeY;
2652 NTSTATUS Status;
2653 COORD BufferSize;
2654 COORD BufferCoord;
2655 SMALL_RECT ReadRegion;
2656 SMALL_RECT ScreenRect;
2657 DWORD i;
2658 PBYTE Ptr;
2659 LONG X, Y;
2660 UINT CodePage;
2661
2662 DPRINT("CsrReadConsoleOutput\n");
2663
2664 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2665 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2666
2667 Status = ConioLockScreenBuffer(ProcessData, Request->Data.ReadConsoleOutputRequest.ConsoleHandle, &Buff, GENERIC_READ);
2668 if (! NT_SUCCESS(Status))
2669 {
2670 return Status;
2671 }
2672
2673 CharInfo = Request->Data.ReadConsoleOutputRequest.CharInfo;
2674 ReadRegion = Request->Data.ReadConsoleOutputRequest.ReadRegion;
2675 BufferSize = Request->Data.ReadConsoleOutputRequest.BufferSize;
2676 BufferCoord = Request->Data.ReadConsoleOutputRequest.BufferCoord;
2677 Length = BufferSize.X * BufferSize.Y;
2678 Size = Length * sizeof(CHAR_INFO);
2679
2680 /* FIXME: Is this correct? */
2681 CodePage = ProcessData->Console->OutputCodePage;
2682
2683 if (((PVOID)CharInfo < ProcessData->CsrSectionViewBase)
2684 || (((ULONG_PTR)CharInfo + Size) > ((ULONG_PTR)ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2685 {
2686 ConioUnlockScreenBuffer(Buff);
2687 return STATUS_ACCESS_VIOLATION;
2688 }
2689
2690 SizeY = min(BufferSize.Y - BufferCoord.Y, ConioRectHeight(&ReadRegion));
2691 SizeX = min(BufferSize.X - BufferCoord.X, ConioRectWidth(&ReadRegion));
2692 ReadRegion.Bottom = ReadRegion.Top + SizeY;
2693 ReadRegion.Right = ReadRegion.Left + SizeX;
2694
2695 ConioInitRect(&ScreenRect, 0, 0, Buff->MaxY, Buff->MaxX);
2696 if (! ConioGetIntersection(&ReadRegion, &ScreenRect, &ReadRegion))
2697 {
2698 ConioUnlockScreenBuffer(Buff);
2699 return STATUS_SUCCESS;
2700 }
2701
2702 for (i = 0, Y = ReadRegion.Top; Y < ReadRegion.Bottom; ++i, ++Y)
2703 {
2704 CurCharInfo = CharInfo + (i * BufferSize.X);
2705
2706 Ptr = ConioCoordToPointer(Buff, ReadRegion.Left, Y);
2707 for (X = ReadRegion.Left; X < ReadRegion.Right; ++X)
2708 {
2709 if (Request->Data.ReadConsoleOutputRequest.Unicode)
2710 {
2711 MultiByteToWideChar(CodePage, 0,
2712 (PCHAR)Ptr++, 1,
2713 &CurCharInfo->Char.UnicodeChar, 1);
2714 }
2715 else
2716 {
2717 CurCharInfo->Char.AsciiChar = *Ptr++;
2718 }
2719 CurCharInfo->Attributes = *Ptr++;
2720 ++CurCharInfo;
2721 }
2722 }
2723
2724 ConioUnlockScreenBuffer(Buff);
2725
2726 Request->Data.ReadConsoleOutputRequest.ReadRegion.Right = ReadRegion.Left + SizeX - 1;
2727 Request->Data.ReadConsoleOutputRequest.ReadRegion.Bottom = ReadRegion.Top + SizeY - 1;
2728 Request->Data.ReadConsoleOutputRequest.ReadRegion.Left = ReadRegion.Left;
2729 Request->Data.ReadConsoleOutputRequest.ReadRegion.Top = ReadRegion.Top;
2730
2731 return STATUS_SUCCESS;
2732 }
2733
2734
2735 CSR_API(CsrWriteConsoleInput)
2736 {
2737 PINPUT_RECORD InputRecord;
2738 PCSRSS_CONSOLE Console;
2739 NTSTATUS Status;
2740 DWORD Length;
2741 DWORD Size;
2742 DWORD i;
2743 ConsoleInput* Record;
2744
2745 DPRINT("CsrWriteConsoleInput\n");
2746
2747 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2748 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2749
2750 Status = ConioLockConsole(ProcessData, Request->Data.WriteConsoleInputRequest.ConsoleHandle, &Console, GENERIC_WRITE);
2751 if (! NT_SUCCESS(Status))
2752 {
2753 return Status;
2754 }
2755
2756 InputRecord = Request->Data.WriteConsoleInputRequest.InputRecord;
2757 Length = Request->Data.WriteConsoleInputRequest.Length;
2758 Size = Length * sizeof(INPUT_RECORD);
2759
2760 if (((PVOID)InputRecord < ProcessData->CsrSectionViewBase)
2761 || (((ULONG_PTR)InputRecord + Size) > ((ULONG_PTR)ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2762 {
2763 ConioUnlockConsole(Console);
2764 return STATUS_ACCESS_VIOLATION;
2765 }
2766
2767 for (i = 0; i < Length; i++)
2768 {
2769 Record = HeapAlloc(Win32CsrApiHeap, 0, sizeof(ConsoleInput));
2770 if (NULL == Record)
2771 {
2772 ConioUnlockConsole(Console);
2773 return STATUS_INSUFFICIENT_RESOURCES;
2774 }
2775
2776 Record->Echoed = FALSE;
2777 Record->Fake = FALSE;
2778 //Record->InputEvent = *InputRecord++;
2779 memcpy(&Record->InputEvent, &InputRecord[i], sizeof(INPUT_RECORD));
2780 if (KEY_EVENT == Record->InputEvent.EventType)
2781 {
2782 /* FIXME - convert from unicode to ascii!! */
2783 ConioProcessChar(Console, Record);
2784 }
2785 }
2786
2787 ConioUnlockConsole(Console);
2788
2789 Request->Data.WriteConsoleInputRequest.Length = i;
2790
2791 return STATUS_SUCCESS;
2792 }
2793
2794 /**********************************************************************
2795 * HardwareStateProperty
2796 *
2797 * DESCRIPTION
2798 * Set/Get the value of the HardwareState and switch
2799 * between direct video buffer ouput and GDI windowed
2800 * output.
2801 * ARGUMENTS
2802 * Client hands us a CSRSS_CONSOLE_HARDWARE_STATE
2803 * object. We use the same object to Request.
2804 * NOTE
2805 * ConsoleHwState has the correct size to be compatible
2806 * with NT's, but values are not.
2807 */
2808 static NTSTATUS FASTCALL
2809 SetConsoleHardwareState (PCSRSS_CONSOLE Console, DWORD ConsoleHwState)
2810 {
2811 DPRINT1("Console Hardware State: %d\n", ConsoleHwState);
2812
2813 if ((CONSOLE_HARDWARE_STATE_GDI_MANAGED == ConsoleHwState)
2814 ||(CONSOLE_HARDWARE_STATE_DIRECT == ConsoleHwState))
2815 {
2816 if (Console->HardwareState != ConsoleHwState)
2817 {
2818 /* TODO: implement switching from full screen to windowed mode */
2819 /* TODO: or back; now simply store the hardware state */
2820 Console->HardwareState = ConsoleHwState;
2821 }
2822
2823 return STATUS_SUCCESS;
2824 }
2825
2826 return STATUS_INVALID_PARAMETER_3; /* Client: (handle, set_get, [mode]) */
2827 }
2828
2829 CSR_API(CsrHardwareStateProperty)
2830 {
2831 PCSRSS_CONSOLE Console;
2832 NTSTATUS Status;
2833
2834 DPRINT("CsrHardwareStateProperty\n");
2835
2836 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2837 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2838
2839 Status = ConioLockConsole(ProcessData,
2840 Request->Data.ConsoleHardwareStateRequest.ConsoleHandle,
2841 &Console,
2842 GENERIC_READ);
2843 if (! NT_SUCCESS(Status))
2844 {
2845 DPRINT1("Failed to get console handle in SetConsoleHardwareState\n");
2846 return Status;
2847 }
2848
2849 switch (Request->Data.ConsoleHardwareStateRequest.SetGet)
2850 {
2851 case CONSOLE_HARDWARE_STATE_GET:
2852 Request->Data.ConsoleHardwareStateRequest.State = Console->HardwareState;
2853 break;
2854
2855 case CONSOLE_HARDWARE_STATE_SET:
2856 DPRINT("Setting console hardware state.\n");
2857 Status = SetConsoleHardwareState(Console, Request->Data.ConsoleHardwareStateRequest.State);
2858 break;
2859
2860 default:
2861 Status = STATUS_INVALID_PARAMETER_2; /* Client: (handle, [set_get], mode) */
2862 break;
2863 }
2864
2865 ConioUnlockConsole(Console);
2866
2867 return Status;
2868 }
2869
2870 CSR_API(CsrGetConsoleWindow)
2871 {
2872 PCSRSS_CONSOLE Console;
2873 NTSTATUS Status;
2874
2875 DPRINT("CsrGetConsoleWindow\n");
2876
2877 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2878 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2879
2880 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2881 if (! NT_SUCCESS(Status))
2882 {
2883 return Status;
2884 }
2885
2886 Request->Data.GetConsoleWindowRequest.WindowHandle = Console->hWindow;
2887 ConioUnlockConsole(Console);
2888
2889 return STATUS_SUCCESS;
2890 }
2891
2892 CSR_API(CsrSetConsoleIcon)
2893 {
2894 PCSRSS_CONSOLE Console;
2895 NTSTATUS Status;
2896
2897 DPRINT("CsrSetConsoleIcon\n");
2898
2899 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2900 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2901
2902 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2903 if (! NT_SUCCESS(Status))
2904 {
2905 return Status;
2906 }
2907
2908 Status = (ConioChangeIcon(Console, Request->Data.SetConsoleIconRequest.WindowIcon)
2909 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
2910 ConioUnlockConsole(Console);
2911
2912 return Status;
2913 }
2914
2915 CSR_API(CsrGetConsoleCodePage)
2916 {
2917 PCSRSS_CONSOLE Console;
2918 NTSTATUS Status;
2919
2920 DPRINT("CsrGetConsoleCodePage\n");
2921
2922 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2923 if (! NT_SUCCESS(Status))
2924 {
2925 return Status;
2926 }
2927
2928 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2929 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2930 Request->Data.GetConsoleCodePage.CodePage = Console->CodePage;
2931 ConioUnlockConsole(Console);
2932 return STATUS_SUCCESS;
2933 }
2934
2935 CSR_API(CsrSetConsoleCodePage)
2936 {
2937 PCSRSS_CONSOLE Console;
2938 NTSTATUS Status;
2939
2940 DPRINT("CsrSetConsoleCodePage\n");
2941
2942 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2943 if (! NT_SUCCESS(Status))
2944 {
2945 return Status;
2946 }
2947
2948 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2949 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2950
2951 if (IsValidCodePage(Request->Data.SetConsoleCodePage.CodePage))
2952 {
2953 Console->CodePage = Request->Data.SetConsoleCodePage.CodePage;
2954 ConioUnlockConsole(Console);
2955 return STATUS_SUCCESS;
2956 }
2957
2958 ConioUnlockConsole(Console);
2959 return STATUS_INVALID_PARAMETER;
2960 }
2961
2962 CSR_API(CsrGetConsoleOutputCodePage)
2963 {
2964 PCSRSS_CONSOLE Console;
2965 NTSTATUS Status;
2966
2967 DPRINT("CsrGetConsoleOutputCodePage\n");
2968
2969 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2970 if (! NT_SUCCESS(Status))
2971 {
2972 return Status;
2973 }
2974
2975 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2976 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2977 Request->Data.GetConsoleOutputCodePage.CodePage = Console->OutputCodePage;
2978 ConioUnlockConsole(Console);
2979 return STATUS_SUCCESS;
2980 }
2981
2982 CSR_API(CsrSetConsoleOutputCodePage)
2983 {
2984 PCSRSS_CONSOLE Console;
2985 NTSTATUS Status;
2986
2987 DPRINT("CsrSetConsoleOutputCodePage\n");
2988
2989 Status = ConioConsoleFromProcessData