Sync to trunk revision 63922.
[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 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 if (!CsrCreateWait(&ScreenBuffer->Header.Console->WriteWaitQueue,
421 WriteConsoleThread,
422 ClientThread,
423 ApiMessage,
424 NULL))
425 {
426 /* Fail */
427 Status = STATUS_NO_MEMORY;
428 goto Quit;
429 }
430 }
431
432 /* Wait until we un-pause the console */
433 // Status = STATUS_PENDING;
434 }
435 else
436 {
437 /* We read all what we wanted. Set the number of bytes written. */
438 WriteConsoleRequest->NumBytes = NrCharactersWritten * CharSize;
439 }
440
441 Quit:
442 ConSrvReleaseScreenBuffer(ScreenBuffer, FALSE);
443 return Status;
444 }
445
446
447 /* TEXT OUTPUT APIS ***********************************************************/
448
449 NTSTATUS NTAPI
450 ConDrvReadConsoleOutput(IN PCONSOLE Console,
451 IN PTEXTMODE_SCREEN_BUFFER Buffer,
452 IN BOOLEAN Unicode,
453 OUT PCHAR_INFO CharInfo/*Buffer*/,
454 IN OUT PSMALL_RECT ReadRegion);
455 CSR_API(SrvReadConsoleOutput)
456 {
457 NTSTATUS Status;
458 PCONSOLE_READOUTPUT ReadOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadOutputRequest;
459 PTEXTMODE_SCREEN_BUFFER Buffer;
460
461 ULONG NumCells;
462 PCHAR_INFO CharInfo;
463
464 DPRINT("SrvReadConsoleOutput\n");
465
466 NumCells = (ReadOutputRequest->ReadRegion.Right - ReadOutputRequest->ReadRegion.Left + 1) *
467 (ReadOutputRequest->ReadRegion.Bottom - ReadOutputRequest->ReadRegion.Top + 1);
468
469 /*
470 * For optimization purposes, Windows (and hence ReactOS, too, for
471 * compatibility reasons) uses a static buffer if no more than one
472 * cell is read. Otherwise a new buffer is used.
473 * The client-side expects that we know this behaviour.
474 */
475 if (NumCells <= 1)
476 {
477 /*
478 * Adjust the internal pointer, because its old value points to
479 * the static buffer in the original ApiMessage structure.
480 */
481 // ReadOutputRequest->CharInfo = &ReadOutputRequest->StaticBuffer;
482 CharInfo = &ReadOutputRequest->StaticBuffer;
483 }
484 else
485 {
486 if (!CsrValidateMessageBuffer(ApiMessage,
487 (PVOID*)&ReadOutputRequest->CharInfo,
488 NumCells,
489 sizeof(CHAR_INFO)))
490 {
491 return STATUS_INVALID_PARAMETER;
492 }
493
494 CharInfo = ReadOutputRequest->CharInfo;
495 }
496
497 Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
498 ReadOutputRequest->OutputHandle,
499 &Buffer, GENERIC_READ, TRUE);
500 if (!NT_SUCCESS(Status)) return Status;
501
502 Status = ConDrvReadConsoleOutput(Buffer->Header.Console,
503 Buffer,
504 ReadOutputRequest->Unicode,
505 CharInfo,
506 &ReadOutputRequest->ReadRegion);
507
508 ConSrvReleaseScreenBuffer(Buffer, TRUE);
509 return Status;
510 }
511
512 NTSTATUS NTAPI
513 ConDrvWriteConsoleOutput(IN PCONSOLE Console,
514 IN PTEXTMODE_SCREEN_BUFFER Buffer,
515 IN BOOLEAN Unicode,
516 IN PCHAR_INFO CharInfo/*Buffer*/,
517 IN OUT PSMALL_RECT WriteRegion);
518 CSR_API(SrvWriteConsoleOutput)
519 {
520 NTSTATUS Status;
521 PCONSOLE_WRITEOUTPUT WriteOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteOutputRequest;
522 PTEXTMODE_SCREEN_BUFFER Buffer;
523 PCSR_PROCESS Process = CsrGetClientThread()->Process;
524
525 ULONG NumCells;
526 PCHAR_INFO CharInfo;
527
528 DPRINT("SrvWriteConsoleOutput\n");
529
530 NumCells = (WriteOutputRequest->WriteRegion.Right - WriteOutputRequest->WriteRegion.Left + 1) *
531 (WriteOutputRequest->WriteRegion.Bottom - WriteOutputRequest->WriteRegion.Top + 1);
532
533 Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(Process),
534 WriteOutputRequest->OutputHandle,
535 &Buffer, GENERIC_WRITE, TRUE);
536 if (!NT_SUCCESS(Status)) return Status;
537
538 /*
539 * Validate the message buffer if we do not use a process' heap buffer
540 * (CsrAllocateCaptureBuffer succeeded because we haven't allocated
541 * a too large (>= 64 kB, size of the CSR heap) data buffer).
542 */
543 if (!WriteOutputRequest->UseVirtualMemory)
544 {
545 /*
546 * For optimization purposes, Windows (and hence ReactOS, too, for
547 * compatibility reasons) uses a static buffer if no more than one
548 * cell is written. Otherwise a new buffer is used.
549 * The client-side expects that we know this behaviour.
550 */
551 if (NumCells <= 1)
552 {
553 /*
554 * Adjust the internal pointer, because its old value points to
555 * the static buffer in the original ApiMessage structure.
556 */
557 // WriteOutputRequest->CharInfo = &WriteOutputRequest->StaticBuffer;
558 CharInfo = &WriteOutputRequest->StaticBuffer;
559 }
560 else
561 {
562 if (!CsrValidateMessageBuffer(ApiMessage,
563 (PVOID*)&WriteOutputRequest->CharInfo,
564 NumCells,
565 sizeof(CHAR_INFO)))
566 {
567 Status = STATUS_INVALID_PARAMETER;
568 goto Quit;
569 }
570
571 CharInfo = WriteOutputRequest->CharInfo;
572 }
573 }
574 else
575 {
576 /*
577 * This was not the case: we use a heap buffer. Retrieve its contents.
578 */
579 ULONG Size = NumCells * sizeof(CHAR_INFO);
580
581 CharInfo = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size);
582 if (CharInfo == NULL)
583 {
584 Status = STATUS_NO_MEMORY;
585 goto Quit;
586 }
587
588 Status = NtReadVirtualMemory(Process->ProcessHandle,
589 WriteOutputRequest->CharInfo,
590 CharInfo,
591 Size,
592 NULL);
593 if (!NT_SUCCESS(Status))
594 {
595 ConsoleFreeHeap(CharInfo);
596 // Status = STATUS_NO_MEMORY;
597 goto Quit;
598 }
599 }
600
601 Status = ConDrvWriteConsoleOutput(Buffer->Header.Console,
602 Buffer,
603 WriteOutputRequest->Unicode,
604 CharInfo,
605 &WriteOutputRequest->WriteRegion);
606
607 /* Free the temporary buffer if we used the process' heap buffer */
608 if (WriteOutputRequest->UseVirtualMemory && CharInfo)
609 ConsoleFreeHeap(CharInfo);
610
611 Quit:
612 ConSrvReleaseScreenBuffer(Buffer, TRUE);
613 return Status;
614 }
615
616 CSR_API(SrvWriteConsole)
617 {
618 NTSTATUS Status;
619 PCONSOLE_WRITECONSOLE WriteConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteConsoleRequest;
620
621 DPRINT("SrvWriteConsole\n");
622
623 /*
624 * For optimization purposes, Windows (and hence ReactOS, too, for
625 * compatibility reasons) uses a static buffer if no more than eighty
626 * bytes are written. Otherwise a new buffer is used.
627 * The client-side expects that we know this behaviour.
628 */
629 if (WriteConsoleRequest->UsingStaticBuffer &&
630 WriteConsoleRequest->NumBytes <= sizeof(WriteConsoleRequest->StaticBuffer))
631 {
632 /*
633 * Adjust the internal pointer, because its old value points to
634 * the static buffer in the original ApiMessage structure.
635 */
636 // WriteConsoleRequest->Buffer = WriteConsoleRequest->StaticBuffer;
637 }
638 else
639 {
640 if (!CsrValidateMessageBuffer(ApiMessage,
641 (PVOID)&WriteConsoleRequest->Buffer,
642 WriteConsoleRequest->NumBytes,
643 sizeof(BYTE)))
644 {
645 return STATUS_INVALID_PARAMETER;
646 }
647 }
648
649 Status = DoWriteConsole(ApiMessage, CsrGetClientThread(), TRUE);
650
651 if (Status == STATUS_PENDING) *ReplyCode = CsrReplyPending;
652
653 return Status;
654 }
655
656 NTSTATUS NTAPI
657 ConDrvReadConsoleOutputString(IN PCONSOLE Console,
658 IN PTEXTMODE_SCREEN_BUFFER Buffer,
659 IN CODE_TYPE CodeType,
660 OUT PVOID StringBuffer,
661 IN ULONG NumCodesToRead,
662 IN PCOORD ReadCoord,
663 // OUT PCOORD EndCoord,
664 OUT PULONG NumCodesRead OPTIONAL);
665 CSR_API(SrvReadConsoleOutputString)
666 {
667 NTSTATUS Status;
668 PCONSOLE_READOUTPUTCODE ReadOutputCodeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadOutputCodeRequest;
669 PTEXTMODE_SCREEN_BUFFER Buffer;
670 ULONG CodeSize;
671
672 PVOID pCode;
673
674 DPRINT("SrvReadConsoleOutputString\n");
675
676 switch (ReadOutputCodeRequest->CodeType)
677 {
678 case CODE_ASCII:
679 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
680 break;
681
682 case CODE_UNICODE:
683 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
684 break;
685
686 case CODE_ATTRIBUTE:
687 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
688 break;
689
690 default:
691 return STATUS_INVALID_PARAMETER;
692 }
693
694 /*
695 * For optimization purposes, Windows (and hence ReactOS, too, for
696 * compatibility reasons) uses a static buffer if no more than eighty
697 * bytes are read. Otherwise a new buffer is used.
698 * The client-side expects that we know this behaviour.
699 */
700 if (ReadOutputCodeRequest->NumCodes * CodeSize <= sizeof(ReadOutputCodeRequest->CodeStaticBuffer))
701 {
702 /*
703 * Adjust the internal pointer, because its old value points to
704 * the static buffer in the original ApiMessage structure.
705 */
706 // ReadOutputCodeRequest->pCode = ReadOutputCodeRequest->CodeStaticBuffer;
707 pCode = ReadOutputCodeRequest->CodeStaticBuffer;
708 }
709 else
710 {
711 if (!CsrValidateMessageBuffer(ApiMessage,
712 (PVOID*)&ReadOutputCodeRequest->pCode,
713 ReadOutputCodeRequest->NumCodes,
714 CodeSize))
715 {
716 return STATUS_INVALID_PARAMETER;
717 }
718
719 pCode = ReadOutputCodeRequest->pCode;
720 }
721
722 Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
723 ReadOutputCodeRequest->OutputHandle,
724 &Buffer, GENERIC_READ, TRUE);
725 if (!NT_SUCCESS(Status))
726 {
727 ReadOutputCodeRequest->NumCodes = 0;
728 return Status;
729 }
730
731 Status = ConDrvReadConsoleOutputString(Buffer->Header.Console,
732 Buffer,
733 ReadOutputCodeRequest->CodeType,
734 pCode,
735 ReadOutputCodeRequest->NumCodes,
736 &ReadOutputCodeRequest->Coord,
737 // &ReadOutputCodeRequest->EndCoord,
738 &ReadOutputCodeRequest->NumCodes);
739
740 ConSrvReleaseScreenBuffer(Buffer, TRUE);
741 return Status;
742 }
743
744 NTSTATUS NTAPI
745 ConDrvWriteConsoleOutputString(IN PCONSOLE Console,
746 IN PTEXTMODE_SCREEN_BUFFER Buffer,
747 IN CODE_TYPE CodeType,
748 IN PVOID StringBuffer,
749 IN ULONG NumCodesToWrite,
750 IN PCOORD WriteCoord,
751 // OUT PCOORD EndCoord,
752 OUT PULONG NumCodesWritten OPTIONAL);
753 CSR_API(SrvWriteConsoleOutputString)
754 {
755 NTSTATUS Status;
756 PCONSOLE_WRITEOUTPUTCODE WriteOutputCodeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.WriteOutputCodeRequest;
757 PTEXTMODE_SCREEN_BUFFER Buffer;
758 ULONG CodeSize;
759
760 PVOID pCode;
761
762 DPRINT("SrvWriteConsoleOutputString\n");
763
764 switch (WriteOutputCodeRequest->CodeType)
765 {
766 case CODE_ASCII:
767 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
768 break;
769
770 case CODE_UNICODE:
771 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
772 break;
773
774 case CODE_ATTRIBUTE:
775 CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
776 break;
777
778 default:
779 return STATUS_INVALID_PARAMETER;
780 }
781
782 /*
783 * For optimization purposes, Windows (and hence ReactOS, too, for
784 * compatibility reasons) uses a static buffer if no more than eighty
785 * bytes are written. Otherwise a new buffer is used.
786 * The client-side expects that we know this behaviour.
787 */
788 if (WriteOutputCodeRequest->NumCodes * CodeSize <= sizeof(WriteOutputCodeRequest->CodeStaticBuffer))
789 {
790 /*
791 * Adjust the internal pointer, because its old value points to
792 * the static buffer in the original ApiMessage structure.
793 */
794 // WriteOutputCodeRequest->pCode = WriteOutputCodeRequest->CodeStaticBuffer;
795 pCode = WriteOutputCodeRequest->CodeStaticBuffer;
796 }
797 else
798 {
799 if (!CsrValidateMessageBuffer(ApiMessage,
800 (PVOID*)&WriteOutputCodeRequest->pCode,
801 WriteOutputCodeRequest->NumCodes,
802 CodeSize))
803 {
804 return STATUS_INVALID_PARAMETER;
805 }
806
807 pCode = WriteOutputCodeRequest->pCode;
808 }
809
810 Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
811 WriteOutputCodeRequest->OutputHandle,
812 &Buffer, GENERIC_WRITE, TRUE);
813 if (!NT_SUCCESS(Status))
814 {
815 WriteOutputCodeRequest->NumCodes = 0;
816 return Status;
817 }
818
819 Status = ConDrvWriteConsoleOutputString(Buffer->Header.Console,
820 Buffer,
821 WriteOutputCodeRequest->CodeType,
822 pCode,
823 WriteOutputCodeRequest->NumCodes,
824 &WriteOutputCodeRequest->Coord,
825 // &WriteOutputCodeRequest->EndCoord,
826 &WriteOutputCodeRequest->NumCodes);
827
828 ConSrvReleaseScreenBuffer(Buffer, TRUE);
829 return Status;
830 }
831
832 NTSTATUS NTAPI
833 ConDrvFillConsoleOutput(IN PCONSOLE Console,
834 IN PTEXTMODE_SCREEN_BUFFER Buffer,
835 IN CODE_TYPE CodeType,
836 IN CODE_ELEMENT Code,
837 IN ULONG NumCodesToWrite,
838 IN PCOORD WriteCoord,
839 OUT PULONG NumCodesWritten OPTIONAL);
840 CSR_API(SrvFillConsoleOutput)
841 {
842 NTSTATUS Status;
843 PCONSOLE_FILLOUTPUTCODE FillOutputRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.FillOutputRequest;
844 PTEXTMODE_SCREEN_BUFFER Buffer;
845 CODE_TYPE CodeType = FillOutputRequest->CodeType;
846
847 DPRINT("SrvFillConsoleOutput\n");
848
849 if ( (CodeType != CODE_ASCII ) &&
850 (CodeType != CODE_UNICODE ) &&
851 (CodeType != CODE_ATTRIBUTE) )
852 {
853 return STATUS_INVALID_PARAMETER;
854 }
855
856 Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
857 FillOutputRequest->OutputHandle,
858 &Buffer, GENERIC_WRITE, TRUE);
859 if (!NT_SUCCESS(Status))
860 {
861 FillOutputRequest->NumCodes = 0;
862 return Status;
863 }
864
865 Status = ConDrvFillConsoleOutput(Buffer->Header.Console,
866 Buffer,
867 CodeType,
868 FillOutputRequest->Code,
869 FillOutputRequest->NumCodes,
870 &FillOutputRequest->WriteCoord,
871 &FillOutputRequest->NumCodes);
872
873 ConSrvReleaseScreenBuffer(Buffer, TRUE);
874 return Status;
875 }
876
877 NTSTATUS NTAPI
878 ConDrvGetConsoleScreenBufferInfo(IN PCONSOLE Console,
879 IN PTEXTMODE_SCREEN_BUFFER Buffer,
880 OUT PCOORD ScreenBufferSize,
881 OUT PCOORD CursorPosition,
882 OUT PCOORD ViewOrigin,
883 OUT PCOORD ViewSize,
884 OUT PCOORD MaximumViewSize,
885 OUT PWORD Attributes);
886 CSR_API(SrvGetConsoleScreenBufferInfo)
887 {
888 NTSTATUS Status;
889 PCONSOLE_GETSCREENBUFFERINFO ScreenBufferInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ScreenBufferInfoRequest;
890 PTEXTMODE_SCREEN_BUFFER Buffer;
891
892 DPRINT("SrvGetConsoleScreenBufferInfo\n");
893
894 Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
895 ScreenBufferInfoRequest->OutputHandle,
896 &Buffer, GENERIC_READ, TRUE);
897 if (!NT_SUCCESS(Status)) return Status;
898
899 Status = ConDrvGetConsoleScreenBufferInfo(Buffer->Header.Console,
900 Buffer,
901 &ScreenBufferInfoRequest->ScreenBufferSize,
902 &ScreenBufferInfoRequest->CursorPosition,
903 &ScreenBufferInfoRequest->ViewOrigin,
904 &ScreenBufferInfoRequest->ViewSize,
905 &ScreenBufferInfoRequest->MaximumViewSize,
906 &ScreenBufferInfoRequest->Attributes);
907
908 ConSrvReleaseScreenBuffer(Buffer, TRUE);
909 return Status;
910 }
911
912 NTSTATUS NTAPI
913 ConDrvSetConsoleTextAttribute(IN PCONSOLE Console,
914 IN PTEXTMODE_SCREEN_BUFFER Buffer,
915 IN WORD Attributes);
916 CSR_API(SrvSetConsoleTextAttribute)
917 {
918 NTSTATUS Status;
919 PCONSOLE_SETTEXTATTRIB SetTextAttribRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetTextAttribRequest;
920 PTEXTMODE_SCREEN_BUFFER Buffer;
921
922 DPRINT("SrvSetConsoleTextAttribute\n");
923
924 Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
925 SetTextAttribRequest->OutputHandle,
926 &Buffer, GENERIC_WRITE, TRUE);
927 if (!NT_SUCCESS(Status)) return Status;
928
929 Status = ConDrvSetConsoleTextAttribute(Buffer->Header.Console,
930 Buffer,
931 SetTextAttribRequest->Attributes);
932
933 ConSrvReleaseScreenBuffer(Buffer, TRUE);
934 return Status;
935 }
936
937 NTSTATUS NTAPI
938 ConDrvSetConsoleScreenBufferSize(IN PCONSOLE Console,
939 IN PTEXTMODE_SCREEN_BUFFER Buffer,
940 IN PCOORD Size);
941 CSR_API(SrvSetConsoleScreenBufferSize)
942 {
943 NTSTATUS Status;
944 PCONSOLE_SETSCREENBUFFERSIZE SetScreenBufferSizeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetScreenBufferSizeRequest;
945 PTEXTMODE_SCREEN_BUFFER Buffer;
946
947 DPRINT("SrvSetConsoleScreenBufferSize\n");
948
949 Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
950 SetScreenBufferSizeRequest->OutputHandle,
951 &Buffer, GENERIC_WRITE, TRUE);
952 if (!NT_SUCCESS(Status)) return Status;
953
954 Status = ConDrvSetConsoleScreenBufferSize(Buffer->Header.Console,
955 Buffer,
956 &SetScreenBufferSizeRequest->Size);
957
958 ConSrvReleaseScreenBuffer(Buffer, TRUE);
959 return Status;
960 }
961
962 NTSTATUS NTAPI
963 ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
964 IN PTEXTMODE_SCREEN_BUFFER Buffer,
965 IN BOOLEAN Unicode,
966 IN PSMALL_RECT ScrollRectangle,
967 IN BOOLEAN UseClipRectangle,
968 IN PSMALL_RECT ClipRectangle OPTIONAL,
969 IN PCOORD DestinationOrigin,
970 IN CHAR_INFO FillChar);
971 CSR_API(SrvScrollConsoleScreenBuffer)
972 {
973 NTSTATUS Status;
974 PCONSOLE_SCROLLSCREENBUFFER ScrollScreenBufferRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ScrollScreenBufferRequest;
975 PTEXTMODE_SCREEN_BUFFER Buffer;
976
977 DPRINT("SrvScrollConsoleScreenBuffer\n");
978
979 Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
980 ScrollScreenBufferRequest->OutputHandle,
981 &Buffer, GENERIC_WRITE, TRUE);
982 if (!NT_SUCCESS(Status)) return Status;
983
984 Status = ConDrvScrollConsoleScreenBuffer(Buffer->Header.Console,
985 Buffer,
986 ScrollScreenBufferRequest->Unicode,
987 &ScrollScreenBufferRequest->ScrollRectangle,
988 ScrollScreenBufferRequest->UseClipRectangle,
989 &ScrollScreenBufferRequest->ClipRectangle,
990 &ScrollScreenBufferRequest->DestinationOrigin,
991 ScrollScreenBufferRequest->Fill);
992
993 ConSrvReleaseScreenBuffer(Buffer, TRUE);
994 return Status;
995 }
996
997 NTSTATUS NTAPI
998 ConDrvSetConsoleWindowInfo(IN PCONSOLE Console,
999 IN PTEXTMODE_SCREEN_BUFFER Buffer,
1000 IN BOOLEAN Absolute,
1001 IN PSMALL_RECT WindowRect);
1002 CSR_API(SrvSetConsoleWindowInfo)
1003 {
1004 NTSTATUS Status;
1005 PCONSOLE_SETWINDOWINFO SetWindowInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetWindowInfoRequest;
1006 // PCONSOLE_SCREEN_BUFFER Buffer;
1007 PTEXTMODE_SCREEN_BUFFER Buffer;
1008
1009 DPRINT1("SrvSetConsoleWindowInfo(0x%08x, %d, {L%d, T%d, R%d, B%d}) called\n",
1010 SetWindowInfoRequest->OutputHandle, SetWindowInfoRequest->Absolute,
1011 SetWindowInfoRequest->WindowRect.Left ,
1012 SetWindowInfoRequest->WindowRect.Top ,
1013 SetWindowInfoRequest->WindowRect.Right,
1014 SetWindowInfoRequest->WindowRect.Bottom);
1015
1016 // ConSrvGetScreenBuffer
1017 Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
1018 SetWindowInfoRequest->OutputHandle,
1019 &Buffer, GENERIC_READ, TRUE);
1020 if (!NT_SUCCESS(Status)) return Status;
1021
1022 Status = ConDrvSetConsoleWindowInfo(Buffer->Header.Console,
1023 Buffer,
1024 SetWindowInfoRequest->Absolute,
1025 &SetWindowInfoRequest->WindowRect);
1026
1027 ConSrvReleaseScreenBuffer(Buffer, TRUE);
1028 return Status;
1029 }
1030
1031 /* EOF */