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