システム コールを使用せずにシステム カラーのように動作するメソッドが必要です。setConsoleTextAttribute() があることは知っていますが、それは前景と背景全体を色だけの新しい文字で埋めません。これをすべてのウィンドウと互換性を持たせたいのですが、私はwindows7を使用しています
1 に答える
あなたのコメントによると、解決しようとしている問題に対するより完全な解決策があります。これは、私の元の回答 (この回答の最後にあります) に基づいています。
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;
}