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