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