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