「画像ローダ その 1」 VC++.NET メモ #01

1. はじめに

この文章は Microsoft 社の C/C++ 用の統合開発環境 Visual C++ .NET 2002 (以下 VC++.NET と書く) を使用した際のメモ書きです。

この章 (#01) では,リソースとして埋め込んだビットマップ画像を表示するだけの簡単なアプリケーションを作ります。次のようなアプリケーションとします。

  1. 起動と同時に画像を読み込む
  2. 終了するまで画像を表示
  3. 「閉じる」ボタンで終了

行うことは次の 2 つ。

  • リソースとしてビットマップ画像を登録する。
  • コードを 10 数行追加する。

MFC は使用せず Windows API のみで作成します。

2. プロジェクトの作成

  1. Visual Studio .NET の「スタートページ」で「新しいプロジェクト」ボタンを押す。
  2. 「新しいプロジェクト」ウィンドウが開く。
  3. 「Visual C++ プロジェクト」の中から「Win32 プロジェクト」を選び,プロジェクト名に適当な名前 (ここでは「Test」とする) を付けて,「OK」ボタンを押す。
    図 : 新しいプロジェクト
  4. 「Win32 アプリケーション ウィザード」ウィンドウが開く。
  5. 「アプリケーションの設定」でアプリケーションの種類で「Windows アプリケーション」を選択,追加のオプションの「空のプロジェクト」にチェックが入っていないことを確認し「完了」ボタンを押す。

上記のようにプロジェクトを作成する。これにより「Windows アプリケーション」AppWizard がプログラムの骨格部分を作った状態からプログラム開発を始めることができる。

3. 画像ファイルの指定

  1. 右側に表示されている(であろう)ウィンドウをタブで「リソースビュー」へ切り替える。
  2. ツリーの一番上にある「Test」にマウスカーソルを合わせ右クリックし,ポップアップウィンドウで「追加」の中の「リソースの追加」を選択する。
    図 : リソースビュー
  3. 「リソースの追加」ウィンドウが開く。
  4. リソースの種類で「Bitmap」を選択し,「インポート」ボタンを押す。
  5. 「インポート」ウィンドウが開く。
  6. 表示したい BMP 画像ファイルを選択し,「開く」ボタンを押す。
  7. 「リソースビュー」のツリーに「Bitmap」が作成され,その中に「IDB_BITMAP1」が作成される。

上記のようにビットマップ画像をリソースとして登録する。「IDB_BITMAP1」が埋め込んだビットマップ画像のリソース ID である。


4. ソースコードの記述

  1. 「リソースビュー」下部のタブで「ソリューションエクスプローラ」を選択する。
  2. 「ソリューションエクスプローラ」のツリーで「Test.cpp」をダブルクリックする。
  3. 「Test.cpp」の内容が表示されるので画像を表示するためのプログラムを記述する。

下記のように WndProc() に書き加える。

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;
    HDC hBufdc;
    static HBITMAP hBitmap;
    BITMAP bmp;

    switch (message) 
    {
    case WM_COMMAND:
        wmId    = LOWORD(wParam); 
        wmEvent = HIWORD(wParam); 
        // 選択されたメニューの解析 :
        switch (wmId)
        {
        case IDM_ABOUT:
            DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
            break;
        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        // TODO: 描画コードをここに追加してください...
        hBufdc = CreateCompatibleDC(hdc);
        SelectObject(hBufdc, hBitmap);
        GetObject(hBitmap, sizeof(BITMAP), &bmp);
        BitBlt(hdc, 0, 0,
               (int)bmp.bmWidth, (int)bmp.bmHeight,
               hBufdc, 0, 0, SRCCOPY);
        DeleteDC(hBufdc);
        EndPaint(hWnd, &ps);
        break;
    case WM_CREATE:
        hBitmap = (HBITMAP)LoadImage(hInst,
                                     MAKEINTRESOURCE(IDB_BITMAP1),
                                     IMAGE_BITMAP,
                                     0, 0,
                                     LR_DEFAULTCOLOR);
        break;
    case WM_DESTROY:
        DeleteObject(hBitmap);
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

5. コードの説明

画像の読み込み

アプリケーションが起動した時に画像を読み込むため,まず WM_CREATE イベントハンドラを追加し,画像を読み込む処理を記述する。

    case WM_CREATE:
        hBitmap = (HBITMAP)LoadImage(hInst,
                                     MAKEINTRESOURCE(IDB_BITMAP1),
                                     IMAGE_BITMAP,
                                     0, 0,
                                     LR_DEFAULTCOLOR);
        break;

画像を読み込むのには LoadImage() を使う。[参考 : MSDN Library Japan]

LoadImage() の引数は以下の通り

hInst

画像リソースが入ったモジュールのインスタンスハンドル。今回,画像リソースはこのプログラムに埋め込まれるので,このプログラムが起動した際に与えられるインスタンスハンドルを指定する。

hInst はインスタンスハンドルを格納したグローバル変数。

MAKEINTRESOURCE(IDB_BITMAP1)

画像リソース識別子。TEXT("IDB_BITMAP1") ではなく VC++ の独特の書き方を使う。

これはリソースビューで画像を追加した時点で自動的に resource.h へ #define IDB_BITMAP1 129 と記述されているからである。

MAKEINTRESOURCE() はリソースシンボル値 (WORD 型での識別子) を通常のリソース識別子に変換する関数マクロ。

(LPCTSTR)IDB_BITMAP1 と書くこともできるが,MAKEINTRESOURCE() を使った方が安全だろう。

IMAGE_BITMAP
リソースの種類。ここではビットマップ画像 (IMAGE_BITMAP) を指定。
0
画像の幅。リソースの実際のサイズを使用するため 0 を指定。
0
画像の高さ。リソースの実際のサイズを使用するため 0 を指定。
LR_DEFAULTCOLOR
各種オプション。何もしない LR_DEFAULTCOLOR を指定。

LoadImage() の返値がロードされた画像のハンドルとなる。

画像をアプリケーションが終了するまで表示するために,ハンドルを格納する変数には static を付け,アプリケーションが終了するまで保持させる。

LoadImage() の代わりに LoadBitmap() を使って次のように書くことも出来ます。ただし,この方法は古い方法であるとされています。[参考 : MSDN Library Japan | MSDN ライブラリ アーカイブ サイト]

    case WM_CREATE:
        hBitmap = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP1));
        break;

画像の破棄

描画について書く前に,画像を破棄する手順を説明する。

    case WM_DESTROY:
        DeleteObject(hBitmap);
        PostQuitMessage(0);
        break;

LoadImage() でロードした画像は DeleteObject() で破棄します。[参考 : MSDN ライブラリ アーカイブ サイト]

hBitmap

引数には破棄する対象の画像を示すハンドルを指定します。

今回のアプリケーションに関しては,画像の破棄はアプリケーションの終了時なので,DeleteObject() を書かなくても終了時に Windows が勝手に破棄してくれますが,書いておくべきでしょう。

6. ビルド

  1. キーボードの「F5」を押す。(又は,メニューバーの「デバッグ」の中の「開始」を選択する。)
  2. 「これらのプロジェクトは古い形式で構成されています~~~」と書かれたウィンドウが表示される。
  3. 「はい」ボタンを押す。
  4. プログラムに間違いがなければ,ビルドが終了し,アプリケーションが起動する。
  5. アプリケーションのウィンドウに画像が表示されているはず……