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