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