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