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