1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/winsrv/consrv/conoutput.c
5 * PURPOSE: General Console Output Functions
6 * PROGRAMMERS: Jeffrey Morlan
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include "consrv.h"
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* PUBLIC SERVER APIS *********************************************************/
18
19 /*
20 * FIXME: This function MUST be moved from condrv/conoutput.c because only
21 * consrv knows how to manipulate VDM screenbuffers.
22 */
23 NTSTATUS NTAPI
24 ConDrvWriteConsoleOutputVDM(IN PCONSOLE Console,
25 IN PTEXTMODE_SCREEN_BUFFER Buffer,
26 IN PCHAR_CELL CharInfo/*Buffer*/,
27 IN COORD CharInfoSize,
28 IN PSMALL_RECT WriteRegion);
29 NTSTATUS NTAPI
30 ConDrvInvalidateBitMapRect(IN PCONSOLE Console,
31 IN PCONSOLE_SCREEN_BUFFER Buffer,
32 IN PSMALL_RECT Region);
33 /* API_NUMBER: ConsolepInvalidateBitMapRect */
CON_API(SrvInvalidateBitMapRect,CONSOLE_INVALIDATEDIBITS,InvalidateDIBitsRequest)34 CON_API(SrvInvalidateBitMapRect,
35 CONSOLE_INVALIDATEDIBITS, InvalidateDIBitsRequest)
36 {
37 NTSTATUS Status;
38 PCONSOLE_SCREEN_BUFFER Buffer;
39
40 Status = ConSrvGetScreenBuffer(ProcessData,
41 InvalidateDIBitsRequest->OutputHandle,
42 &Buffer, GENERIC_READ, TRUE);
43 if (!NT_SUCCESS(Status))
44 return Status;
45
46 ASSERT((PCONSOLE)Console == Buffer->Header.Console);
47
48 /* In text-mode only, draw the VDM buffer if present */
49 if (GetType(Buffer) == TEXTMODE_BUFFER && Console->VDMBuffer)
50 {
51 PTEXTMODE_SCREEN_BUFFER TextBuffer = (PTEXTMODE_SCREEN_BUFFER)Buffer;
52
53 /*Status =*/ ConDrvWriteConsoleOutputVDM((PCONSOLE)Console,
54 TextBuffer,
55 Console->VDMBuffer,
56 Console->VDMBufferSize,
57 &InvalidateDIBitsRequest->Region);
58 }
59
60 Status = ConDrvInvalidateBitMapRect((PCONSOLE)Console,
61 Buffer,
62 &InvalidateDIBitsRequest->Region);
63
64 ConSrvReleaseScreenBuffer(Buffer, TRUE);
65 return Status;
66 }
67
68 NTSTATUS NTAPI
69 ConDrvSetConsolePalette(IN PCONSOLE Console,
70 // IN PGRAPHICS_SCREEN_BUFFER Buffer,
71 IN PCONSOLE_SCREEN_BUFFER Buffer,
72 IN HPALETTE PaletteHandle,
73 IN UINT PaletteUsage);
74 /* API_NUMBER: ConsolepSetPalette */
CON_API(SrvSetConsolePalette,CONSOLE_SETPALETTE,SetPaletteRequest)75 CON_API(SrvSetConsolePalette,
76 CONSOLE_SETPALETTE, SetPaletteRequest)
77 {
78 NTSTATUS Status;
79 // PGRAPHICS_SCREEN_BUFFER Buffer;
80 PCONSOLE_SCREEN_BUFFER Buffer;
81
82 // NOTE: Tests show that this function is used only for graphics screen buffers
83 // and otherwise it returns FALSE + sets last error to invalid handle.
84 // I think it's ridiculous, because if you are in text mode, simulating
85 // a change of VGA palette via DAC registers (done by a call to SetConsolePalette)
86 // cannot be done... So I allow it in ReactOS !
87 /*
88 Status = ConSrvGetGraphicsBuffer(ProcessData,
89 SetPaletteRequest->OutputHandle,
90 &Buffer, GENERIC_WRITE, TRUE);
91 */
92 Status = ConSrvGetScreenBuffer(ProcessData,
93 SetPaletteRequest->OutputHandle,
94 &Buffer, GENERIC_WRITE, TRUE);
95 if (!NT_SUCCESS(Status))
96 return Status;
97
98 ASSERT((PCONSOLE)Console == Buffer->Header.Console);
99
100 /*
101 * Make the palette handle public, so that it can be
102 * used by other threads calling GDI functions on it.
103 * Indeed, the palette handle comes from a console app
104 * calling ourselves, running in CSRSS.
105 */
106 NtUserConsoleControl(ConsoleMakePalettePublic,
107 &SetPaletteRequest->PaletteHandle,
108 sizeof(SetPaletteRequest->PaletteHandle));
109
110 Status = ConDrvSetConsolePalette((PCONSOLE)Console,
111 Buffer,
112 SetPaletteRequest->PaletteHandle,
113 SetPaletteRequest->Usage);
114
115 ConSrvReleaseScreenBuffer(Buffer, TRUE);
116 return Status;
117 }
118
119 NTSTATUS NTAPI
120 ConDrvGetConsoleCursorInfo(IN PCONSOLE Console,
121 IN PTEXTMODE_SCREEN_BUFFER Buffer,
122 OUT PCONSOLE_CURSOR_INFO CursorInfo);
123 /* API_NUMBER: ConsolepGetCursorInfo */
CON_API(SrvGetConsoleCursorInfo,CONSOLE_GETSETCURSORINFO,CursorInfoRequest)124 CON_API(SrvGetConsoleCursorInfo,
125 CONSOLE_GETSETCURSORINFO, CursorInfoRequest)
126 {
127 NTSTATUS Status;
128 PTEXTMODE_SCREEN_BUFFER Buffer;
129
130 Status = ConSrvGetTextModeBuffer(ProcessData,
131 CursorInfoRequest->OutputHandle,
132 &Buffer, GENERIC_READ, TRUE);
133 if (!NT_SUCCESS(Status))
134 return Status;
135
136 ASSERT((PCONSOLE)Console == Buffer->Header.Console);
137
138 Status = ConDrvGetConsoleCursorInfo((PCONSOLE)Console,
139 Buffer,
140 &CursorInfoRequest->Info);
141
142 ConSrvReleaseScreenBuffer(Buffer, TRUE);
143 return Status;
144 }
145
146 NTSTATUS NTAPI
147 ConDrvSetConsoleCursorInfo(IN PCONSOLE Console,
148 IN PTEXTMODE_SCREEN_BUFFER Buffer,
149 IN PCONSOLE_CURSOR_INFO CursorInfo);
150 /* API_NUMBER: ConsolepSetCursorInfo */
CON_API(SrvSetConsoleCursorInfo,CONSOLE_GETSETCURSORINFO,CursorInfoRequest)151 CON_API(SrvSetConsoleCursorInfo,
152 CONSOLE_GETSETCURSORINFO, CursorInfoRequest)
153 {
154 NTSTATUS Status;
155 PTEXTMODE_SCREEN_BUFFER Buffer;
156
157 Status = ConSrvGetTextModeBuffer(ProcessData,
158 CursorInfoRequest->OutputHandle,
159 &Buffer, GENERIC_WRITE, TRUE);
160 if (!NT_SUCCESS(Status))
161 return Status;
162
163 ASSERT((PCONSOLE)Console == Buffer->Header.Console);
164
165 Status = ConDrvSetConsoleCursorInfo((PCONSOLE)Console,
166 Buffer,
167 &CursorInfoRequest->Info);
168
169 ConSrvReleaseScreenBuffer(Buffer, TRUE);
170 return Status;
171 }
172
173 NTSTATUS NTAPI
174 ConDrvSetConsoleCursorPosition(IN PCONSOLE Console,
175 IN PTEXTMODE_SCREEN_BUFFER Buffer,
176 IN PCOORD Position);
177 /* API_NUMBER: ConsolepSetCursorPosition */
CON_API(SrvSetConsoleCursorPosition,CONSOLE_SETCURSORPOSITION,SetCursorPositionRequest)178 CON_API(SrvSetConsoleCursorPosition,
179 CONSOLE_SETCURSORPOSITION, SetCursorPositionRequest)
180 {
181 NTSTATUS Status;
182 PTEXTMODE_SCREEN_BUFFER Buffer;
183
184 Status = ConSrvGetTextModeBuffer(ProcessData,
185 SetCursorPositionRequest->OutputHandle,
186 &Buffer, GENERIC_WRITE, TRUE);
187 if (!NT_SUCCESS(Status))
188 return Status;
189
190 ASSERT((PCONSOLE)Console == Buffer->Header.Console);
191
192 Status = ConDrvSetConsoleCursorPosition((PCONSOLE)Console,
193 Buffer,
194 &SetCursorPositionRequest->Position);
195
196 ConSrvReleaseScreenBuffer(Buffer, TRUE);
197 return Status;
198 }
199
200 /* API_NUMBER: ConsolepCreateScreenBuffer */
CON_API(SrvCreateConsoleScreenBuffer,CONSOLE_CREATESCREENBUFFER,CreateScreenBufferRequest)201 CON_API(SrvCreateConsoleScreenBuffer,
202 CONSOLE_CREATESCREENBUFFER, CreateScreenBufferRequest)
203 {
204 NTSTATUS Status;
205 PCSR_PROCESS Process = CsrGetClientThread()->Process;
206 // PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process);
207 PCONSOLE_SCREEN_BUFFER Buff;
208
209 PVOID ScreenBufferInfo = NULL;
210 TEXTMODE_BUFFER_INFO TextModeInfo = {{80, 25},
211 {80, 25},
212 DEFAULT_SCREEN_ATTRIB,
213 DEFAULT_POPUP_ATTRIB,
214 TRUE,
215 CSR_DEFAULT_CURSOR_SIZE};
216 GRAPHICS_BUFFER_INFO GraphicsInfo;
217 GraphicsInfo.Info = CreateScreenBufferRequest->GraphicsBufferInfo; // HACK for MSVC
218
219 if (CreateScreenBufferRequest->ScreenBufferType == CONSOLE_TEXTMODE_BUFFER)
220 {
221 ScreenBufferInfo = &TextModeInfo;
222
223 /*
224 * This is Windows behaviour, as described by MSDN and verified manually:
225 *
226 * The newly created screen buffer will copy some properties from the
227 * active screen buffer at the time that this function is called.
228 * The behavior is as follows:
229 * Font - copied from active screen buffer.
230 * Display Window Size - copied from active screen buffer.
231 * Buffer Size - matched to Display Window Size (NOT copied).
232 * Default Attributes (colors) - copied from active screen buffer.
233 * Default Popup Attributes (colors) - copied from active screen buffer.
234 */
235
236 /* If we have an active screen buffer, use its attributes as the new ones */
237 if (Console->ActiveBuffer && GetType(Console->ActiveBuffer) == TEXTMODE_BUFFER)
238 {
239 PTEXTMODE_SCREEN_BUFFER Buffer = (PTEXTMODE_SCREEN_BUFFER)Console->ActiveBuffer;
240
241 TextModeInfo.ScreenAttrib = Buffer->ScreenDefaultAttrib;
242 TextModeInfo.PopupAttrib = Buffer->PopupDefaultAttrib;
243
244 TextModeInfo.CursorSize = Buffer->CursorInfo.dwSize;
245 TextModeInfo.IsCursorVisible = Buffer->CursorInfo.bVisible;
246
247 /* Use the current view size */
248 TextModeInfo.ScreenBufferSize = Buffer->ViewSize;
249 TextModeInfo.ViewSize = Buffer->ViewSize;
250 }
251 else
252 {
253 /* Use the current console size */
254 TextModeInfo.ScreenBufferSize = Console->ConsoleSize;
255 TextModeInfo.ViewSize = Console->ConsoleSize;
256 }
257
258 /* Normalize the screen buffer size if needed */
259 if (TextModeInfo.ScreenBufferSize.X == 0) TextModeInfo.ScreenBufferSize.X = 1;
260 if (TextModeInfo.ScreenBufferSize.Y == 0) TextModeInfo.ScreenBufferSize.Y = 1;
261 }
262 else if (CreateScreenBufferRequest->ScreenBufferType == CONSOLE_GRAPHICS_BUFFER)
263 {
264 /* Get information from the graphics buffer information structure */
265 if (!CsrValidateMessageBuffer(ApiMessage,
266 (PVOID*)&CreateScreenBufferRequest->GraphicsBufferInfo.lpBitMapInfo,
267 CreateScreenBufferRequest->GraphicsBufferInfo.dwBitMapInfoLength,
268 sizeof(BYTE)))
269 {
270 return STATUS_INVALID_PARAMETER;
271 }
272
273 ScreenBufferInfo = &GraphicsInfo;
274
275 /* Initialize shared variables */
276 // CreateScreenBufferRequest->GraphicsBufferInfo.hMutex
277 CreateScreenBufferRequest->hMutex = GraphicsInfo.Info.hMutex = INVALID_HANDLE_VALUE;
278 // CreateScreenBufferRequest->GraphicsBufferInfo.lpBitMap
279 CreateScreenBufferRequest->lpBitMap = GraphicsInfo.Info.lpBitMap = NULL;
280
281 /* A graphics screen buffer is never inheritable */
282 CreateScreenBufferRequest->InheritHandle = FALSE;
283 }
284 else
285 {
286 DPRINT1("Invalid ScreenBuffer type %lu\n", CreateScreenBufferRequest->ScreenBufferType);
287 return STATUS_INVALID_PARAMETER;
288 }
289
290 Status = ConDrvCreateScreenBuffer(&Buff,
291 (PCONSOLE)Console,
292 Process->ProcessHandle,
293 CreateScreenBufferRequest->ScreenBufferType,
294 ScreenBufferInfo);
295 if (!NT_SUCCESS(Status))
296 return Status;
297
298 /* Insert the new handle inside the process handles table */
299 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
300
301 Status = ConSrvInsertObject(ProcessData,
302 &CreateScreenBufferRequest->OutputHandle,
303 &Buff->Header,
304 CreateScreenBufferRequest->DesiredAccess,
305 CreateScreenBufferRequest->InheritHandle,
306 CreateScreenBufferRequest->ShareMode);
307
308 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
309
310 if (!NT_SUCCESS(Status))
311 {
312 ConDrvDeleteScreenBuffer(Buff);
313 return Status;
314 }
315
316 if (CreateScreenBufferRequest->ScreenBufferType == CONSOLE_GRAPHICS_BUFFER)
317 {
318 PGRAPHICS_SCREEN_BUFFER Buffer = (PGRAPHICS_SCREEN_BUFFER)Buff;
319 /*
320 * Initialize the graphics buffer information structure
321 * and give it back to the client.
322 */
323 // CreateScreenBufferRequest->GraphicsBufferInfo.hMutex
324 CreateScreenBufferRequest->hMutex = Buffer->ClientMutex;
325 // CreateScreenBufferRequest->GraphicsBufferInfo.lpBitMap
326 CreateScreenBufferRequest->lpBitMap = Buffer->ClientBitMap;
327 }
328
329 return Status;
330 }
331
332 NTSTATUS NTAPI
333 ConDrvSetConsoleActiveScreenBuffer(IN PCONSOLE Console,
334 IN PCONSOLE_SCREEN_BUFFER Buffer);
335 /* API_NUMBER: ConsolepSetActiveScreenBuffer */
CON_API(SrvSetConsoleActiveScreenBuffer,CONSOLE_SETACTIVESCREENBUFFER,SetScreenBufferRequest)336 CON_API(SrvSetConsoleActiveScreenBuffer,
337 CONSOLE_SETACTIVESCREENBUFFER, SetScreenBufferRequest)
338 {
339 NTSTATUS Status;
340 PCONSOLE_SCREEN_BUFFER Buffer;
341
342 Status = ConSrvGetScreenBuffer(ProcessData,
343 SetScreenBufferRequest->OutputHandle,
344 &Buffer, GENERIC_WRITE, TRUE);
345 if (!NT_SUCCESS(Status))
346 return Status;
347
348 ASSERT((PCONSOLE)Console == Buffer->Header.Console);
349
350 Status = ConDrvSetConsoleActiveScreenBuffer((PCONSOLE)Console, Buffer);
351
352 ConSrvReleaseScreenBuffer(Buffer, TRUE);
353 return Status;
354 }
355
356
357 /* CSR THREADS FOR WriteConsole ***********************************************/
358
359 static NTSTATUS
360 DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage,
361 IN PCSR_THREAD ClientThread,
362 IN BOOLEAN CreateWaitBlock OPTIONAL);
363
364 // Wait function CSR_WAIT_FUNCTION
365 static BOOLEAN
366 NTAPI
WriteConsoleThread(IN PLIST_ENTRY WaitList,IN PCSR_THREAD WaitThread,IN PCSR_API_MESSAGE WaitApiMessage,IN PVOID WaitContext,IN PVOID WaitArgument1,IN PVOID WaitArgument2,IN ULONG WaitFlags)367 WriteConsoleThread(IN PLIST_ENTRY WaitList,
368 IN PCSR_THREAD WaitThread,
369 IN PCSR_API_MESSAGE WaitApiMessage,
370 IN PVOID WaitContext,
371 IN PVOID WaitArgument1,
372 IN PVOID WaitArgument2,
373 IN ULONG WaitFlags)
374 {
375 NTSTATUS Status;
376
377 DPRINT("WriteConsoleThread - WaitContext = 0x%p, WaitArgument1 = 0x%p, WaitArgument2 = 0x%p, WaitFlags = %lu\n", WaitContext, WaitArgument1, WaitArgument2, WaitFlags);
378
379 /*
380 * If we are notified of the process termination via a call
381 * to CsrNotifyWaitBlock triggered by CsrDestroyProcess or
382 * CsrDestroyThread, just return.
383 */
384 if (WaitFlags & CsrProcessTerminating)
385 {
386 Status = STATUS_THREAD_IS_TERMINATING;
387 goto Quit;
388 }
389
390 Status = DoWriteConsole(WaitApiMessage, WaitThread, FALSE);
391
392 Quit:
393 if (Status != STATUS_PENDING)
394 {
395 WaitApiMessage->Status = Status;
396 }
397
398 return (Status == STATUS_PENDING ? FALSE : TRUE);
399 }
400
401 NTSTATUS NTAPI
402 ConDrvWriteConsole(IN PCONSOLE Console,
403 IN PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
404 IN BOOLEAN Unicode,
405 IN PVOID StringBuffer,
406 IN ULONG NumCharsToWrite,
407 OUT PULONG NumCharsWritten OPTIONAL);
408 static NTSTATUS
DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage,IN PCSR_THREAD ClientThread,IN BOOLEAN CreateWaitBlock OPTIONAL)409 DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage,
410 IN PCSR_THREAD ClientThread,
411 IN BOOLEAN CreateWaitBlock OPTIONAL)
412 {
413 NTSTATUS Status;
414 PCONSOLE_WRITECONSOLE WriteConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleRequest;
415 PTEXTMODE_SCREEN_BUFFER ScreenBuffer;
416
417 PVOID Buffer;
418 ULONG NrCharactersWritten = 0;
419 ULONG CharSize = (WriteConsoleRequest->Unicode ? sizeof(WCHAR) : sizeof(CHAR));
420
421 Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(ClientThread->Process),
422 WriteConsoleRequest->OutputHandle,
423 &ScreenBuffer, GENERIC_WRITE, FALSE);
424 if (!NT_SUCCESS(Status)) return Status;
425
426 /*
427 * For optimization purposes, Windows (and hence ReactOS, too, for
428 * compatibility reasons) uses a static buffer if no more than eighty
429 * bytes are written. Otherwise a new buffer is used.
430 * The client-side expects that we know this behaviour.
431 */
432 if (WriteConsoleRequest->UsingStaticBuffer &&
433 WriteConsoleRequest->NumBytes <= sizeof(WriteConsoleRequest->StaticBuffer))
434 {
435 /*
436 * Adjust the internal pointer, because its old value points to
437 * the static buffer in the original ApiMessage structure.
438 */
439 // WriteConsoleRequest->Buffer = WriteConsoleRequest->StaticBuffer;
440 Buffer = WriteConsoleRequest->StaticBuffer;
441 }
442 else
443 {
444 Buffer = WriteConsoleRequest->Buffer;
445 }
446
447 DPRINT("Calling ConDrvWriteConsole\n");
448 Status = ConDrvWriteConsole(ScreenBuffer->Header.Console,
449 ScreenBuffer,
450 WriteConsoleRequest->Unicode,
451 Buffer,
452 WriteConsoleRequest->NumBytes / CharSize, // NrCharactersToWrite
453 &NrCharactersWritten);
454 DPRINT("ConDrvWriteConsole returned (%d ; Status = 0x%08x)\n",
455 NrCharactersWritten, Status);
456
457 if (Status == STATUS_PENDING)
458 {
459 if (CreateWaitBlock)
460 {
461 PCONSRV_CONSOLE Console = (PCONSRV_CONSOLE)ScreenBuffer->Header.Console;
462
463 if (!CsrCreateWait(&Console->WriteWaitQueue,
464 WriteConsoleThread,
465 ClientThread,
466 ApiMessage,
467 NULL))
468 {
469 /* Fail */
470 Status = STATUS_NO_MEMORY;
471 goto Quit;
472 }
473 }
474
475 /* Wait until we un-pause the console */
476 // Status = STATUS_PENDING;
477 }
478 else
479 {
480 /* We read all what we wanted. Set the number of bytes written. */
481 WriteConsoleRequest->NumBytes = NrCharactersWritten * CharSize;
482 }
483
484 Quit:
485 ConSrvReleaseScreenBuffer(ScreenBuffer, FALSE);
486 return Status;
487 }
488
489
490 /* TEXT OUTPUT APIS ***********************************************************/
491
492 NTSTATUS NTAPI
493 ConDrvReadConsoleOutput(IN PCONSOLE Console,
494 IN PTEXTMODE_SCREEN_BUFFER Buffer,
495 IN BOOLEAN Unicode,
496 OUT PCHAR_INFO CharInfo/*Buffer*/,
497 IN OUT PSMALL_RECT ReadRegion);
498 /* API_NUMBER: ConsolepReadConsoleOutput */
CON_API(SrvReadConsoleOutput,CONSOLE_READOUTPUT,ReadOutputRequest)499 CON_API(SrvReadConsoleOutput,
500 CONSOLE_READOUTPUT, ReadOutputRequest)
501 {
502 NTSTATUS Status;
503 PTEXTMODE_SCREEN_BUFFER Buffer;
504 ULONG NumCells;
505 PCHAR_INFO CharInfo;
506
507 NumCells = ConioRectWidth(&ReadOutputRequest->ReadRegion) *
508 ConioRectHeight(&ReadOutputRequest->ReadRegion);
509
510 /*
511 * For optimization purposes, Windows (and hence ReactOS, too, for
512 * compatibility reasons) uses a static buffer if no more than one
513 * cell is read. Otherwise a new buffer is used.
514 * The client-side expects that we know this behaviour.
515 */
516 if (NumCells <= 1)
517 {
518 /*
519 * Adjust the internal pointer, because its old value points to
520 * the static buffer in the original ApiMessage structure.
521 */
522 // ReadOutputRequest->CharInfo = &ReadOutputRequest->StaticBuffer;
523 CharInfo = &ReadOutputRequest->StaticBuffer;
524 }
525 else
526 {
527 if (!CsrValidateMessageBuffer(ApiMessage,
528 (PVOID*)&ReadOutputRequest->CharInfo,
529 NumCells,
530 sizeof(CHAR_INFO)))
531 {
532 return STATUS_INVALID_PARAMETER;
533 }
534
535 CharInfo = ReadOutputRequest->CharInfo;
536 }
537
538 Status = ConSrvGetTextModeBuffer(ProcessData,
539 ReadOutputRequest->OutputHandle,
540 &Buffer, GENERIC_READ, TRUE);
541 if (!NT_SUCCESS(Status))
542 return Status;
543
544 ASSERT((PCONSOLE)Console == Buffer->Header.Console);
545
546 Status = ConDrvReadConsoleOutput((PCONSOLE)Console,
547 Buffer,
548 ReadOutputRequest->Unicode,
549 CharInfo,
550 &ReadOutputRequest->ReadRegion);
551
552 ConSrvReleaseScreenBuffer(Buffer, TRUE);
553 return Status;
554 }
555
556 NTSTATUS NTAPI
557 ConDrvWriteConsoleOutput(IN PCONSOLE Console,
558 IN PTEXTMODE_SCREEN_BUFFER Buffer,
559 IN BOOLEAN Unicode,
560 IN PCHAR_INFO CharInfo/*Buffer*/,
561 IN OUT PSMALL_RECT WriteRegion);
562 /* API_NUMBER: ConsolepWriteConsoleOutput */
CON_API(SrvWriteConsoleOutput,CONSOLE_WRITEOUTPUT,WriteOutputRequest)563 CON_API(SrvWriteConsoleOutput,
564 CONSOLE_WRITEOUTPUT, WriteOutputRequest)
565 {
566 NTSTATUS Status;
567 PCSR_PROCESS Process = CsrGetClientThread()->Process;
568 // PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process);
569 PTEXTMODE_SCREEN_BUFFER Buffer;
570 ULONG NumCells;
571 PCHAR_INFO CharInfo;
572
573 NumCells = ConioRectWidth(&WriteOutputRequest->WriteRegion) *
574 ConioRectHeight(&WriteOutputRequest->WriteRegion);
575
576 Status = ConSrvGetTextModeBuffer(ProcessData,
577 WriteOutputRequest->OutputHandle,
578 &Buffer, GENERIC_WRITE, TRUE);
579 if (!NT_SUCCESS(Status))
580 return Status;
581
582 ASSERT((PCONSOLE)Console == Buffer->Header.Console);
583
584 /*
585 * Validate the message buffer if we do not use a process' heap buffer
586 * (CsrAllocateCaptureBuffer succeeded because we haven't allocated
587 * a too large (>= 64 kB, size of the CSR heap) data buffer).
588 */
589 if (!WriteOutputRequest->UseVirtualMemory)
590 {
591 /*
592 * For optimization purposes, Windows (and hence ReactOS, too, for
593 * compatibility reasons) uses a static buffer if no more than one
594 * cell is written. Otherwise a new buffer is used.
595 * The client-side expects that we know this behaviour.
596 */
597 if (NumCells <= 1)
598 {
599 /*
600 * Adjust the internal pointer, because its old value points to
601 * the static buffer in the original ApiMessage structure.
602 */
603 // WriteOutputRequest->CharInfo = &WriteOutputRequest->StaticBuffer;
604 CharInfo = &WriteOutputRequest->StaticBuffer;
605 }
606 else
607 {
608 if (!CsrValidateMessageBuffer(ApiMessage,
609 (PVOID*)&WriteOutputRequest->CharInfo,
610 NumCells,
611 sizeof(CHAR_INFO)))
612 {
613 Status = STATUS_INVALID_PARAMETER;
614 goto Quit;
615 }
616
617 CharInfo = WriteOutputRequest->CharInfo;
618 }
619 }
620 else
621 {
622 /*
623 * This was not the case: we use a heap buffer. Retrieve its contents.
624 */
625 ULONG Size = NumCells * sizeof(CHAR_INFO);
626
627 CharInfo = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size);
628 if (CharInfo == NULL)
629 {
630 Status = STATUS_NO_MEMORY;
631 goto Quit;
632 }
633
634 Status = NtReadVirtualMemory(Process->ProcessHandle,
635 WriteOutputRequest->CharInfo,
636 CharInfo,
637 Size,
638 NULL);
639 if (!NT_SUCCESS(Status))
640 {
641 ConsoleFreeHeap(CharInfo);
642 // Status = STATUS_NO_MEMORY;
643 goto Quit;
644 }
645 }
646
647 Status = ConDrvWriteConsoleOutput((PCONSOLE)Console,
648 Buffer,
649 WriteOutputRequest->Unicode,
650 CharInfo,
651 &WriteOutputRequest->WriteRegion);
652
653 /* Free the temporary buffer if we used the process' heap buffer */
654 if (WriteOutputRequest->UseVirtualMemory && CharInfo)
655 ConsoleFreeHeap(CharInfo);
656
657 Quit:
658 ConSrvReleaseScreenBuffer(Buffer, TRUE);
659 return Status;
660 }
661
662 /* API_NUMBER: ConsolepWriteConsole */
CON_API(SrvWriteConsole,CONSOLE_WRITECONSOLE,WriteConsoleRequest)663 CON_API(SrvWriteConsole,
664 CONSOLE_WRITECONSOLE, WriteConsoleRequest)
665 {
666 NTSTATUS Status;
667
668 DPRINT("SrvWriteConsole\n");
669
670 /*
671 * For optimization purposes, Windows (and hence ReactOS, too, for
672 * compatibility reasons) uses a static buffer if no more than eighty
673 * bytes are written. Otherwise a new buffer is used.
674 * The client-side expects that we know this behaviour.
675 */
676 if (WriteConsoleRequest->UsingStaticBuffer &&
677 WriteConsoleRequest->NumBytes <= sizeof(WriteConsoleRequest->StaticBuffer))
678 {
679 /*
680 * Adjust the internal pointer, because its old value points to
681 * the static buffer in the original ApiMessage structure.
682 */
683 // WriteConsoleRequest->Buffer = WriteConsoleRequest->StaticBuffer;
684 }
685 else
686 {
687 if (!CsrValidateMessageBuffer(ApiMessage,
688 (PVOID)&WriteConsoleRequest->Buffer,
689 WriteConsoleRequest->NumBytes,
690 sizeof(BYTE)))
691 {
692 return STATUS_INVALID_PARAMETER;
693 }
694 }
695
696 Status = DoWriteConsole(ApiMessage, CsrGetClientThread(), TRUE);
697
698 if (Status == STATUS_PENDING) *ReplyCode = CsrReplyPending;
699
700 return Status;
701 }
702
703 NTSTATUS NTAPI
704 ConDrvReadConsoleOutputString(IN PCONSOLE Console,
705 IN PTEXTMODE_SCREEN_BUFFER Buffer,
706 IN CODE_TYPE CodeType,
707 OUT PVOID StringBuffer,
708 IN ULONG NumCodesToRead,
709 IN PCOORD ReadCoord,
710 // OUT PCOORD EndCoord,
711 OUT PULONG NumCodesRead OPTIONAL);
712 /* API_NUMBER: ConsolepReadConsoleOutputString */
CON_API(SrvReadConsoleOutputString,CONSOLE_READOUTPUTCODE,ReadOutputCodeRequest)713 CON_API(SrvReadConsoleOutputString,
714 CONSOLE_READOUTPUTCODE, ReadOutputCodeRequest)
715 {
716 NTSTATUS Status;
717 PTEXTMODE_SCREEN_BUFFER Buffer;
718 ULONG CodeSize;
719 PVOID pCode;
720
721 switch (ReadOutputCodeRequest->CodeType)
722 {
723 case CODE_ASCII:
724 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
725 break;
726
727 case CODE_UNICODE:
728 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
729 break;
730
731 case CODE_ATTRIBUTE:
732 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
733 break;
734
735 default:
736 return STATUS_INVALID_PARAMETER;
737 }
738
739 /*
740 * For optimization purposes, Windows (and hence ReactOS, too, for
741 * compatibility reasons) uses a static buffer if no more than eighty
742 * bytes are read. Otherwise a new buffer is used.
743 * The client-side expects that we know this behaviour.
744 */
745 if (ReadOutputCodeRequest->NumCodes * CodeSize <= sizeof(ReadOutputCodeRequest->CodeStaticBuffer))
746 {
747 /*
748 * Adjust the internal pointer, because its old value points to
749 * the static buffer in the original ApiMessage structure.
750 */
751 // ReadOutputCodeRequest->pCode = ReadOutputCodeRequest->CodeStaticBuffer;
752 pCode = ReadOutputCodeRequest->CodeStaticBuffer;
753 }
754 else
755 {
756 if (!CsrValidateMessageBuffer(ApiMessage,
757 (PVOID*)&ReadOutputCodeRequest->pCode,
758 ReadOutputCodeRequest->NumCodes,
759 CodeSize))
760 {
761 return STATUS_INVALID_PARAMETER;
762 }
763
764 pCode = ReadOutputCodeRequest->pCode;
765 }
766
767 Status = ConSrvGetTextModeBuffer(ProcessData,
768 ReadOutputCodeRequest->OutputHandle,
769 &Buffer, GENERIC_READ, TRUE);
770 if (!NT_SUCCESS(Status))
771 {
772 ReadOutputCodeRequest->NumCodes = 0;
773 return Status;
774 }
775
776 ASSERT((PCONSOLE)Console == Buffer->Header.Console);
777
778 Status = ConDrvReadConsoleOutputString((PCONSOLE)Console,
779 Buffer,
780 ReadOutputCodeRequest->CodeType,
781 pCode,
782 ReadOutputCodeRequest->NumCodes,
783 &ReadOutputCodeRequest->Coord,
784 // &ReadOutputCodeRequest->EndCoord,
785 &ReadOutputCodeRequest->NumCodes);
786
787 ConSrvReleaseScreenBuffer(Buffer, TRUE);
788 return Status;
789 }
790
791 NTSTATUS NTAPI
792 ConDrvWriteConsoleOutputString(IN PCONSOLE Console,
793 IN PTEXTMODE_SCREEN_BUFFER Buffer,
794 IN CODE_TYPE CodeType,
795 IN PVOID StringBuffer,
796 IN ULONG NumCodesToWrite,
797 IN PCOORD WriteCoord,
798 // OUT PCOORD EndCoord,
799 OUT PULONG NumCodesWritten OPTIONAL);
800 /* API_NUMBER: ConsolepWriteConsoleOutputString */
CON_API(SrvWriteConsoleOutputString,CONSOLE_WRITEOUTPUTCODE,WriteOutputCodeRequest)801 CON_API(SrvWriteConsoleOutputString,
802 CONSOLE_WRITEOUTPUTCODE, WriteOutputCodeRequest)
803 {
804 NTSTATUS Status;
805 PTEXTMODE_SCREEN_BUFFER Buffer;
806 ULONG CodeSize;
807 PVOID pCode;
808
809 switch (WriteOutputCodeRequest->CodeType)
810 {
811 case CODE_ASCII:
812 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
813 break;
814
815 case CODE_UNICODE:
816 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
817 break;
818
819 case CODE_ATTRIBUTE:
820 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
821 break;
822
823 default:
824 return STATUS_INVALID_PARAMETER;
825 }
826
827 /*
828 * For optimization purposes, Windows (and hence ReactOS, too, for
829 * compatibility reasons) uses a static buffer if no more than eighty
830 * bytes are written. Otherwise a new buffer is used.
831 * The client-side expects that we know this behaviour.
832 */
833 if (WriteOutputCodeRequest->NumCodes * CodeSize <= sizeof(WriteOutputCodeRequest->CodeStaticBuffer))
834 {
835 /*
836 * Adjust the internal pointer, because its old value points to
837 * the static buffer in the original ApiMessage structure.
838 */
839 // WriteOutputCodeRequest->pCode = WriteOutputCodeRequest->CodeStaticBuffer;
840 pCode = WriteOutputCodeRequest->CodeStaticBuffer;
841 }
842 else
843 {
844 if (!CsrValidateMessageBuffer(ApiMessage,
845 (PVOID*)&WriteOutputCodeRequest->pCode,
846 WriteOutputCodeRequest->NumCodes,
847 CodeSize))
848 {
849 return STATUS_INVALID_PARAMETER;
850 }
851
852 pCode = WriteOutputCodeRequest->pCode;
853 }
854
855 Status = ConSrvGetTextModeBuffer(ProcessData,
856 WriteOutputCodeRequest->OutputHandle,
857 &Buffer, GENERIC_WRITE, TRUE);
858 if (!NT_SUCCESS(Status))
859 {
860 WriteOutputCodeRequest->NumCodes = 0;
861 return Status;
862 }
863
864 ASSERT((PCONSOLE)Console == Buffer->Header.Console);
865
866 Status = ConDrvWriteConsoleOutputString((PCONSOLE)Console,
867 Buffer,
868 WriteOutputCodeRequest->CodeType,
869 pCode,
870 WriteOutputCodeRequest->NumCodes,
871 &WriteOutputCodeRequest->Coord,
872 // &WriteOutputCodeRequest->EndCoord,
873 &WriteOutputCodeRequest->NumCodes);
874
875 ConSrvReleaseScreenBuffer(Buffer, TRUE);
876 return Status;
877 }
878
879 NTSTATUS NTAPI
880 ConDrvFillConsoleOutput(IN PCONSOLE Console,
881 IN PTEXTMODE_SCREEN_BUFFER Buffer,
882 IN CODE_TYPE CodeType,
883 IN CODE_ELEMENT Code,
884 IN ULONG NumCodesToWrite,
885 IN PCOORD WriteCoord,
886 OUT PULONG NumCodesWritten OPTIONAL);
887 /* API_NUMBER: ConsolepFillConsoleOutput */
CON_API(SrvFillConsoleOutput,CONSOLE_FILLOUTPUTCODE,FillOutputRequest)888 CON_API(SrvFillConsoleOutput,
889 CONSOLE_FILLOUTPUTCODE, FillOutputRequest)
890 {
891 NTSTATUS Status;
892 PTEXTMODE_SCREEN_BUFFER Buffer;
893 CODE_TYPE CodeType = FillOutputRequest->CodeType;
894
895 if ( (CodeType != CODE_ASCII ) &&
896 (CodeType != CODE_UNICODE ) &&
897 (CodeType != CODE_ATTRIBUTE) )
898 {
899 return STATUS_INVALID_PARAMETER;
900 }
901
902 Status = ConSrvGetTextModeBuffer(ProcessData,
903 FillOutputRequest->OutputHandle,
904 &Buffer, GENERIC_WRITE, TRUE);
905 if (!NT_SUCCESS(Status))
906 {
907 FillOutputRequest->NumCodes = 0;
908 return Status;
909 }
910
911 ASSERT((PCONSOLE)Console == Buffer->Header.Console);
912
913 Status = ConDrvFillConsoleOutput((PCONSOLE)Console,
914 Buffer,
915 CodeType,
916 FillOutputRequest->Code,
917 FillOutputRequest->NumCodes,
918 &FillOutputRequest->WriteCoord,
919 &FillOutputRequest->NumCodes);
920
921 ConSrvReleaseScreenBuffer(Buffer, TRUE);
922 return Status;
923 }
924
925 NTSTATUS NTAPI
926 ConDrvGetConsoleScreenBufferInfo(IN PCONSOLE Console,
927 IN PTEXTMODE_SCREEN_BUFFER Buffer,
928 OUT PCOORD ScreenBufferSize,
929 OUT PCOORD CursorPosition,
930 OUT PCOORD ViewOrigin,
931 OUT PCOORD ViewSize,
932 OUT PCOORD MaximumViewSize,
933 OUT PWORD Attributes);
934 /* API_NUMBER: ConsolepGetScreenBufferInfo */
CON_API(SrvGetConsoleScreenBufferInfo,CONSOLE_GETSCREENBUFFERINFO,ScreenBufferInfoRequest)935 CON_API(SrvGetConsoleScreenBufferInfo,
936 CONSOLE_GETSCREENBUFFERINFO, ScreenBufferInfoRequest)
937 {
938 NTSTATUS Status;
939 PTEXTMODE_SCREEN_BUFFER Buffer;
940
941 Status = ConSrvGetTextModeBuffer(ProcessData,
942 ScreenBufferInfoRequest->OutputHandle,
943 &Buffer, GENERIC_READ, TRUE);
944 if (!NT_SUCCESS(Status))
945 return Status;
946
947 ASSERT((PCONSOLE)Console == Buffer->Header.Console);
948
949 Status = ConDrvGetConsoleScreenBufferInfo((PCONSOLE)Console,
950 Buffer,
951 &ScreenBufferInfoRequest->ScreenBufferSize,
952 &ScreenBufferInfoRequest->CursorPosition,
953 &ScreenBufferInfoRequest->ViewOrigin,
954 &ScreenBufferInfoRequest->ViewSize,
955 &ScreenBufferInfoRequest->MaximumViewSize,
956 &ScreenBufferInfoRequest->Attributes);
957
958 ConSrvReleaseScreenBuffer(Buffer, TRUE);
959 return Status;
960 }
961
962 NTSTATUS NTAPI
963 ConDrvSetConsoleTextAttribute(IN PCONSOLE Console,
964 IN PTEXTMODE_SCREEN_BUFFER Buffer,
965 IN WORD Attributes);
966 /* API_NUMBER: ConsolepSetTextAttribute */
CON_API(SrvSetConsoleTextAttribute,CONSOLE_SETTEXTATTRIB,SetTextAttribRequest)967 CON_API(SrvSetConsoleTextAttribute,
968 CONSOLE_SETTEXTATTRIB, SetTextAttribRequest)
969 {
970 NTSTATUS Status;
971 PTEXTMODE_SCREEN_BUFFER Buffer;
972
973 Status = ConSrvGetTextModeBuffer(ProcessData,
974 SetTextAttribRequest->OutputHandle,
975 &Buffer, GENERIC_WRITE, TRUE);
976 if (!NT_SUCCESS(Status))
977 return Status;
978
979 ASSERT((PCONSOLE)Console == Buffer->Header.Console);
980
981 Status = ConDrvSetConsoleTextAttribute((PCONSOLE)Console,
982 Buffer,
983 SetTextAttribRequest->Attributes);
984
985 ConSrvReleaseScreenBuffer(Buffer, TRUE);
986 return Status;
987 }
988
989 NTSTATUS NTAPI
990 ConDrvSetConsoleScreenBufferSize(IN PCONSOLE Console,
991 IN PTEXTMODE_SCREEN_BUFFER Buffer,
992 IN PCOORD Size);
993 /* API_NUMBER: ConsolepSetScreenBufferSize */
CON_API(SrvSetConsoleScreenBufferSize,CONSOLE_SETSCREENBUFFERSIZE,SetScreenBufferSizeRequest)994 CON_API(SrvSetConsoleScreenBufferSize,
995 CONSOLE_SETSCREENBUFFERSIZE, SetScreenBufferSizeRequest)
996 {
997 NTSTATUS Status;
998 PTEXTMODE_SCREEN_BUFFER Buffer;
999
1000 Status = ConSrvGetTextModeBuffer(ProcessData,
1001 SetScreenBufferSizeRequest->OutputHandle,
1002 &Buffer, GENERIC_WRITE, TRUE);
1003 if (!NT_SUCCESS(Status))
1004 return Status;
1005
1006 ASSERT((PCONSOLE)Console == Buffer->Header.Console);
1007
1008 Status = ConDrvSetConsoleScreenBufferSize((PCONSOLE)Console,
1009 Buffer,
1010 &SetScreenBufferSizeRequest->Size);
1011
1012 ConSrvReleaseScreenBuffer(Buffer, TRUE);
1013 return Status;
1014 }
1015
1016 NTSTATUS NTAPI
1017 ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
1018 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1019 IN BOOLEAN Unicode,
1020 IN PSMALL_RECT ScrollRectangle,
1021 IN BOOLEAN UseClipRectangle,
1022 IN PSMALL_RECT ClipRectangle OPTIONAL,
1023 IN PCOORD DestinationOrigin,
1024 IN CHAR_INFO FillChar);
1025 /* API_NUMBER: ConsolepScrollScreenBuffer */
CON_API(SrvScrollConsoleScreenBuffer,CONSOLE_SCROLLSCREENBUFFER,ScrollScreenBufferRequest)1026 CON_API(SrvScrollConsoleScreenBuffer,
1027 CONSOLE_SCROLLSCREENBUFFER, ScrollScreenBufferRequest)
1028 {
1029 NTSTATUS Status;
1030 PTEXTMODE_SCREEN_BUFFER Buffer;
1031
1032 Status = ConSrvGetTextModeBuffer(ProcessData,
1033 ScrollScreenBufferRequest->OutputHandle,
1034 &Buffer, GENERIC_WRITE, TRUE);
1035 if (!NT_SUCCESS(Status))
1036 return Status;
1037
1038 ASSERT((PCONSOLE)Console == Buffer->Header.Console);
1039
1040 Status = ConDrvScrollConsoleScreenBuffer((PCONSOLE)Console,
1041 Buffer,
1042 ScrollScreenBufferRequest->Unicode,
1043 &ScrollScreenBufferRequest->ScrollRectangle,
1044 ScrollScreenBufferRequest->UseClipRectangle,
1045 &ScrollScreenBufferRequest->ClipRectangle,
1046 &ScrollScreenBufferRequest->DestinationOrigin,
1047 ScrollScreenBufferRequest->Fill);
1048
1049 ConSrvReleaseScreenBuffer(Buffer, TRUE);
1050 return Status;
1051 }
1052
1053 NTSTATUS NTAPI
1054 ConDrvSetConsoleWindowInfo(IN PCONSOLE Console,
1055 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1056 IN BOOLEAN Absolute,
1057 IN PSMALL_RECT WindowRect);
1058 /* API_NUMBER: ConsolepSetWindowInfo */
CON_API(SrvSetConsoleWindowInfo,CONSOLE_SETWINDOWINFO,SetWindowInfoRequest)1059 CON_API(SrvSetConsoleWindowInfo,
1060 CONSOLE_SETWINDOWINFO, SetWindowInfoRequest)
1061 {
1062 NTSTATUS Status;
1063 // PCONSOLE_SCREEN_BUFFER Buffer;
1064 PTEXTMODE_SCREEN_BUFFER Buffer;
1065
1066 DPRINT("SrvSetConsoleWindowInfo(0x%08x, %d, {L%d, T%d, R%d, B%d}) called\n",
1067 SetWindowInfoRequest->OutputHandle, SetWindowInfoRequest->Absolute,
1068 SetWindowInfoRequest->WindowRect.Left ,
1069 SetWindowInfoRequest->WindowRect.Top ,
1070 SetWindowInfoRequest->WindowRect.Right,
1071 SetWindowInfoRequest->WindowRect.Bottom);
1072
1073 // ConSrvGetScreenBuffer
1074 Status = ConSrvGetTextModeBuffer(ProcessData,
1075 SetWindowInfoRequest->OutputHandle,
1076 &Buffer, GENERIC_READ, TRUE);
1077 if (!NT_SUCCESS(Status))
1078 return Status;
1079
1080 ASSERT((PCONSOLE)Console == Buffer->Header.Console);
1081
1082 Status = ConDrvSetConsoleWindowInfo((PCONSOLE)Console,
1083 Buffer,
1084 SetWindowInfoRequest->Absolute,
1085 &SetWindowInfoRequest->WindowRect);
1086
1087 ConSrvReleaseScreenBuffer(Buffer, TRUE);
1088 return Status;
1089 }
1090
1091 /* EOF */
1092