#はじめに
コマンドプロンプト画面(コンソール)は、デフォルトでは黒に白の文字が表示されます。しかし、Win32 コンソール API 関数を使うといろいろな色で文字を表示できます。
この API はハイレベル関数とローレベル関数からなっていて、後者を使用するとコンソール画面の細かな制御が可能です。
参照:MSDN Using the Console
#ハイレベル I/O 関数とローレベル I/O 関数
ハイレベル I/O 関数は ReadFile / WriteFile または ReadConsole / WriteConsole です。これらのグループはほぼ同じ動作を行いますが、ReadFile / WriteFile はワイド文字では使用できません。よって、ReadConsole / WriteConsole を使ったほうがよいでしょう。
このため、ReadFile / WriteFile を使う場合は、プロジェクトのプロパティで「全般」・「文字セット」をマルチバイト文字にする必要があります。
ローレベル I/O 関数を使うと、行単位の入出力だけでなく、文字単位の入出力が行えます。カーソルを制御して文字列の表示位置を変えたり、スクロールを制御したりと、様々な細かな処理ができますが、それだけ多くの関数を使いこなす必要があります。
ハイレベルでは CRLF があると自動的に改行しますが、ローレベルではモードによります。
#文字列の表示と入力
ハイレベル関数を使って文字列の入出力を行うためには、次のような手順が必要です。
- GetStdHandle 関数を使って標準入出力ハンドルを取得する。
- 必要なら標準出力の属性を変更する。(その場合は、デフォルトの属性を取得して保存しておく)
- GetConsoleScreenBufferInfo でデフォルトの属性を取得できる。SetConsoleTextAttribute で属性を変更できる。
- WriteConsole 関数で文字列を出力する。ReadConsole 関数で文字列(行単位)を入力する。
- 最後に、標準出力の属性を元に戻す。
#サンプル
##色を変更した文字列の出力
表示文字列の属性を変更するには、SetConsoleTextAttribute の第二引数で色と明るさを指定します。背景色の変更も同時に行うことができます。
前景色は、 FOREGROUND_xxxx というシステム定義定数を使って指定します。xxxx の部分が色の指定で、BLACK や RED などが指定できます。(指定できるのは原色だけで、任意の色は指定できません)
背景色は、BACKGROUND_xxxx というシステム定義定数を使って指定します。xxxxx の部分(色の名前)は前景色と同じです。
明るさは FOREGROUND_INTENSITY や BACKGROUND_INTENSITY で指定します。明るさの指定は明るい・暗いの2種類だけです。
これらの定数を | 演算子で結合したものが SetConsoleTextAttribute の第二引数になります。下に例を示します。
FOREGROUND_GREEN | FOREGROUND_INTENSITY (前景色が明るい緑、背景色は黒)
FOREGROUND_WHITE | BACKGROUND_BLUE | BAKCGROUND_INTENSITY (前景色が暗い白(シルバー)、背景色は明るい青)
次のサンプルは、 Fig.1 のように色を変えた文字列を表示した後、デフォルトに戻して終了するだけのものです。
Fig.1 色を変更した文字列の出力
##ヘッダーファイル
// stdafx.h : 標準のシステム インクルード ファイルのインクルード ファイル、または
// 参照回数が多く、かつあまり変更されない、プロジェクト専用のインクルード ファイル
// を記述します。
//
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
// TODO: プログラムに必要な追加ヘッダーをここで参照してください
#include <Windows.h>
##CPP ファイル
// ConsoleApi01.cpp : アプリケーションのエントリ ポイントを定義します。
//
#include "stdafx.h"
/*
WriteConsole() の代わりに WriteFile() を使う場合、Unicode でなくマルチバイト文字にしないと正しく表示しない。
*/
int main()
{
HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
if (h == INVALID_HANDLE_VALUE)
{
printf_s("ErrorCode = %d\n", GetLastError());
return -1;
}
LPCSTR str = "Write Console.\n";
LPCSTR done = "Done.\n";
DWORD len = -1;
DWORD n = strlen(str);
DWORD nd = strlen(done);
// デフォルトの表示文字の色を保存
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
if (!GetConsoleScreenBufferInfo(h, &consoleInfo))
{
printf("ErrorCode = %d\n", GetLastError());
return -1;
}
// 表示文字の色を変更
WORD wAttr = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY | BACKGROUND_BLUE;
// 文字列を表示する。
if (!SetConsoleTextAttribute(h, wAttr))
{
printf_s("ErrorCode = %d\n", GetLastError());
return -1;
}
WriteConsole(h, str, n, &len, NULL);
// 表示文字の色を元に戻す。
wAttr = consoleInfo.wAttributes;
SetConsoleTextAttribute(h, wAttr);
WriteConsole(h, done, nd, &len, NULL);
getchar();
return 0;
}
##コンソールから行を入力する
コンソールから文字列を行単位で入力するには、ReadConsole 関数 (マルチバイト文字モードなら ReadFile 関数も使用可能) を使用します。
次のサンプルは、文字列を入力し、それをメッセージボックスに表示します。
##ヘッダーファイル
// stdafx.h : 標準のシステム インクルード ファイルのインクルード ファイル、または
// 参照回数が多く、かつあまり変更されない、プロジェクト専用のインクルード ファイル
// を記述します。
//
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
// TODO: プログラムに必要な追加ヘッダーをここで参照してください
#include <Windows.h>
##CPP ファイル
// ConsoleApi03.cpp : アプリケーションのエントリ ポイントを定義します。
//
#include "stdafx.h"
#define BUFFLEN 1024
/*
コンソール入力
==============
*/
int main()
{
WCHAR buffer[BUFFLEN];
DWORD len;
LPCWSTR str = L"ReadConsole ..\n";
// 標準入出力ハンドルを得る。
HANDLE ho = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE hi = GetStdHandle(STD_INPUT_HANDLE);
if (ho == INVALID_HANDLE_VALUE || hi == INVALID_HANDLE_VALUE)
{
wprintf_s(L"ErrorCode = %d\n", GetLastError());
return -1;
}
// str を表示する。
WriteConsole(ho, str, wcslen(str), &len, NULL);
// キーボード入力。
ReadConsole(hi, buffer, BUFFLEN, &len, NULL);
if (len < 3)
{
// Ctrl+C や Enter のみが押されたとき
return -1;
}
// 行末に CRLF が入るので削除する。(ついでに行末に'\0'を追加)
buffer[len - 1] = '\0';
buffer[len - 2] = '\0';
MessageBox(NULL, buffer, L"Result", MB_OK);
return 0;
}