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