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