2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

C++:ウィンドウ作成不要!コンソール画面に直接 GDI+ で図形を描画する最短の方法

2
Last updated at Posted at 2026-07-01

ほとんどニーズがないと思うが,コンソール AP で GDI+ を使用したサンプル.
T_GDIx_2026_07_01.png

#include <windows.h>
#include <gdiplus.h>
#include <iostream>

#pragma comment(lib, "gdiplus.lib")

int main()
{
    // 1. GDI+ の初期化
    ULONG_PTR gdiplusToken;
    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    {
        // 2. コンソールウィンドウのデバイスコンテキスト(HDC)を取得
        HWND hWnd = ::GetConsoleWindow();
        if (hWnd != NULL)
        {
            HDC hdc = ::GetDC(hWnd);
            if (hdc != NULL)
            {
                // HDC を基に Graphics オブジェクトを作成(画面への直接描画)
                Gdiplus::Graphics graphics(hdc);

                // 背景を白でクリア(コンソール上に 150x100 の白い四角形を描画)
                Gdiplus::SolidBrush brush(Gdiplus::Color(255, 255, 255, 255));
                graphics.FillRectangle(&brush, 200, 200, 150, 100);

                // 画面への描画を即座に反映
                graphics.Flush(Gdiplus::FlushIntentionSync);

                std::cout << "GDI+ の画面描画を実行しました" << std::endl;

                // 使い終わった HDC を解放
                ::ReleaseDC(hWnd, hdc);
            }
        }
    } // 各種 GDI+ オブジェクト(SolidBrush等)のデストラクタを確実に呼ぶためスコープで囲む

    // 3. GDI+ の後処理
    Gdiplus::GdiplusShutdown(gdiplusToken);

    {
        std::cout << "Press Enter to exit." << std::endl;
        std::cin.get();
    }

    return 0;
}

簡単にポイント解説

  • ::GetConsoleWindow() の利用
    通常のウィンドウアプリケーションのようにウィンドウクラスの登録やメッセージループ(WndProc)を実装することなく、現在実行中のコンソール自体のウインドウハンドル(HWND)を一行で取得して描画対象にしています。
  • 中括弧 { } によるスコープ(寿命管理)
    GDI+ の大原則として、Gdiplus::GdiplusShutdown を呼び出す前に、すべての GDI+ オブジェクト(GraphicsSolidBrush など)が破棄されている必要があります。そのため、初期化と後処理の間に明示的なスコープを設けて、その中でオブジェクトの寿命が確実に尽きるようにしています。
  • graphics.Flush の実行
    メモリ上のバッファリングではなく、画面のデバイスコンテキストに対して即座にレンダリングを確定させるために FlushIntentionSync を指定して同期的に反映させています。

あわせて読みたい(関連記事)

今回の実装に至る背景や、コンソールアプリケーションにおけるデバイスコンテキスト(DC)のさらなる活用法、ウィンドウハンドル(HWND)取得のより詳しい仕組みについては、以下の検証記事もあわせてご参照ください。


2026-07-02 追記: Windows 11 環境で意図した表示にならない場合

Windows 11(特に近年のアップデート適用環境)では、OS の「既定のターミナルアプリケーション」が従来のコンソールホスト(conhost.exe)ではなく、モダンな Windows Terminal に変更されています。

Windows Terminal は内部のレンダリングに GDI ではなく DirectX(GPUアクセラレーション)を使用しているため、::GetConsoleWindow() で取得したハンドル(HDC)に対して GDI/GDI+ で直接ピクセルを書き込もうとしても、描画が無視されるか即座に上書きされて消えてしまう現象が発生します。

もし Windows 11 環境で正しく四角形が表示されない場合は、OS のターミナル設定を「Windows コンソール ホスト」に戻すか、以下のような 正攻法の Win32 ウィンドウ(メッセージループを持つ最小構成) での描画をお試しください。

Win32 ウィンドウでの GDI+ 最小実装サンプルを表示する
#include <windows.h>
#include <gdiplus.h>
#pragma comment(lib, "gdiplus.lib")

using namespace Gdiplus;

ULONG_PTR g_gdiplusToken;

// -------------------------------------------------------------
// ウィンドウプロシージャ
// -------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = ::BeginPaint(hWnd, &ps);

            Graphics graphics(hdc);

            SolidBrush brush(Color(255, 255, 0, 0));   // 赤
            graphics.FillRectangle(&brush, 50, 50, 200, 120);

            ::EndPaint(hWnd, &ps);
        }
        return 0;

    case WM_DESTROY:
        ::PostQuitMessage(0);
        return 0;
    }

    return ::DefWindowProc(hWnd, msg, wParam, lParam);
}

// -------------------------------------------------------------
// WinMain
// -------------------------------------------------------------
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow)
{
    // --- GDI+ 初期化 ---
    GdiplusStartupInput gdiplusStartupInput;
    gdiplusStartupInput.GdiplusVersion = 1;
    ::GdiplusStartup(&g_gdiplusToken, &gdiplusStartupInput, NULL);

    // --- ウィンドウクラス登録 ---
    WNDCLASS wc;
    ::ZeroMemory(&wc, sizeof(wc));
    wc.lpfnWndProc   = ::WndProc;
    wc.hInstance     = hInstance;
    wc.lpszClassName = TEXT("GDIPlusSampleWindow");
    wc.hCursor       = ::LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

    ::RegisterClass(&wc);

    // --- ウィンドウ作成 ---
    HWND hWnd = ::CreateWindow(
        wc.lpszClassName,
        TEXT("GDI+ Win32 Sample"),
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        400, 300,
        NULL,
        NULL,
        hInstance,
        NULL
    );

    ::ShowWindow(hWnd, nCmdShow);
    ::UpdateWindow(hWnd);

    // --- メッセージループ ---
    MSG msg;
    while (::GetMessage(&msg, NULL, 0, 0))
    {
        ::TranslateMessage(&msg);
        ::DispatchMessage(&msg);
    }

    // --- GDI+ 終了 ---
    ::GdiplusShutdown(g_gdiplusToken);

    return (int)msg.wParam;
}

※ 本記事の構成および文章の作成には、生成 AI を利用しています。

2
1
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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?