0

システム コールを使用せずにシステム カラーのように動作するメソッドが必要です。setConsoleTextAttribute() があることは知っていますが、それは前景と背景全体を色だけの新しい文字で埋めません。これをすべてのウィンドウと互換性を持たせたいのですが、私はwindows7を使用しています

4

1 に答える 1

0

あなたのコメントによると、解決しようとしている問題に対するより完全な解決策があります。これは、私の元の回答 (この回答の最後にあります) に基づいています。

Windows API の 1 つの制限を発見しました。それは、80 列 x 300 行の既定のコンソール モード ウィンドウの画面バッファー全体を読み取ることができないということです。Windows プロセス ヒープが不十分であるため、ERROR_NOT_ENOUGH_MEMORY エラーが発生します (Google 検索からわかる限り)。XxxConsoleOutput 関数の周りにラッパーを実装して、関数が成功するか、1 X 1 (1 文字) 領域の読み取りに失敗するまで、必要に応じて画面バッファー領域の自動分割をサポートしました。

繰り返しますが、このコードはおそらく完全ではありません。概念を説明するためのものであり、(必ずしも) 完全なソリューションを提供するためのものではありません。ただし、現在はコンソール全体を埋め (以前はウィンドウの表示部分のみを埋めていました)、将来の出力のためにコンソールのテキスト属性を設定します。

元の回答を読むには、このコードをスキップしてください。

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>

#include <iostream>
#include <vector>

using namespace std;

// Split a rectangular region into two smaller rectangles
// based on the largest dimension.
void SplitRegion(
    SHORT width, SHORT height,
    COORD dwBufferCoord, const SMALL_RECT& readRegion,
    COORD& dwBufferCoordA, SMALL_RECT& readRegionA,
    COORD& dwBufferCoordB, SMALL_RECT& readRegionB)
{
    dwBufferCoordA = dwBufferCoordB = dwBufferCoord;
    readRegionA = readRegionB = readRegion;

    if (height >= width)
    {
        SHORT half = height / 2;
        dwBufferCoordB.Y += half;
        readRegionB.Top += half;
        readRegionA.Bottom = readRegionB.Top - 1;
    }
    else
    {
        SHORT half = width / 2;
        dwBufferCoordB.X += half;
        readRegionB.Left += half;
        readRegionA.Right = readRegionB.Left - 1;
    }
}

// Utility function to figure out the distance
// between two points.
template <typename type>
inline type DiffHelper(type first, type second)
{
    return (second >= first) ? (second - first + 1) : 0;
}

// A template that wraps up the shared code common between
// reading and writing the screen buffer. If it is ever
// given a region of zero width or height, it will
// "succeed". If it ever tries to subdivide a 1 by 1
// region, it will fail.
template <typename lpBufferType>
BOOL XferConsoleOutputWrapper(
    HANDLE hConsoleOutput, 
    lpBufferType lpBuffer, 
    COORD dwBufferSize, 
    COORD dwBufferCoord, 
    SMALL_RECT& xferRegion,
    BOOL (WINAPI * xferConsoleOutput)(
        HANDLE, lpBufferType, COORD, COORD, PSMALL_RECT))
{
    SHORT width = DiffHelper(xferRegion.Left, xferRegion.Right);
    SHORT height = DiffHelper(xferRegion.Top, xferRegion.Bottom);

    if ((width == 0) || (height == 0))
    {
        return TRUE;
    }

    BOOL success = xferConsoleOutput(hConsoleOutput, 
        lpBuffer, dwBufferSize, dwBufferCoord, &xferRegion);
    if (!success)
    {
        if ((GetLastError() == ERROR_NOT_ENOUGH_MEMORY) &&
            ((width * height) > 1))
        {
            COORD dwBufferCoordA, dwBufferCoordB;
            SMALL_RECT xferRegionA, xferRegionB;
            SplitRegion(
                width, height,
                dwBufferCoord, xferRegion,
                dwBufferCoordA, xferRegionA,
                dwBufferCoordB, xferRegionB);
            success =
                XferConsoleOutputWrapper(hConsoleOutput, lpBuffer, dwBufferSize,
                    dwBufferCoordA, xferRegionA, xferConsoleOutput) &&
                XferConsoleOutputWrapper(hConsoleOutput, lpBuffer, dwBufferSize,
                    dwBufferCoordB, xferRegionB, xferConsoleOutput);
        }
    }
    return success;
}

// ReadConsoleOutput failed to read an 80 by 300 character screen
// buffer in a single call, resulting in ERROR_NOT_ENOUGH_MEMORY.
// ReadConsoleOutputWrapper will subdivide the operation into
// smaller and smaller chunks as needed until it succeeds in reading
// the entire screen buffer.
inline BOOL ReadConsoleOutputWrapper(
    HANDLE hConsoleOutput, 
    PCHAR_INFO lpBuffer, 
    COORD dwBufferSize, 
    COORD dwBufferCoord, 
    SMALL_RECT& readRegion)
{
    return XferConsoleOutputWrapper(hConsoleOutput, lpBuffer, dwBufferSize,
        dwBufferCoord, readRegion, ReadConsoleOutput);
}

