static VOID FASTCALL TuiCopyRect(PCHAR Dest, PTEXTMODE_SCREEN_BUFFER Buff, SMALL_RECT* Region) { UINT SrcDelta, DestDelta; LONG i; PCHAR_INFO Src, SrcEnd; Src = ConioCoordToPointer(Buff, Region->Left, Region->Top); SrcDelta = Buff->ScreenBufferSize.X * sizeof(CHAR_INFO); SrcEnd = Buff->Buffer + Buff->ScreenBufferSize.Y * Buff->ScreenBufferSize.X * sizeof(CHAR_INFO); DestDelta = ConioRectWidth(Region) * 2 /* 2 == sizeof(CHAR) + sizeof(BYTE) */; for (i = Region->Top; i <= Region->Bottom; i++) { ConsoleUnicodeCharToAnsiChar(Buff->Header.Console, (PCHAR)Dest, &Src->Char.UnicodeChar); *(PBYTE)(Dest + 1) = (BYTE)Src->Attributes; Src += SrcDelta; if (SrcEnd <= Src) { Src -= Buff->ScreenBufferSize.Y * Buff->ScreenBufferSize.X * sizeof(CHAR_INFO); } Dest += DestDelta; } }
NTSTATUS NTAPI ConDrvReadConsoleOutputString(IN PCONSOLE Console, IN PTEXTMODE_SCREEN_BUFFER Buffer, IN CODE_TYPE CodeType, OUT PVOID StringBuffer, IN ULONG NumCodesToRead, IN PCOORD ReadCoord, OUT PCOORD EndCoord, OUT PULONG CodesRead) { SHORT Xpos, Ypos; PVOID ReadBuffer; ULONG i; ULONG CodeSize; PCHAR_INFO Ptr; if (Console == NULL || Buffer == NULL || ReadCoord == NULL || EndCoord == NULL || CodesRead == NULL) { return STATUS_INVALID_PARAMETER; } /* Validity checks */ ASSERT(Console == Buffer->Header.Console); ASSERT( (StringBuffer != NULL && NumCodesToRead >= 0) || (StringBuffer == NULL && NumCodesToRead == 0) ); switch (CodeType) { case CODE_ASCII: CodeSize = sizeof(CHAR); break; case CODE_UNICODE: CodeSize = sizeof(WCHAR); break; case CODE_ATTRIBUTE: CodeSize = sizeof(WORD); break; default: return STATUS_INVALID_PARAMETER; } ReadBuffer = StringBuffer; Xpos = ReadCoord->X; Ypos = (ReadCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y; /* * MSDN (ReadConsoleOutputAttribute and ReadConsoleOutputCharacter) : * * If the number of attributes (resp. characters) to be read from extends * beyond the end of the specified screen buffer row, attributes (resp. * characters) are read from the next row. If the number of attributes * (resp. characters) to be read from extends beyond the end of the console * screen buffer, attributes (resp. characters) up to the end of the console * screen buffer are read. * * TODO: Do NOT loop up to NumCodesToRead, but stop before * if we are going to overflow... */ // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work for (i = 0; i < min(NumCodesToRead, Buffer->ScreenBufferSize.X * Buffer->ScreenBufferSize.Y); ++i) { // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work either Ptr = &Buffer->Buffer[Xpos + Ypos * Buffer->ScreenBufferSize.X]; switch (CodeType) { case CODE_ASCII: ConsoleUnicodeCharToAnsiChar(Console, (PCHAR)ReadBuffer, &Ptr->Char.UnicodeChar); break; case CODE_UNICODE: *(PWCHAR)ReadBuffer = Ptr->Char.UnicodeChar; break; case CODE_ATTRIBUTE: *(PWORD)ReadBuffer = Ptr->Attributes; break; } ReadBuffer = (PVOID)((ULONG_PTR)ReadBuffer + CodeSize); // ++Ptr; Xpos++; if (Xpos == Buffer->ScreenBufferSize.X) { Xpos = 0; Ypos++; if (Ypos == Buffer->ScreenBufferSize.Y) { Ypos = 0; } } } // switch (CodeType) // { // case CODE_UNICODE: // *(PWCHAR)ReadBuffer = 0; // break; // case CODE_ASCII: // *(PCHAR)ReadBuffer = 0; // break; // case CODE_ATTRIBUTE: // *(PWORD)ReadBuffer = 0; // break; // } EndCoord->X = Xpos; EndCoord->Y = (Ypos - Buffer->VirtualY + Buffer->ScreenBufferSize.Y) % Buffer->ScreenBufferSize.Y; *CodesRead = (ULONG)((ULONG_PTR)ReadBuffer - (ULONG_PTR)StringBuffer) / CodeSize; // <= NumCodesToRead return STATUS_SUCCESS; }