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