- Work with screen buffer data using pointers rather than offsets; remove confusing...
[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_SCREEN_BUFFER Buff;
1296 PCONSOLE_SCREEN_BUFFER_INFO pInfo;
1297
1298 DPRINT("CsrGetScreenBufferInfo\n");
1299
1300 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1301 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1302
1303 Status = ConioLockScreenBuffer(ProcessData, Request->Data.ScreenBufferInfoRequest.ConsoleHandle, &Buff, GENERIC_READ);
1304 if (! NT_SUCCESS(Status))
1305 {
1306 return Request->Status = Status;
1307 }
1308 pInfo = &Request->Data.ScreenBufferInfoRequest.Info;
1309 pInfo->dwSize.X = Buff->MaxX;
1310 pInfo->dwSize.Y = Buff->MaxY;
1311 pInfo->dwCursorPosition.X = Buff->CurrentX;
1312 pInfo->dwCursorPosition.Y = Buff->CurrentY;
1313 pInfo->wAttributes = Buff->DefaultAttrib;
1314 pInfo->srWindow.Left = 0;
1315 pInfo->srWindow.Right = Buff->MaxX - 1;
1316 pInfo->srWindow.Top = 0;
1317 pInfo->srWindow.Bottom = Buff->MaxY - 1;
1318 pInfo->dwMaximumWindowSize.X = Buff->MaxX;
1319 pInfo->dwMaximumWindowSize.Y = Buff->MaxY;
1320 ConioUnlockScreenBuffer(Buff);
1321
1322 Request->Status = STATUS_SUCCESS;
1323
1324 return Request->Status;
1325 }
1326
1327 CSR_API(CsrSetCursor)
1328 {
1329 NTSTATUS Status;
1330 PCSRSS_CONSOLE Console;
1331 PCSRSS_SCREEN_BUFFER Buff;
1332 LONG OldCursorX, OldCursorY;
1333 LONG NewCursorX, NewCursorY;
1334
1335 DPRINT("CsrSetCursor\n");
1336
1337 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1338 if (! NT_SUCCESS(Status))
1339 {
1340 return Request->Status = Status;
1341 }
1342
1343 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1344 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1345
1346 Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetCursorRequest.ConsoleHandle, &Buff, GENERIC_WRITE);
1347 if (! NT_SUCCESS(Status))
1348 {
1349 ConioUnlockConsole(Console);
1350 return Request->Status = Status;
1351 }
1352
1353 NewCursorX = Request->Data.SetCursorRequest.Position.X;
1354 NewCursorY = Request->Data.SetCursorRequest.Position.Y;
1355 if (NewCursorX < 0 || NewCursorX >= Buff->MaxX ||
1356 NewCursorY < 0 || NewCursorY >= Buff->MaxY)
1357 {
1358 ConioUnlockScreenBuffer(Buff);
1359 ConioUnlockConsole(Console);
1360 return Request->Status = STATUS_INVALID_PARAMETER;
1361 }
1362 OldCursorX = Buff->CurrentX;
1363 OldCursorY = Buff->CurrentY;
1364 Buff->CurrentX = NewCursorX;
1365 Buff->CurrentY = NewCursorY;
1366 if (Buff == Console->ActiveBuffer)
1367 {
1368 if (! ConioSetScreenInfo(Console, Buff, OldCursorX, OldCursorY))
1369 {
1370 ConioUnlockScreenBuffer(Buff);
1371 ConioUnlockConsole(Console);
1372 return Request->Status = STATUS_UNSUCCESSFUL;
1373 }
1374 }
1375
1376 ConioUnlockScreenBuffer(Buff);
1377 ConioUnlockConsole(Console);
1378
1379 return Request->Status = STATUS_SUCCESS;
1380 }
1381
1382 static VOID FASTCALL
1383 ConioComputeUpdateRect(PCSRSS_SCREEN_BUFFER Buff, RECT *UpdateRect, COORD *Start, UINT Length)
1384 {
1385 if (Buff->MaxX <= Start->X + Length)
1386 {
1387 UpdateRect->left = 0;
1388 }
1389 else
1390 {
1391 UpdateRect->left = Start->X;
1392 }
1393 if (Buff->MaxX <= Start->X + Length)
1394 {
1395 UpdateRect->right = Buff->MaxX - 1;
1396 }
1397 else
1398 {
1399 UpdateRect->right = Start->X + Length - 1;
1400 }
1401 UpdateRect->top = Start->Y;
1402 UpdateRect->bottom = Start->Y+ (Start->X + Length - 1) / Buff->MaxX;
1403 if (Buff->MaxY <= UpdateRect->bottom)
1404 {
1405 UpdateRect->bottom = Buff->MaxY - 1;
1406 }
1407 }
1408
1409 CSR_API(CsrWriteConsoleOutputChar)
1410 {
1411 NTSTATUS Status;
1412 PCHAR String, tmpString = NULL;
1413 PBYTE Buffer;
1414 PCSRSS_CONSOLE Console;
1415 PCSRSS_SCREEN_BUFFER Buff;
1416 DWORD X, Y, Length, CharSize, Written = 0;
1417 RECT UpdateRect;
1418
1419 DPRINT("CsrWriteConsoleOutputChar\n");
1420
1421 CharSize = (Request->Data.WriteConsoleOutputCharRequest.Unicode ? sizeof(WCHAR) : sizeof(CHAR));
1422
1423 if (Request->Header.u1.s1.TotalLength
1424 < CSR_API_MESSAGE_HEADER_SIZE(CSRSS_WRITE_CONSOLE_OUTPUT_CHAR)
1425 + (Request->Data.WriteConsoleOutputCharRequest.Length * CharSize))
1426 {
1427 DPRINT1("Invalid request size\n");
1428 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1429 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1430 return Request->Status = STATUS_INVALID_PARAMETER;
1431 }
1432
1433 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1434 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1435 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1436 if (NT_SUCCESS(Status))
1437 {
1438 if(Request->Data.WriteConsoleOutputCharRequest.Unicode)
1439 {
1440 Length = WideCharToMultiByte(Console->OutputCodePage, 0,
1441 (PWCHAR)Request->Data.WriteConsoleOutputCharRequest.String,
1442 Request->Data.WriteConsoleOutputCharRequest.Length,
1443 NULL, 0, NULL, NULL);
1444 tmpString = String = RtlAllocateHeap(GetProcessHeap(), 0, Length);
1445 if (String)
1446 {
1447 WideCharToMultiByte(Console->OutputCodePage, 0,
1448 (PWCHAR)Request->Data.WriteConsoleOutputCharRequest.String,
1449 Request->Data.WriteConsoleOutputCharRequest.Length,
1450 String, Length, NULL, NULL);
1451 }
1452 else
1453 {
1454 Status = STATUS_NO_MEMORY;
1455 }
1456 }
1457 else
1458 {
1459 String = (PCHAR)Request->Data.WriteConsoleOutputCharRequest.String;
1460 }
1461
1462 if (String)
1463 {
1464 Status = ConioLockScreenBuffer(ProcessData,
1465 Request->Data.WriteConsoleOutputCharRequest.ConsoleHandle,
1466 &Buff,
1467 GENERIC_WRITE);
1468 if (NT_SUCCESS(Status))
1469 {
1470 X = Request->Data.WriteConsoleOutputCharRequest.Coord.X;
1471 Y = (Request->Data.WriteConsoleOutputCharRequest.Coord.Y + Buff->VirtualY) % Buff->MaxY;
1472 Length = Request->Data.WriteConsoleOutputCharRequest.Length;
1473 Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X)];
1474 while (Length--)
1475 {
1476 *Buffer = *String++;
1477 Written++;
1478 Buffer += 2;
1479 if (++X == Buff->MaxX)
1480 {
1481 if (++Y == Buff->MaxY)
1482 {
1483 Y = 0;
1484 Buffer = Buff->Buffer;
1485 }
1486 X = 0;
1487 }
1488 }
1489 if (Buff == Console->ActiveBuffer)
1490 {
1491 ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.WriteConsoleOutputCharRequest.Coord,
1492 Request->Data.WriteConsoleOutputCharRequest.Length);
1493 ConioDrawRegion(Console, &UpdateRect);
1494 }
1495
1496 Request->Data.WriteConsoleOutputCharRequest.EndCoord.X = X;
1497 Request->Data.WriteConsoleOutputCharRequest.EndCoord.Y = (Y + Buff->MaxY - Buff->VirtualY) % Buff->MaxY;
1498
1499 ConioUnlockScreenBuffer(Buff);
1500 }
1501 if (Request->Data.WriteConsoleRequest.Unicode)
1502 {
1503 RtlFreeHeap(GetProcessHeap(), 0, tmpString);
1504 }
1505 }
1506 ConioUnlockConsole(Console);
1507 }
1508 Request->Data.WriteConsoleOutputCharRequest.NrCharactersWritten = Written;
1509 return Request->Status = Status;
1510 }
1511
1512 CSR_API(CsrFillOutputChar)
1513 {
1514 NTSTATUS Status;
1515 PCSRSS_CONSOLE Console;
1516 PCSRSS_SCREEN_BUFFER Buff;
1517 DWORD X, Y, Length, Written = 0;
1518 CHAR Char;
1519 PBYTE Buffer;
1520 RECT UpdateRect;
1521
1522 DPRINT("CsrFillOutputChar\n");
1523
1524 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1525 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1526
1527 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1528 if (! NT_SUCCESS(Status))
1529 {
1530 return Request->Status = Status;
1531 }
1532
1533 Status = ConioLockScreenBuffer(ProcessData, Request->Data.FillOutputRequest.ConsoleHandle, &Buff, GENERIC_WRITE);
1534 if (! NT_SUCCESS(Status))
1535 {
1536 ConioUnlockConsole(Console);
1537 return Request->Status = Status;
1538 }
1539
1540 X = Request->Data.FillOutputRequest.Position.X;
1541 Y = (Request->Data.FillOutputRequest.Position.Y + Buff->VirtualY) % Buff->MaxY;
1542 Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X)];
1543 if(Request->Data.FillOutputRequest.Unicode)
1544 ConsoleUnicodeCharToAnsiChar(Console, &Char, &Request->Data.FillOutputRequest.Char.UnicodeChar);
1545 else
1546 Char = Request->Data.FillOutputRequest.Char.AsciiChar;
1547 Length = Request->Data.FillOutputRequest.Length;
1548 while (Length--)
1549 {
1550 *Buffer = Char;
1551 Buffer += 2;
1552 Written++;
1553 if (++X == Buff->MaxX)
1554 {
1555 if (++Y == Buff->MaxY)
1556 {
1557 Y = 0;
1558 Buffer = Buff->Buffer;
1559 }
1560 X = 0;
1561 }
1562 }
1563
1564 if (Buff == Console->ActiveBuffer)
1565 {
1566 ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.FillOutputRequest.Position,
1567 Request->Data.FillOutputRequest.Length);
1568 ConioDrawRegion(Console, &UpdateRect);
1569 }
1570
1571 ConioUnlockScreenBuffer(Buff);
1572 ConioUnlockConsole(Console);
1573 Length = Request->Data.FillOutputRequest.Length;
1574 Request->Data.FillOutputRequest.NrCharactersWritten = Length;
1575 return Request->Status;
1576 }
1577
1578 CSR_API(CsrReadInputEvent)
1579 {
1580 PLIST_ENTRY CurrentEntry;
1581 PCSRSS_CONSOLE Console;
1582 NTSTATUS Status;
1583 BOOLEAN Done = FALSE;
1584 ConsoleInput *Input;
1585
1586 DPRINT("CsrReadInputEvent\n");
1587
1588 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1589 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1590 Request->Data.ReadInputRequest.Event = ProcessData->ConsoleEvent;
1591
1592 Status = ConioLockConsole(ProcessData, Request->Data.ReadInputRequest.ConsoleHandle, &Console, GENERIC_READ);
1593 if (! NT_SUCCESS(Status))
1594 {
1595 return Request->Status = Status;
1596 }
1597
1598 /* only get input if there is any */
1599 CurrentEntry = Console->InputEvents.Flink;
1600 while (CurrentEntry != &Console->InputEvents)
1601 {
1602 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
1603 CurrentEntry = CurrentEntry->Flink;
1604
1605 if (Done && !Input->Fake)
1606 {
1607 Request->Data.ReadInputRequest.MoreEvents = TRUE;
1608 break;
1609 }
1610
1611 RemoveEntryList(&Input->ListEntry);
1612
1613 if (!Done && !Input->Fake)
1614 {
1615 Request->Data.ReadInputRequest.Input = Input->InputEvent;
1616 if (Request->Data.ReadInputRequest.Unicode == FALSE)
1617 {
1618 ConioInputEventToAnsi(Console, &Request->Data.ReadInputRequest.Input);
1619 }
1620 Done = TRUE;
1621 }
1622
1623 if (Input->InputEvent.EventType == KEY_EVENT)
1624 {
1625 if (0 != (Console->Mode & ENABLE_LINE_INPUT)
1626 && Input->InputEvent.Event.KeyEvent.bKeyDown
1627 && '\r' == Input->InputEvent.Event.KeyEvent.uChar.AsciiChar)
1628 {
1629 Console->WaitingLines--;
1630 }
1631 Console->WaitingChars--;
1632 }
1633 HeapFree(Win32CsrApiHeap, 0, Input);
1634 }
1635
1636 if (Done)
1637 {
1638 Status = STATUS_SUCCESS;
1639 Console->EarlyReturn = FALSE;
1640 }
1641 else
1642 {
1643 Status = STATUS_PENDING;
1644 Console->EarlyReturn = TRUE; /* mark for early return */
1645 }
1646
1647 if (IsListEmpty(&Console->InputEvents))
1648 {
1649 ResetEvent(Console->ActiveEvent);
1650 }
1651
1652 ConioUnlockConsole(Console);
1653
1654 return Request->Status = Status;
1655 }
1656
1657 CSR_API(CsrWriteConsoleOutputAttrib)
1658 {
1659 PCSRSS_CONSOLE Console;
1660 PCSRSS_SCREEN_BUFFER Buff;
1661 PUCHAR Buffer;
1662 PWORD Attribute;
1663 int X, Y, Length;
1664 NTSTATUS Status;
1665 RECT UpdateRect;
1666
1667 DPRINT("CsrWriteConsoleOutputAttrib\n");
1668
1669 if (Request->Header.u1.s1.TotalLength
1670 < CSR_API_MESSAGE_HEADER_SIZE(CSRSS_WRITE_CONSOLE_OUTPUT_ATTRIB)
1671 + Request->Data.WriteConsoleOutputAttribRequest.Length * sizeof(WORD))
1672 {
1673 DPRINT1("Invalid request size\n");
1674 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1675 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1676 return Request->Status = STATUS_INVALID_PARAMETER;
1677 }
1678
1679 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1680 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1681 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1682 if (! NT_SUCCESS(Status))
1683 {
1684 return Request->Status = Status;
1685 }
1686
1687 Status = ConioLockScreenBuffer(ProcessData,
1688 Request->Data.WriteConsoleOutputAttribRequest.ConsoleHandle,
1689 &Buff,
1690 GENERIC_WRITE);
1691 if (! NT_SUCCESS(Status))
1692 {
1693 ConioUnlockConsole(Console);
1694 return Request->Status = Status;
1695 }
1696
1697 X = Request->Data.WriteConsoleOutputAttribRequest.Coord.X;
1698 Y = (Request->Data.WriteConsoleOutputAttribRequest.Coord.Y + Buff->VirtualY) % Buff->MaxY;
1699 Length = Request->Data.WriteConsoleOutputAttribRequest.Length;
1700 Buffer = &Buff->Buffer[2 * (Y * Buff->MaxX + X) + 1];
1701 Attribute = Request->Data.WriteConsoleOutputAttribRequest.Attribute;
1702 while (Length--)
1703 {
1704 *Buffer = (UCHAR)(*Attribute++);
1705 Buffer += 2;
1706 if (++X == Buff->MaxX)
1707 {
1708 if (++Y == Buff->MaxY)
1709 {
1710 Y = 0;
1711 Buffer = Buff->Buffer + 1;
1712 }
1713 X = 0;
1714 }
1715 }
1716
1717 if (Buff == Console->ActiveBuffer)
1718 {
1719 ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.WriteConsoleOutputAttribRequest.Coord,
1720 Request->Data.WriteConsoleOutputAttribRequest.Length);
1721 ConioDrawRegion(Console, &UpdateRect);
1722 }
1723
1724 ConioUnlockConsole(Console);
1725
1726 Request->Data.WriteConsoleOutputAttribRequest.EndCoord.X = X;
1727 Request->Data.WriteConsoleOutputAttribRequest.EndCoord.Y = (Y + Buff->MaxY - Buff->VirtualY) % Buff->MaxY;
1728
1729 ConioUnlockScreenBuffer(Buff);
1730
1731 return Request->Status = STATUS_SUCCESS;
1732 }
1733
1734 CSR_API(CsrFillOutputAttrib)
1735 {
1736 PCSRSS_SCREEN_BUFFER Buff;
1737 PUCHAR Buffer;
1738 NTSTATUS Status;
1739 int X, Y, Length;
1740 UCHAR Attr;
1741 RECT UpdateRect;
1742 PCSRSS_CONSOLE Console;
1743
1744 DPRINT("CsrFillOutputAttrib\n");
1745
1746 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1747 if (! NT_SUCCESS(Status))
1748 {
1749 return Request->Status = Status;
1750 }
1751
1752 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1753 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1754 Status = ConioLockScreenBuffer(ProcessData, Request->Data.FillOutputAttribRequest.ConsoleHandle, &Buff, GENERIC_WRITE);
1755 if (! NT_SUCCESS(Status))
1756 {
1757 ConioUnlockConsole(Console);
1758 return Request->Status = Status;
1759 }
1760
1761 X = Request->Data.FillOutputAttribRequest.Coord.X;
1762 Y = (Request->Data.FillOutputAttribRequest.Coord.Y + Buff->VirtualY) % Buff->MaxY;
1763 Length = Request->Data.FillOutputAttribRequest.Length;
1764 Attr = Request->Data.FillOutputAttribRequest.Attribute;
1765 Buffer = &Buff->Buffer[(Y * Buff->MaxX * 2) + (X * 2) + 1];
1766 while (Length--)
1767 {
1768 *Buffer = Attr;
1769 Buffer += 2;
1770 if (++X == Buff->MaxX)
1771 {
1772 if (++Y == Buff->MaxY)
1773 {
1774 Y = 0;
1775 Buffer = Buff->Buffer + 1;
1776 }
1777 X = 0;
1778 }
1779 }
1780
1781 if (Buff == Console->ActiveBuffer)
1782 {
1783 ConioComputeUpdateRect(Buff, &UpdateRect, &Request->Data.FillOutputAttribRequest.Coord,
1784 Request->Data.FillOutputAttribRequest.Length);
1785 ConioDrawRegion(Console, &UpdateRect);
1786 }
1787
1788 ConioUnlockScreenBuffer(Buff);
1789 ConioUnlockConsole(Console);
1790
1791 return Request->Status = STATUS_SUCCESS;
1792 }
1793
1794
1795 CSR_API(CsrGetCursorInfo)
1796 {
1797 PCSRSS_SCREEN_BUFFER Buff;
1798 NTSTATUS Status;
1799
1800 DPRINT("CsrGetCursorInfo\n");
1801
1802 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1803 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1804
1805 Status = ConioLockScreenBuffer(ProcessData, Request->Data.GetCursorInfoRequest.ConsoleHandle, &Buff, GENERIC_READ);
1806 if (! NT_SUCCESS(Status))
1807 {
1808 return Request->Status = Status;
1809 }
1810 Request->Data.GetCursorInfoRequest.Info.bVisible = Buff->CursorInfo.bVisible;
1811 Request->Data.GetCursorInfoRequest.Info.dwSize = Buff->CursorInfo.dwSize;
1812 ConioUnlockScreenBuffer(Buff);
1813
1814 return Request->Status = STATUS_SUCCESS;
1815 }
1816
1817 CSR_API(CsrSetCursorInfo)
1818 {
1819 PCSRSS_CONSOLE Console;
1820 PCSRSS_SCREEN_BUFFER Buff;
1821 DWORD Size;
1822 BOOL Visible;
1823 NTSTATUS Status;
1824
1825 DPRINT("CsrSetCursorInfo\n");
1826
1827 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1828 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1829
1830 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1831 if (! NT_SUCCESS(Status))
1832 {
1833 return Request->Status = Status;
1834 }
1835
1836 Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetCursorInfoRequest.ConsoleHandle, &Buff, GENERIC_WRITE);
1837 if (! NT_SUCCESS(Status))
1838 {
1839 ConioUnlockConsole(Console);
1840 return Request->Status = Status;
1841 }
1842
1843 Size = Request->Data.SetCursorInfoRequest.Info.dwSize;
1844 Visible = Request->Data.SetCursorInfoRequest.Info.bVisible;
1845 if (Size < 1)
1846 {
1847 Size = 1;
1848 }
1849 if (100 < Size)
1850 {
1851 Size = 100;
1852 }
1853
1854 if (Size != Buff->CursorInfo.dwSize
1855 || (Visible && ! Buff->CursorInfo.bVisible) || (! Visible && Buff->CursorInfo.bVisible))
1856 {
1857 Buff->CursorInfo.dwSize = Size;
1858 Buff->CursorInfo.bVisible = Visible;
1859
1860 if (! ConioSetCursorInfo(Console, Buff))
1861 {
1862 ConioUnlockScreenBuffer(Buff);
1863 ConioUnlockConsole(Console);
1864 return Request->Status = STATUS_UNSUCCESSFUL;
1865 }
1866 }
1867
1868 ConioUnlockScreenBuffer(Buff);
1869 ConioUnlockConsole(Console);
1870
1871 return Request->Status = STATUS_SUCCESS;
1872 }
1873
1874 CSR_API(CsrSetTextAttrib)
1875 {
1876 NTSTATUS Status;
1877 PCSRSS_CONSOLE Console;
1878 PCSRSS_SCREEN_BUFFER Buff;
1879
1880 DPRINT("CsrSetTextAttrib\n");
1881
1882 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1883 if (! NT_SUCCESS(Status))
1884 {
1885 return Request->Status = Status;
1886 }
1887
1888 Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetCursorRequest.ConsoleHandle, &Buff, GENERIC_WRITE);
1889 if (! NT_SUCCESS(Status))
1890 {
1891 ConioUnlockConsole(Console);
1892 return Request->Status = Status;
1893 }
1894
1895 Buff->DefaultAttrib = Request->Data.SetAttribRequest.Attrib;
1896 if (Buff == Console->ActiveBuffer)
1897 {
1898 if (! ConioUpdateScreenInfo(Console, Buff))
1899 {
1900 ConioUnlockScreenBuffer(Buff);
1901 ConioUnlockConsole(Console);
1902 return Request->Status = STATUS_UNSUCCESSFUL;
1903 }
1904 }
1905
1906 ConioUnlockScreenBuffer(Buff);
1907 ConioUnlockConsole(Console);
1908
1909 return Request->Status = STATUS_SUCCESS;
1910 }
1911
1912 CSR_API(CsrSetConsoleMode)
1913 {
1914 NTSTATUS Status;
1915 PCSRSS_CONSOLE Console;
1916 PCSRSS_SCREEN_BUFFER Buff;
1917
1918 DPRINT("CsrSetConsoleMode\n");
1919
1920 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1921 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1922 Status = Win32CsrGetObject(ProcessData,
1923 Request->Data.SetConsoleModeRequest.ConsoleHandle,
1924 (Object_t **) &Console, GENERIC_WRITE);
1925 if (! NT_SUCCESS(Status))
1926 {
1927 return Request->Status = Status;
1928 }
1929
1930 Buff = (PCSRSS_SCREEN_BUFFER)Console;
1931 if (CONIO_CONSOLE_MAGIC == Console->Header.Type)
1932 {
1933 Console->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_INPUT_MODE_VALID;
1934 }
1935 else if (CONIO_SCREEN_BUFFER_MAGIC == Console->Header.Type)
1936 {
1937 Buff->Mode = Request->Data.SetConsoleModeRequest.Mode & CONSOLE_OUTPUT_MODE_VALID;
1938 }
1939 else
1940 {
1941 Status = STATUS_INVALID_HANDLE;
1942 }
1943
1944 Win32CsrReleaseObjectByPointer((Object_t *)Console);
1945
1946 return Request->Status = Status;
1947 }
1948
1949 CSR_API(CsrGetConsoleMode)
1950 {
1951 NTSTATUS Status;
1952 PCSRSS_CONSOLE Console;
1953 PCSRSS_SCREEN_BUFFER Buff; /* gee, I really wish I could use an anonymous union here */
1954
1955 DPRINT("CsrGetConsoleMode\n");
1956
1957 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1958 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1959 Status = Win32CsrGetObject(ProcessData, Request->Data.GetConsoleModeRequest.ConsoleHandle,
1960 (Object_t **) &Console, GENERIC_READ);
1961 if (! NT_SUCCESS(Status))
1962 {
1963 return Request->Status = Status;
1964 }
1965 Request->Status = STATUS_SUCCESS;
1966 Buff = (PCSRSS_SCREEN_BUFFER) Console;
1967 if (CONIO_CONSOLE_MAGIC == Console->Header.Type)
1968 {
1969 Request->Data.GetConsoleModeRequest.ConsoleMode = Console->Mode;
1970 }
1971 else if (CONIO_SCREEN_BUFFER_MAGIC == Buff->Header.Type)
1972 {
1973 Request->Data.GetConsoleModeRequest.ConsoleMode = Buff->Mode;
1974 }
1975 else
1976 {
1977 Request->Status = STATUS_INVALID_HANDLE;
1978 }
1979
1980 Win32CsrReleaseObjectByPointer((Object_t *)Console);
1981 return Request->Status;
1982 }
1983
1984 CSR_API(CsrCreateScreenBuffer)
1985 {
1986 PCSRSS_CONSOLE Console;
1987 PCSRSS_SCREEN_BUFFER Buff;
1988 NTSTATUS Status;
1989
1990 DPRINT("CsrCreateScreenBuffer\n");
1991
1992 if (ProcessData == NULL)
1993 {
1994 return Request->Status = STATUS_INVALID_PARAMETER;
1995 }
1996
1997 Status = ConioConsoleFromProcessData(ProcessData, &Console);
1998 if (! NT_SUCCESS(Status))
1999 {
2000 return Request->Status = Status;
2001 }
2002
2003 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2004 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2005
2006 Buff = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY, sizeof(CSRSS_SCREEN_BUFFER));
2007
2008 if (Buff != NULL)
2009 {
2010 if (Console->ActiveBuffer)
2011 {
2012 Buff->MaxX = Console->ActiveBuffer->MaxX;
2013 Buff->MaxY = Console->ActiveBuffer->MaxY;
2014 Buff->CursorInfo.bVisible = Console->ActiveBuffer->CursorInfo.bVisible;
2015 Buff->CursorInfo.dwSize = Console->ActiveBuffer->CursorInfo.dwSize;
2016 }
2017 else
2018 {
2019 Buff->CursorInfo.bVisible = TRUE;
2020 Buff->CursorInfo.dwSize = 5;
2021 }
2022
2023 if (Buff->MaxX == 0)
2024 {
2025 Buff->MaxX = 80;
2026 }
2027
2028 if (Buff->MaxY == 0)
2029 {
2030 Buff->MaxY = 25;
2031 }
2032
2033 Status = CsrInitConsoleScreenBuffer(Console, Buff);
2034 if(! NT_SUCCESS(Status))
2035 {
2036 Request->Status = Status;
2037 }
2038 else
2039 {
2040 Request->Status = Win32CsrInsertObject(ProcessData,
2041 &Request->Data.CreateScreenBufferRequest.OutputHandle,
2042 &Buff->Header,
2043 Request->Data.CreateScreenBufferRequest.Access,
2044 Request->Data.CreateScreenBufferRequest.Inheritable);
2045 }
2046 }
2047 else
2048 {
2049 Request->Status = STATUS_INSUFFICIENT_RESOURCES;
2050 }
2051
2052 ConioUnlockConsole(Console);
2053 return Request->Status;
2054 }
2055
2056 CSR_API(CsrSetScreenBuffer)
2057 {
2058 NTSTATUS Status;
2059 PCSRSS_CONSOLE Console;
2060 PCSRSS_SCREEN_BUFFER Buff;
2061
2062 DPRINT("CsrSetScreenBuffer\n");
2063
2064 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2065 if (! NT_SUCCESS(Status))
2066 {
2067 return Request->Status = Status;
2068 }
2069
2070 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2071 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2072
2073 Status = ConioLockScreenBuffer(ProcessData, Request->Data.SetScreenBufferRequest.OutputHandle, &Buff, GENERIC_WRITE);
2074 if (! NT_SUCCESS(Status))
2075 {
2076 ConioUnlockConsole(Console);
2077 return Request->Status = Status;
2078 }
2079
2080 if (Buff == Console->ActiveBuffer)
2081 {
2082 ConioUnlockScreenBuffer(Buff);
2083 ConioUnlockConsole(Console);
2084 return Request->Status = STATUS_SUCCESS;
2085 }
2086
2087 /* drop reference to old buffer, maybe delete */
2088 if (! InterlockedDecrement(&Console->ActiveBuffer->Header.ReferenceCount))
2089 {
2090 ConioDeleteScreenBuffer((Object_t *) Console->ActiveBuffer);
2091 }
2092 /* tie console to new buffer */
2093 Console->ActiveBuffer = Buff;
2094 /* inc ref count on new buffer */
2095 InterlockedIncrement(&Buff->Header.ReferenceCount);
2096 /* Redraw the console */
2097 ConioDrawConsole(Console);
2098
2099 ConioUnlockScreenBuffer(Buff);
2100 ConioUnlockConsole(Console);
2101
2102 return Request->Status = STATUS_SUCCESS;
2103 }
2104
2105 CSR_API(CsrSetTitle)
2106 {
2107 NTSTATUS Status;
2108 PCSRSS_CONSOLE Console;
2109 PWCHAR Buffer;
2110
2111 DPRINT("CsrSetTitle\n");
2112
2113 if (Request->Header.u1.s1.TotalLength
2114 < CSR_API_MESSAGE_HEADER_SIZE(CSRSS_SET_TITLE)
2115 + Request->Data.SetTitleRequest.Length)
2116 {
2117 DPRINT1("Invalid request size\n");
2118 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2119 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2120 return Request->Status = STATUS_INVALID_PARAMETER;
2121 }
2122
2123 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2124 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2125 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2126 if(! NT_SUCCESS(Status))
2127 {
2128 Request->Status = Status;
2129 }
2130 else
2131 {
2132 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Request->Data.SetTitleRequest.Length);
2133 if (Buffer)
2134 {
2135 /* copy title to console */
2136 RtlFreeUnicodeString(&Console->Title);
2137 Console->Title.Buffer = Buffer;
2138 Console->Title.Length = Console->Title.MaximumLength = Request->Data.SetTitleRequest.Length;
2139 memcpy(Console->Title.Buffer, Request->Data.SetTitleRequest.Title, Console->Title.Length);
2140 if (! ConioChangeTitle(Console))
2141 {
2142 Request->Status = STATUS_UNSUCCESSFUL;
2143 }
2144 else
2145 {
2146 Request->Status = STATUS_SUCCESS;
2147 }
2148 }
2149 else
2150 {
2151 Request->Status = STATUS_NO_MEMORY;
2152 }
2153 ConioUnlockConsole(Console);
2154 }
2155
2156 return Request->Status;
2157 }
2158
2159 CSR_API(CsrGetTitle)
2160 {
2161 NTSTATUS Status;
2162 PCSRSS_CONSOLE Console;
2163 DWORD Length;
2164
2165 DPRINT("CsrGetTitle\n");
2166
2167 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2168 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2169 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2170 if (! NT_SUCCESS(Status))
2171 {
2172 DPRINT1("Can't get console\n");
2173 return Request->Status = Status;
2174 }
2175
2176 /* Copy title of the console to the user title buffer */
2177 RtlZeroMemory(&Request->Data.GetTitleRequest, sizeof(CSRSS_GET_TITLE));
2178 Request->Data.GetTitleRequest.Length = Console->Title.Length;
2179 memcpy (Request->Data.GetTitleRequest.Title, Console->Title.Buffer,
2180 Console->Title.Length);
2181 Length = CSR_API_MESSAGE_HEADER_SIZE(CSRSS_SET_TITLE) + Console->Title.Length;
2182
2183 ConioUnlockConsole(Console);
2184
2185 if (Length > sizeof(CSR_API_MESSAGE))
2186 {
2187 Request->Header.u1.s1.TotalLength = Length;
2188 Request->Header.u1.s1.DataLength = Length - sizeof(PORT_MESSAGE);
2189 }
2190 Request->Status = STATUS_SUCCESS;
2191
2192 return Request->Status;
2193 }
2194
2195 CSR_API(CsrWriteConsoleOutput)
2196 {
2197 SHORT i, X, Y, SizeX, SizeY;
2198 PCSRSS_CONSOLE Console;
2199 PCSRSS_SCREEN_BUFFER Buff;
2200 RECT ScreenBuffer;
2201 CHAR_INFO* CurCharInfo;
2202 RECT WriteRegion;
2203 CHAR_INFO* CharInfo;
2204 COORD BufferCoord;
2205 COORD BufferSize;
2206 NTSTATUS Status;
2207 PBYTE Ptr;
2208 DWORD PSize;
2209
2210 DPRINT("CsrWriteConsoleOutput\n");
2211
2212 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2213 if (! NT_SUCCESS(Status))
2214 {
2215 return Request->Status = Status;
2216 }
2217
2218 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2219 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2220 Status = ConioLockScreenBuffer(ProcessData,
2221 Request->Data.WriteConsoleOutputRequest.ConsoleHandle,
2222 &Buff,
2223 GENERIC_WRITE);
2224 if (! NT_SUCCESS(Status))
2225 {
2226 ConioUnlockConsole(Console);
2227 return Request->Status = Status;
2228 }
2229
2230 BufferSize = Request->Data.WriteConsoleOutputRequest.BufferSize;
2231 PSize = BufferSize.X * BufferSize.Y * sizeof(CHAR_INFO);
2232 BufferCoord = Request->Data.WriteConsoleOutputRequest.BufferCoord;
2233 CharInfo = Request->Data.WriteConsoleOutputRequest.CharInfo;
2234 if (((PVOID)CharInfo < ProcessData->CsrSectionViewBase) ||
2235 (((ULONG_PTR)CharInfo + PSize) >
2236 ((ULONG_PTR)ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2237 {
2238 ConioUnlockScreenBuffer(Buff);
2239 ConioUnlockConsole(Console);
2240 return Request->Status = STATUS_ACCESS_VIOLATION;
2241 }
2242 WriteRegion.left = Request->Data.WriteConsoleOutputRequest.WriteRegion.Left;
2243 WriteRegion.top = Request->Data.WriteConsoleOutputRequest.WriteRegion.Top;
2244 WriteRegion.right = Request->Data.WriteConsoleOutputRequest.WriteRegion.Right;
2245 WriteRegion.bottom = Request->Data.WriteConsoleOutputRequest.WriteRegion.Bottom;
2246
2247 SizeY = min(BufferSize.Y - BufferCoord.Y, ConioRectHeight(&WriteRegion));
2248 SizeX = min(BufferSize.X - BufferCoord.X, ConioRectWidth(&WriteRegion));
2249 WriteRegion.bottom = WriteRegion.top + SizeY - 1;
2250 WriteRegion.right = WriteRegion.left + SizeX - 1;
2251
2252 /* Make sure WriteRegion is inside the screen buffer */
2253 ConioInitRect(&ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
2254 if (! ConioGetIntersection(&WriteRegion, &ScreenBuffer, &WriteRegion))
2255 {
2256 ConioUnlockScreenBuffer(Buff);
2257 ConioUnlockConsole(Console);
2258
2259 /* It is okay to have a WriteRegion completely outside the screen buffer.
2260 No data is written then. */
2261 return Request->Status = STATUS_SUCCESS;
2262 }
2263
2264 for (i = 0, Y = WriteRegion.top; Y <= WriteRegion.bottom; i++, Y++)
2265 {
2266 CurCharInfo = CharInfo + (i + BufferCoord.Y) * BufferSize.X + BufferCoord.X;
2267 Ptr = ConioCoordToPointer(Buff, WriteRegion.left, Y);
2268 for (X = WriteRegion.left; X <= WriteRegion.right; X++)
2269 {
2270 CHAR AsciiChar;
2271 if (Request->Data.WriteConsoleOutputRequest.Unicode)
2272 {
2273 ConsoleUnicodeCharToAnsiChar(Console, &AsciiChar, &CurCharInfo->Char.UnicodeChar);
2274 }
2275 else
2276 {
2277 AsciiChar = CurCharInfo->Char.AsciiChar;
2278 }
2279 *Ptr++ = AsciiChar;
2280 *Ptr++ = CurCharInfo->Attributes;
2281 CurCharInfo++;
2282 }
2283 }
2284
2285 ConioDrawRegion(Console, &WriteRegion);
2286
2287 ConioUnlockScreenBuffer(Buff);
2288 ConioUnlockConsole(Console);
2289
2290 Request->Data.WriteConsoleOutputRequest.WriteRegion.Right = WriteRegion.left + SizeX - 1;
2291 Request->Data.WriteConsoleOutputRequest.WriteRegion.Bottom = WriteRegion.top + SizeY - 1;
2292 Request->Data.WriteConsoleOutputRequest.WriteRegion.Left = WriteRegion.left;
2293 Request->Data.WriteConsoleOutputRequest.WriteRegion.Top = WriteRegion.top;
2294
2295 return Request->Status = STATUS_SUCCESS;
2296 }
2297
2298 CSR_API(CsrFlushInputBuffer)
2299 {
2300 PLIST_ENTRY CurrentEntry;
2301 PCSRSS_CONSOLE Console;
2302 ConsoleInput* Input;
2303 NTSTATUS Status;
2304
2305 DPRINT("CsrFlushInputBuffer\n");
2306
2307 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2308 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2309 Status = ConioLockConsole(ProcessData,
2310 Request->Data.FlushInputBufferRequest.ConsoleInput,
2311 &Console,
2312 GENERIC_WRITE);
2313 if(! NT_SUCCESS(Status))
2314 {
2315 return Request->Status = Status;
2316 }
2317
2318 /* Discard all entries in the input event queue */
2319 while (!IsListEmpty(&Console->InputEvents))
2320 {
2321 CurrentEntry = RemoveHeadList(&Console->InputEvents);
2322 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
2323 /* Destroy the event */
2324 HeapFree(Win32CsrApiHeap, 0, Input);
2325 }
2326 ResetEvent(Console->ActiveEvent);
2327 Console->WaitingChars=0;
2328
2329 ConioUnlockConsole(Console);
2330
2331 return Request->Status = STATUS_SUCCESS;
2332 }
2333
2334 CSR_API(CsrScrollConsoleScreenBuffer)
2335 {
2336 PCSRSS_CONSOLE Console;
2337 PCSRSS_SCREEN_BUFFER Buff;
2338 RECT ScreenBuffer;
2339 RECT SrcRegion;
2340 RECT DstRegion;
2341 RECT UpdateRegion;
2342 RECT ScrollRectangle;
2343 RECT ClipRectangle;
2344 NTSTATUS Status;
2345 HANDLE ConsoleHandle;
2346 BOOLEAN UseClipRectangle;
2347 COORD DestinationOrigin;
2348 CHAR_INFO Fill;
2349 CHAR FillChar;
2350
2351 DPRINT("CsrScrollConsoleScreenBuffer\n");
2352
2353 ConsoleHandle = Request->Data.ScrollConsoleScreenBufferRequest.ConsoleHandle;
2354 UseClipRectangle = Request->Data.ScrollConsoleScreenBufferRequest.UseClipRectangle;
2355 DestinationOrigin = Request->Data.ScrollConsoleScreenBufferRequest.DestinationOrigin;
2356 Fill = Request->Data.ScrollConsoleScreenBufferRequest.Fill;
2357
2358 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2359 if (! NT_SUCCESS(Status))
2360 {
2361 return Request->Status = Status;
2362 }
2363
2364 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2365 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2366 Status = ConioLockScreenBuffer(ProcessData, ConsoleHandle, &Buff, GENERIC_WRITE);
2367 if (! NT_SUCCESS(Status))
2368 {
2369 ConioUnlockConsole(Console);
2370 return Request->Status = Status;
2371 }
2372
2373 ScrollRectangle.left = Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle.Left;
2374 ScrollRectangle.top = Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle.Top;
2375 ScrollRectangle.right = Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle.Right;
2376 ScrollRectangle.bottom = Request->Data.ScrollConsoleScreenBufferRequest.ScrollRectangle.Bottom;
2377
2378 /* Make sure source rectangle is inside the screen buffer */
2379 ConioInitRect(&ScreenBuffer, 0, 0, Buff->MaxY - 1, Buff->MaxX - 1);
2380 if (! ConioGetIntersection(&SrcRegion, &ScreenBuffer, &ScrollRectangle))
2381 {
2382 ConioUnlockScreenBuffer(Buff);
2383 ConioUnlockConsole(Console);
2384 return Request->Status = STATUS_SUCCESS;
2385 }
2386
2387 /* If the source was clipped on the left or top, adjust the destination accordingly */
2388 if (ScrollRectangle.left < 0)
2389 {
2390 DestinationOrigin.X -= ScrollRectangle.left;
2391 }
2392 if (ScrollRectangle.top < 0)
2393 {
2394 DestinationOrigin.Y -= ScrollRectangle.top;
2395 }
2396
2397 if (UseClipRectangle)
2398 {
2399 ClipRectangle.left = Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle.Left;
2400 ClipRectangle.top = Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle.Top;
2401 ClipRectangle.right = Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle.Right;
2402 ClipRectangle.bottom = Request->Data.ScrollConsoleScreenBufferRequest.ClipRectangle.Bottom;
2403 if (!ConioGetIntersection(&ClipRectangle, &ClipRectangle, &ScreenBuffer))
2404 {
2405 ConioUnlockConsole(Console);
2406 ConioUnlockScreenBuffer(Buff);
2407 return Request->Status = STATUS_SUCCESS;
2408 }
2409 }
2410 else
2411 {
2412 ClipRectangle = ScreenBuffer;
2413 }
2414
2415 ConioInitRect(&DstRegion,
2416 DestinationOrigin.Y,
2417 DestinationOrigin.X,
2418 DestinationOrigin.Y + ConioRectHeight(&SrcRegion) - 1,
2419 DestinationOrigin.X + ConioRectWidth(&SrcRegion) - 1);
2420
2421 if (Request->Data.ScrollConsoleScreenBufferRequest.Unicode)
2422 ConsoleUnicodeCharToAnsiChar(Console, &FillChar, &Fill.Char.UnicodeChar);
2423 else
2424 FillChar = Fill.Char.AsciiChar;
2425
2426 ConioMoveRegion(Buff, &SrcRegion, &DstRegion, &ClipRectangle, Fill.Attributes << 8 | (BYTE)FillChar);
2427
2428 if (Buff == Console->ActiveBuffer)
2429 {
2430 ConioGetUnion(&UpdateRegion, &SrcRegion, &DstRegion);
2431 if (ConioGetIntersection(&UpdateRegion, &UpdateRegion, &ClipRectangle))
2432 {
2433 /* Draw update region */
2434 ConioDrawRegion(Console, &UpdateRegion);
2435 }
2436 }
2437
2438 ConioUnlockScreenBuffer(Buff);
2439 ConioUnlockConsole(Console);
2440
2441 return Request->Status = STATUS_SUCCESS;
2442 }
2443
2444 CSR_API(CsrReadConsoleOutputChar)
2445 {
2446 NTSTATUS Status;
2447 PCSRSS_CONSOLE Console;
2448 PCSRSS_SCREEN_BUFFER Buff;
2449 DWORD Xpos, Ypos;
2450 PCHAR ReadBuffer;
2451 DWORD i;
2452 ULONG CharSize;
2453 CHAR Char;
2454
2455 DPRINT("CsrReadConsoleOutputChar\n");
2456
2457 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2458 Request->Header.u1.s1.DataLength = Request->Header.u1.s1.TotalLength - sizeof(PORT_MESSAGE);
2459 ReadBuffer = Request->Data.ReadConsoleOutputCharRequest.String;
2460
2461 CharSize = (Request->Data.ReadConsoleOutputCharRequest.Unicode ? sizeof(WCHAR) : sizeof(CHAR));
2462
2463 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2464 if (! NT_SUCCESS(Status))
2465 {
2466 return Request->Status = Status;
2467 }
2468
2469 Status = ConioLockScreenBuffer(ProcessData, Request->Data.ReadConsoleOutputCharRequest.ConsoleHandle, &Buff, GENERIC_READ);
2470 if (! NT_SUCCESS(Status))
2471 {
2472 ConioUnlockConsole(Console);
2473 return Request->Status = Status;
2474 }
2475
2476 Xpos = Request->Data.ReadConsoleOutputCharRequest.ReadCoord.X;
2477 Ypos = (Request->Data.ReadConsoleOutputCharRequest.ReadCoord.Y + Buff->VirtualY) % Buff->MaxY;
2478
2479 for (i = 0; i < Request->Data.ReadConsoleOutputCharRequest.NumCharsToRead; ++i)
2480 {
2481 Char = Buff->Buffer[(Xpos * 2) + (Ypos * 2 * Buff->MaxX)];
2482
2483 if(Request->Data.ReadConsoleOutputCharRequest.Unicode)
2484 {
2485 ConsoleAnsiCharToUnicodeChar(Console, (WCHAR*)ReadBuffer, &Char);
2486 ReadBuffer += sizeof(WCHAR);
2487 }
2488 else
2489 *(ReadBuffer++) = Char;
2490
2491 Xpos++;
2492
2493 if (Xpos == Buff->MaxX)
2494 {
2495 Xpos = 0;
2496 Ypos++;
2497
2498 if (Ypos == Buff->MaxY)
2499 {
2500 Ypos = 0;
2501 }
2502 }
2503 }
2504
2505 *ReadBuffer = 0;
2506 Request->Status = STATUS_SUCCESS;
2507 Request->Data.ReadConsoleOutputCharRequest.EndCoord.X = Xpos;
2508 Request->Data.ReadConsoleOutputCharRequest.EndCoord.Y = (Ypos - Buff->VirtualY + Buff->MaxY) % Buff->MaxY;
2509
2510 ConioUnlockScreenBuffer(Buff);
2511 ConioUnlockConsole(Console);
2512
2513 Request->Data.ReadConsoleOutputCharRequest.CharsRead = (DWORD)((ULONG_PTR)ReadBuffer - (ULONG_PTR)Request->Data.ReadConsoleOutputCharRequest.String) / CharSize;
2514 if (Request->Data.ReadConsoleOutputCharRequest.CharsRead * CharSize + CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE_OUTPUT_CHAR) > sizeof(CSR_API_MESSAGE))
2515 {
2516 Request->Header.u1.s1.TotalLength = Request->Data.ReadConsoleOutputCharRequest.CharsRead * CharSize + CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE_OUTPUT_CHAR);
2517 Request->Header.u1.s1.DataLength = Request->Header.u1.s1.TotalLength - sizeof(PORT_MESSAGE);
2518 }
2519
2520 return Request->Status;
2521 }
2522
2523
2524 CSR_API(CsrReadConsoleOutputAttrib)
2525 {
2526 NTSTATUS Status;
2527 PCSRSS_SCREEN_BUFFER Buff;
2528 DWORD Xpos, Ypos;
2529 PWORD ReadBuffer;
2530 DWORD i;
2531 DWORD CurrentLength;
2532
2533 DPRINT("CsrReadConsoleOutputAttrib\n");
2534
2535 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2536 Request->Header.u1.s1.DataLength = Request->Header.u1.s1.TotalLength - sizeof(PORT_MESSAGE);
2537 ReadBuffer = Request->Data.ReadConsoleOutputAttribRequest.Attribute;
2538
2539 Status = ConioLockScreenBuffer(ProcessData, Request->Data.ReadConsoleOutputAttribRequest.ConsoleHandle, &Buff, GENERIC_READ);
2540 if (! NT_SUCCESS(Status))
2541 {
2542 return Request->Status = Status;
2543 }
2544
2545 Xpos = Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.X;
2546 Ypos = (Request->Data.ReadConsoleOutputAttribRequest.ReadCoord.Y + Buff->VirtualY) % Buff->MaxY;
2547
2548 for (i = 0; i < Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead; ++i)
2549 {
2550 *ReadBuffer = Buff->Buffer[(Xpos * 2) + (Ypos * 2 * Buff->MaxX) + 1];
2551
2552 ReadBuffer++;
2553 Xpos++;
2554
2555 if (Xpos == Buff->MaxX)
2556 {
2557 Xpos = 0;
2558 Ypos++;
2559
2560 if (Ypos == Buff->MaxY)
2561 {
2562 Ypos = 0;
2563 }
2564 }
2565 }
2566
2567 *ReadBuffer = 0;
2568
2569 Request->Status = STATUS_SUCCESS;
2570 Request->Data.ReadConsoleOutputAttribRequest.EndCoord.X = Xpos;
2571 Request->Data.ReadConsoleOutputAttribRequest.EndCoord.Y = (Ypos - Buff->VirtualY + Buff->MaxY) % Buff->MaxY;
2572
2573 ConioUnlockScreenBuffer(Buff);
2574
2575 CurrentLength = CSR_API_MESSAGE_HEADER_SIZE(CSRSS_READ_CONSOLE_OUTPUT_ATTRIB)
2576 + Request->Data.ReadConsoleOutputAttribRequest.NumAttrsToRead * sizeof(WORD);
2577 if (CurrentLength > sizeof(CSR_API_MESSAGE))
2578 {
2579 Request->Header.u1.s1.TotalLength = CurrentLength;
2580 Request->Header.u1.s1.DataLength = CurrentLength - sizeof(PORT_MESSAGE);
2581 }
2582
2583 return Request->Status;
2584 }
2585
2586
2587 CSR_API(CsrGetNumberOfConsoleInputEvents)
2588 {
2589 NTSTATUS Status;
2590 PCSRSS_CONSOLE Console;
2591 PLIST_ENTRY CurrentItem;
2592 DWORD NumEvents;
2593 ConsoleInput *Input;
2594
2595 DPRINT("CsrGetNumberOfConsoleInputEvents\n");
2596
2597 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2598 Request->Header.u1.s1.DataLength = Request->Header.u1.s1.TotalLength - sizeof(PORT_MESSAGE);
2599
2600 Status = ConioLockConsole(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, &Console, GENERIC_READ);
2601 if (! NT_SUCCESS(Status))
2602 {
2603 return Request->Status = Status;
2604 }
2605
2606 CurrentItem = Console->InputEvents.Flink;
2607 NumEvents = 0;
2608
2609 /* If there are any events ... */
2610 while (CurrentItem != &Console->InputEvents)
2611 {
2612 Input = CONTAINING_RECORD(CurrentItem, ConsoleInput, ListEntry);
2613 CurrentItem = CurrentItem->Flink;
2614 if (!Input->Fake)
2615 {
2616 NumEvents++;
2617 }
2618 }
2619
2620 ConioUnlockConsole(Console);
2621
2622 Request->Status = STATUS_SUCCESS;
2623 Request->Data.GetNumInputEventsRequest.NumInputEvents = NumEvents;
2624
2625 return Request->Status;
2626 }
2627
2628
2629 CSR_API(CsrPeekConsoleInput)
2630 {
2631 NTSTATUS Status;
2632 PCSRSS_CONSOLE Console;
2633 DWORD Size;
2634 DWORD Length;
2635 PLIST_ENTRY CurrentItem;
2636 PINPUT_RECORD InputRecord;
2637 ConsoleInput* Item;
2638 UINT NumItems;
2639
2640 DPRINT("CsrPeekConsoleInput\n");
2641
2642 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2643 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2644
2645 Status = ConioLockConsole(ProcessData, Request->Data.GetNumInputEventsRequest.ConsoleHandle, &Console, GENERIC_READ);
2646 if(! NT_SUCCESS(Status))
2647 {
2648 return Request->Status = Status;
2649 }
2650
2651 InputRecord = Request->Data.PeekConsoleInputRequest.InputRecord;
2652 Length = Request->Data.PeekConsoleInputRequest.Length;
2653 Size = Length * sizeof(INPUT_RECORD);
2654
2655 if (((PVOID)InputRecord < ProcessData->CsrSectionViewBase)
2656 || (((ULONG_PTR)InputRecord + Size) > ((ULONG_PTR)ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2657 {
2658 ConioUnlockConsole(Console);
2659 Request->Status = STATUS_ACCESS_VIOLATION;
2660 return Request->Status ;
2661 }
2662
2663 NumItems = 0;
2664
2665 if (! IsListEmpty(&Console->InputEvents))
2666 {
2667 CurrentItem = Console->InputEvents.Flink;
2668
2669 while (CurrentItem != &Console->InputEvents && NumItems < Length)
2670 {
2671 Item = CONTAINING_RECORD(CurrentItem, ConsoleInput, ListEntry);
2672
2673 if (Item->Fake)
2674 {
2675 CurrentItem = CurrentItem->Flink;
2676 continue;
2677 }
2678
2679 ++NumItems;
2680 *InputRecord = Item->InputEvent;
2681
2682 if (Request->Data.ReadInputRequest.Unicode == FALSE)
2683 {
2684 ConioInputEventToAnsi(Console, InputRecord);
2685 }
2686
2687 InputRecord++;
2688 CurrentItem = CurrentItem->Flink;
2689 }
2690 }
2691
2692 ConioUnlockConsole(Console);
2693
2694 Request->Status = STATUS_SUCCESS;
2695 Request->Data.PeekConsoleInputRequest.Length = NumItems;
2696
2697 return Request->Status;
2698 }
2699
2700
2701 CSR_API(CsrReadConsoleOutput)
2702 {
2703 PCHAR_INFO CharInfo;
2704 PCHAR_INFO CurCharInfo;
2705 PCSRSS_SCREEN_BUFFER Buff;
2706 DWORD Size;
2707 DWORD Length;
2708 DWORD SizeX, SizeY;
2709 NTSTATUS Status;
2710 COORD BufferSize;
2711 COORD BufferCoord;
2712 RECT ReadRegion;
2713 RECT ScreenRect;
2714 DWORD i;
2715 PBYTE Ptr;
2716 LONG X, Y;
2717 UINT CodePage;
2718
2719 DPRINT("CsrReadConsoleOutput\n");
2720
2721 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2722 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2723
2724 Status = ConioLockScreenBuffer(ProcessData, Request->Data.ReadConsoleOutputRequest.ConsoleHandle, &Buff, GENERIC_READ);
2725 if (! NT_SUCCESS(Status))
2726 {
2727 return Request->Status = Status;
2728 }
2729
2730 CharInfo = Request->Data.ReadConsoleOutputRequest.CharInfo;
2731 ReadRegion.left = Request->Data.ReadConsoleOutputRequest.ReadRegion.Left;
2732 ReadRegion.top = Request->Data.ReadConsoleOutputRequest.ReadRegion.Top;
2733 ReadRegion.right = Request->Data.ReadConsoleOutputRequest.ReadRegion.Right;
2734 ReadRegion.bottom = Request->Data.ReadConsoleOutputRequest.ReadRegion.Bottom;
2735 BufferSize = Request->Data.ReadConsoleOutputRequest.BufferSize;
2736 BufferCoord = Request->Data.ReadConsoleOutputRequest.BufferCoord;
2737 Length = BufferSize.X * BufferSize.Y;
2738 Size = Length * sizeof(CHAR_INFO);
2739
2740 /* FIXME: Is this correct? */
2741 CodePage = ProcessData->Console->OutputCodePage;
2742
2743 if (((PVOID)CharInfo < ProcessData->CsrSectionViewBase)
2744 || (((ULONG_PTR)CharInfo + Size) > ((ULONG_PTR)ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2745 {
2746 ConioUnlockScreenBuffer(Buff);
2747 Request->Status = STATUS_ACCESS_VIOLATION;
2748 return Request->Status ;
2749 }
2750
2751 SizeY = min(BufferSize.Y - BufferCoord.Y, ConioRectHeight(&ReadRegion));
2752 SizeX = min(BufferSize.X - BufferCoord.X, ConioRectWidth(&ReadRegion));
2753 ReadRegion.bottom = ReadRegion.top + SizeY;
2754 ReadRegion.right = ReadRegion.left + SizeX;
2755
2756 ConioInitRect(&ScreenRect, 0, 0, Buff->MaxY, Buff->MaxX);
2757 if (! ConioGetIntersection(&ReadRegion, &ScreenRect, &ReadRegion))
2758 {
2759 ConioUnlockScreenBuffer(Buff);
2760 Request->Status = STATUS_SUCCESS;
2761 return Request->Status;
2762 }
2763
2764 for (i = 0, Y = ReadRegion.top; Y < ReadRegion.bottom; ++i, ++Y)
2765 {
2766 CurCharInfo = CharInfo + (i * BufferSize.X);
2767
2768 Ptr = ConioCoordToPointer(Buff, ReadRegion.left, Y);
2769 for (X = ReadRegion.left; X < ReadRegion.right; ++X)
2770 {
2771 if (Request->Data.ReadConsoleOutputRequest.Unicode)
2772 {
2773 MultiByteToWideChar(CodePage, 0,
2774 (PCHAR)Ptr++, 1,
2775 &CurCharInfo->Char.UnicodeChar, 1);
2776 }
2777 else
2778 {
2779 CurCharInfo->Char.AsciiChar = *Ptr++;
2780 }
2781 CurCharInfo->Attributes = *Ptr++;
2782 ++CurCharInfo;
2783 }
2784 }
2785
2786 ConioUnlockScreenBuffer(Buff);
2787
2788 Request->Status = STATUS_SUCCESS;
2789 Request->Data.ReadConsoleOutputRequest.ReadRegion.Right = ReadRegion.left + SizeX - 1;
2790 Request->Data.ReadConsoleOutputRequest.ReadRegion.Bottom = ReadRegion.top + SizeY - 1;
2791 Request->Data.ReadConsoleOutputRequest.ReadRegion.Left = ReadRegion.left;
2792 Request->Data.ReadConsoleOutputRequest.ReadRegion.Top = ReadRegion.top;
2793
2794 return Request->Status;
2795 }
2796
2797
2798 CSR_API(CsrWriteConsoleInput)
2799 {
2800 PINPUT_RECORD InputRecord;
2801 PCSRSS_CONSOLE Console;
2802 NTSTATUS Status;
2803 DWORD Length;
2804 DWORD Size;
2805 DWORD i;
2806 ConsoleInput* Record;
2807
2808 DPRINT("CsrWriteConsoleInput\n");
2809
2810 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2811 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2812
2813 Status = ConioLockConsole(ProcessData, Request->Data.WriteConsoleInputRequest.ConsoleHandle, &Console, GENERIC_WRITE);
2814 if (! NT_SUCCESS(Status))
2815 {
2816 return Request->Status = Status;
2817 }
2818
2819 InputRecord = Request->Data.WriteConsoleInputRequest.InputRecord;
2820 Length = Request->Data.WriteConsoleInputRequest.Length;
2821 Size = Length * sizeof(INPUT_RECORD);
2822
2823 if (((PVOID)InputRecord < ProcessData->CsrSectionViewBase)
2824 || (((ULONG_PTR)InputRecord + Size) > ((ULONG_PTR)ProcessData->CsrSectionViewBase + ProcessData->CsrSectionViewSize)))
2825 {
2826 ConioUnlockConsole(Console);
2827 Request->Status = STATUS_ACCESS_VIOLATION;
2828 return Request->Status ;
2829 }
2830
2831 for (i = 0; i < Length; i++)
2832 {
2833 Record = HeapAlloc(Win32CsrApiHeap, 0, sizeof(ConsoleInput));
2834 if (NULL == Record)
2835 {
2836 ConioUnlockConsole(Console);
2837 Request->Status = STATUS_INSUFFICIENT_RESOURCES;
2838 return Request->Status;
2839 }
2840
2841 Record->Echoed = FALSE;
2842 Record->Fake = FALSE;
2843 //Record->InputEvent = *InputRecord++;
2844 memcpy(&Record->InputEvent, &InputRecord[i], sizeof(INPUT_RECORD));
2845 if (KEY_EVENT == Record->InputEvent.EventType)
2846 {
2847 /* FIXME - convert from unicode to ascii!! */
2848 ConioProcessChar(Console, Record);
2849 }
2850 }
2851
2852 ConioUnlockConsole(Console);
2853
2854 Request->Status = STATUS_SUCCESS;
2855 Request->Data.WriteConsoleInputRequest.Length = i;
2856
2857 return Request->Status;
2858 }
2859
2860 /**********************************************************************
2861 * HardwareStateProperty
2862 *
2863 * DESCRIPTION
2864 * Set/Get the value of the HardwareState and switch
2865 * between direct video buffer ouput and GDI windowed
2866 * output.
2867 * ARGUMENTS
2868 * Client hands us a CSRSS_CONSOLE_HARDWARE_STATE
2869 * object. We use the same object to Request.
2870 * NOTE
2871 * ConsoleHwState has the correct size to be compatible
2872 * with NT's, but values are not.
2873 */
2874 static NTSTATUS FASTCALL
2875 SetConsoleHardwareState (PCSRSS_CONSOLE Console, DWORD ConsoleHwState)
2876 {
2877 DPRINT1("Console Hardware State: %d\n", ConsoleHwState);
2878
2879 if ((CONSOLE_HARDWARE_STATE_GDI_MANAGED == ConsoleHwState)
2880 ||(CONSOLE_HARDWARE_STATE_DIRECT == ConsoleHwState))
2881 {
2882 if (Console->HardwareState != ConsoleHwState)
2883 {
2884 /* TODO: implement switching from full screen to windowed mode */
2885 /* TODO: or back; now simply store the hardware state */
2886 Console->HardwareState = ConsoleHwState;
2887 }
2888
2889 return STATUS_SUCCESS;
2890 }
2891
2892 return STATUS_INVALID_PARAMETER_3; /* Client: (handle, set_get, [mode]) */
2893 }
2894
2895 CSR_API(CsrHardwareStateProperty)
2896 {
2897 PCSRSS_CONSOLE Console;
2898 NTSTATUS Status;
2899
2900 DPRINT("CsrHardwareStateProperty\n");
2901
2902 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2903 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2904
2905 Status = ConioLockConsole(ProcessData,
2906 Request->Data.ConsoleHardwareStateRequest.ConsoleHandle,
2907 &Console,
2908 GENERIC_READ);
2909 if (! NT_SUCCESS(Status))
2910 {
2911 DPRINT1("Failed to get console handle in SetConsoleHardwareState\n");
2912 return Request->Status = Status;
2913 }
2914
2915 switch (Request->Data.ConsoleHardwareStateRequest.SetGet)
2916 {
2917 case CONSOLE_HARDWARE_STATE_GET:
2918 Request->Data.ConsoleHardwareStateRequest.State = Console->HardwareState;
2919 break;
2920
2921 case CONSOLE_HARDWARE_STATE_SET:
2922 DPRINT("Setting console hardware state.\n");
2923 Request->Status = SetConsoleHardwareState(Console, Request->Data.ConsoleHardwareStateRequest.State);
2924 break;
2925
2926 default:
2927 Request->Status = STATUS_INVALID_PARAMETER_2; /* Client: (handle, [set_get], mode) */
2928 break;
2929 }
2930
2931 ConioUnlockConsole(Console);
2932
2933 return Request->Status;
2934 }
2935
2936 CSR_API(CsrGetConsoleWindow)
2937 {
2938 PCSRSS_CONSOLE Console;
2939 NTSTATUS Status;
2940
2941 DPRINT("CsrGetConsoleWindow\n");
2942
2943 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2944 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2945
2946 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2947 if (! NT_SUCCESS(Status))
2948 {
2949 return Request->Status = Status;
2950 }
2951
2952 Request->Data.GetConsoleWindowRequest.WindowHandle = Console->hWindow;
2953 ConioUnlockConsole(Console);
2954
2955 return Request->Status = STATUS_SUCCESS;
2956 }
2957
2958 CSR_API(CsrSetConsoleIcon)
2959 {
2960 PCSRSS_CONSOLE Console;
2961 NTSTATUS Status;
2962
2963 DPRINT("CsrSetConsoleIcon\n");
2964
2965 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2966 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2967
2968 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2969 if (! NT_SUCCESS(Status))
2970 {
2971 return Request->Status = Status;
2972 }
2973
2974 Request->Status = (ConioChangeIcon(Console, Request->Data.SetConsoleIconRequest.WindowIcon)
2975 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
2976 ConioUnlockConsole(Console);
2977
2978 return Request->Status;
2979 }
2980
2981 CSR_API(CsrGetConsoleCodePage)
2982 {
2983 PCSRSS_CONSOLE Console;
2984 NTSTATUS Status;
2985
2986 DPRINT("CsrGetConsoleCodePage\n");
2987
2988 Status = ConioConsoleFromProcessData(ProcessData, &Console);
2989 if (! NT_SUCCESS(Status))
2990 {
2991 return Request->Status = Status;
2992 }
2993
2994 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
2995 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
2996 Request->Data.GetConsoleCodePage.CodePage = Console->CodePage;
2997 ConioUnlockConsole(Console);
2998 return Request->Status = STATUS_SUCCESS;
2999 }
3000
3001 CSR_API(CsrSetConsoleCodePage)
3002 {
3003 PCSRSS_CONSOLE Console;
3004 NTSTATUS Status;
3005
3006 DPRINT("CsrSetConsoleCodePage\n");
3007
3008 Status = ConioConsoleFromProcessData(ProcessData, &Console);
3009 if (! NT_SUCCESS(Status))
3010 {
3011 return Request->Status = Status;
3012 }
3013
3014 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
3015 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
3016 if (IsValidCodePage(Request->Data.SetConsoleCodePage.CodePage))
3017 {
3018 Console->CodePage = Request->Data.SetConsoleCodePage.CodePage;
3019 ConioUnlockConsole(Console);
3020 return Request->Status = STATUS_SUCCESS;
3021 }
3022 ConioUnlockConsole(Console);
3023 return Request->Status = STATUS_UNSUCCESSFUL;
3024 }
3025
3026 CSR_API(CsrGetConsoleOutputCodePage)
3027 {
3028 PCSRSS_CONSOLE Console;
3029 NTSTATUS Status;
3030
3031 DPRINT("CsrGetConsoleOutputCodePage\n");
3032
3033 Status = ConioConsoleFromProcessData(ProcessData, &Console);
3034 if (! NT_SUCCESS(Status))
3035 {
3036 return Request->Status = Status;
3037 }
3038
3039 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
3040 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
3041 Request->Data.GetConsoleOutputCodePage.CodePage = Console->OutputCodePage;
3042 ConioUnlockConsole(Console);
3043 return Request->Status = STATUS_SUCCESS;
3044 }
3045
3046 CSR_API(CsrSetConsoleOutputCodePage)
3047 {
3048 PCSRSS_CONSOLE Console;
3049 NTSTATUS Status;
3050
3051 DPRINT("CsrSetConsoleOutputCodePage\n");
3052
3053 Status = ConioConsoleFromProcessData(ProcessData, &Console);
3054 if (! NT_SUCCESS(Status))
3055 {
3056 return Request->Status = Status;
3057 }
3058
3059 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
3060 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
3061 if (IsValidCodePage(Request->Data.SetConsoleOutputCodePage.CodePage))
3062 {
3063 Console->OutputCodePage = Request->Data.SetConsoleOutputCodePage.CodePage;
3064 ConioUnlockConsole(Console);
3065 return Request->Status = STATUS_SUCCESS;
3066 }
3067 ConioUnlockConsole(Console);
3068 return Request->Status = STATUS_UNSUCCESSFUL;
3069 }
3070
3071 CSR_API(CsrGetProcessList)
3072 {
3073 PHANDLE Buffer;
3074 PCSRSS_CONSOLE Console;
3075 PCSRSS_PROCESS_DATA current;
3076 PLIST_ENTRY current_entry;
3077 ULONG nItems, nCopied, Length;
3078 NTSTATUS Status;
3079
3080 DPRINT("CsrGetProcessList\n");
3081
3082 Buffer = Request->Data.GetProcessListRequest.ProcessId;
3083 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
3084 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
3085
3086 nItems = nCopied = 0;
3087 Request->Data.GetProcessListRequest.nProcessIdsCopied = 0;
3088 Request->Data.GetProcessListRequest.nProcessIdsTotal = 0;
3089
3090 Status = ConioConsoleFromProcessData(ProcessData, &Console);
3091 if (! NT_SUCCESS(Status))
3092 {
3093 return Request->Status = Status;
3094 }
3095
3096 DPRINT1("Console_Api Ctrl-C\n");
3097
3098 for(current_entry = Console->ProcessList.Flink;
3099 current_entry != &Console->ProcessList;
3100 current_entry = current_entry->Flink)
3101 {
3102 current = CONTAINING_RECORD(current_entry, CSRSS_PROCESS_DATA, ProcessEntry);
3103 if(++nItems < Request->Data.GetProcessListRequest.nMaxIds)
3104 {
3105 *(Buffer++) = current->ProcessId;
3106 nCopied++;
3107 }
3108 }
3109
3110 ConioUnlockConsole(Console);
3111
3112 Request->Data.GetProcessListRequest.nProcessIdsCopied = nCopied;
3113 Request->Data.GetProcessListRequest.nProcessIdsTotal = nItems;
3114
3115 Length = CSR_API_MESSAGE_HEADER_SIZE(CSRSS_GET_PROCESS_LIST) + nCopied * sizeof(HANDLE);
3116 if (Length > sizeof(CSR_API_MESSAGE))
3117 {
3118 Request->Header.u1.s1.TotalLength = Length;
3119 Request->Header.u1.s1.DataLength = Length - sizeof(PORT_MESSAGE);
3120 }
3121 return Request->Status = STATUS_SUCCESS;
3122 }
3123
3124 /* EOF */