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