// WriteConsoleOutputWrapper will subdivide the operation into
// smaller and smaller chunks as needed until it succeeds in writing
// the entire screen buffer. This may not be necessary as
// WriteConsoleOutput never failed, but it was simple to implement
// so it was done just to be safe.
inline BOOL WriteConsoleOutputWrapper(
    HANDLE hConsoleOutput, 
    const CHAR_INFO* lpBuffer, 
    COORD dwBufferSize, 
    COORD dwBufferCoord, 
    SMALL_RECT& writeRegion)
{
    return XferConsoleOutputWrapper(hConsoleOutput, lpBuffer, dwBufferSize,
        dwBufferCoord, writeRegion, WriteConsoleOutput);
}

void ConsoleFillWithAttribute(WORD fillAttribute)
{
    // Get the handle to the output
    HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

    // Get the information for the current screen buffer
    CONSOLE_SCREEN_BUFFER_INFO info;
    GetConsoleScreenBufferInfo(hStdout, &info);

    // Allocate a vector to hold the visible screen buffer data
    vector<CHAR_INFO> buffer(info.dwSize.X * info.dwSize.Y);

    // Initialize a couple of pointers to the begin and end of the buffer
    CHAR_INFO* begin = buffer.data();
    CHAR_INFO* end = begin + buffer.size();

    // Start at the upper left corner of the screen buffer.
    COORD coord;
    coord.X = coord.Y = 0;

    // Initialize the region to encompass the entire screen buffer.
    SMALL_RECT region;
    region.Left = region.Top = 0;
    region.Right = info.dwSize.X - 1;
    region.Bottom = info.dwSize.Y - 1;

    // Read the buffer from the console into the CHAR_INFO vector.
    ReadConsoleOutputWrapper(hStdout, buffer.data(), info.dwSize, coord, region);

    // Change all the attributes to the specified fill attribute.
    while (begin != end)
    {
        begin->Attributes = fillAttribute;
        ++begin;
    }

    // Write the buffer from the CHAR_INFO vector back to the console.
    WriteConsoleOutputWrapper(hStdout, buffer.data(), info.dwSize, coord, region);

    // Finally, set the console text attribute to the fill attribute
    // so that all new text will be printed in the same manner as
    // the attributes we just changed.
    SetConsoleTextAttribute(hStdout, fillAttribute);
}

int main()
{
    cout << "I would like to fill up the console with some text." << endl;
    cout << "The quick brown fox jumped over the lazy dogs." << endl;

    for (int i = 0; i < 100; ++i)
    {
        cout << ' ' << i;
    }

    cout << endl;

    ConsoleFillWithAttribute(
        BACKGROUND_BLUE | FOREGROUND_INTENSITY | 
            FOREGROUND_RED | FOREGROUND_GREEN);

    cout << endl;

    cout << "This should also be printed in the new attribute" << endl;

    return 0;
}

元の回答は次のとおりです。

ご質問の内容が理解できた場合は、コンソール モード ウィンドウ全体の属性を変更できるようにしてください。ReadConsoleOutput関数と関数を調べることができWriteConsoleOutputます。を使用ReadConsoleOutputしてコンソール バッファの一部またはすべてをメモリに読み込み、アプリケーションの必要に応じて属性データを操作してから、 を使用WriteConsoleOutputしてメモリをコンソール出力バッファに書き戻すことができます。

コンソールの現在表示されている部分の属性を変更するコードを次に示します (出力がコンソール以外のハンドルにリダイレクトされていないと仮定します)。

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>

#include <iostream>
#include <vector>

using namespace std;

void ConsoleFillDisplayWithAttribute(WORD fillAttribute)
{
    // Get the handle to the output
    HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

    // Get the information for the current screen buffer
    CONSOLE_SCREEN_BUFFER_INFO info;
    GetConsoleScreenBufferInfo(hStdout, &info);

    // Calculate the size of the displayed portion of the screen buffer
    COORD size;
    size.X = (info.srWindow.Right - info.srWindow.Left + 1);
    size.Y = (info.srWindow.Bottom - info.srWindow.Top + 1);

    // Allocate a vector to hold the visible screen buffer data
    vector<CHAR_INFO> buffer(size.X * size.Y);

    COORD coord;
    coord.X = coord.Y = 0;

    // Read the buffer from the console into the CHAR_INFO vector
    ReadConsoleOutput(hStdout, buffer.data(), size, coord, &info.srWindow);

    // Initialize a couple of pointers to the begin and end of the buffer
    CHAR_INFO* begin = buffer.data();
    CHAR_INFO* end = begin + buffer.size();

    // Change all the attributes to the specified fill attribute
    while (begin != end)
    {
        begin->Attributes = fillAttribute;
        ++begin;
    }

    // Write the buffer from the CHAR_INFO vector back to the console
    WriteConsoleOutput(hStdout, buffer.data(), size, coord, &info.srWindow);
}

int main()
{
    cout << "I would like to fill up the console with some text." << endl;
    cout << "The quick brown fox jumped over the lazy dogs." << endl;

    for (int i = 0; i < 100; ++i)
    {
        cout << ' ' << i;
    }

    cout << endl;

    ConsoleFillDisplayWithAttribute(
        BACKGROUND_BLUE | FOREGROUND_INTENSITY | 
            FOREGROUND_RED | FOREGROUND_GREEN);

    return 0;
}
于 2013-02-05T04:48:38.820 に答える