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