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