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