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