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