LoginSignup
7
4

More than 5 years have passed since last update.

Win32 コンソール API

Last updated at Posted at 2018-02-21

はじめに

コマンドプロンプト画面(コンソール)は、デフォルトでは黒に白の文字が表示されます。しかし、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 のように色を変えた文字列を表示した後、デフォルトに戻して終了するだけのものです。

ConsoleAPI1.png

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 関数も使用可能) を使用します。

次のサンプルは、文字列を入力し、それをメッセージボックスに表示します。

ConsoleAPI2.png
Fig.2 コンソールから行を入力する

ヘッダーファイル

// 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;
}

-

7
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4