第1章 Windowsプログラミングを学ぼう

1-2.Windowsプログラムの構造

最も簡単なWindowsプログラム例(スケルトンプログラム)を元に説明する。

《スケルトンプログラム》

//=============================================================================
//      Windowsプログラミング スケルトンプログラム
//=============================================================================

#include <windows.h>
#include <windowsx.h>

// プロトタイプ宣言
LRESULT CALLBACK WinProc(HWND, UINT, WPARAM, LPARAM);
BOOL InitApp(HINSTANCE, int);

// グローバル変数
HWND hWnd;
char szWinName[] = "Skeleton";

int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR lpszArgs, int nWinMode)
{
    MSG msg;

    /* 表示するウィンドウの定義、登録、表示 */
    if (!InitApp(hThisInst, nWinMode))
        return (FALSE);

    /* メッセージループ */
    while (GetMessage(&msg, NULL, 0, 0)) // Windowsは「WM_QUIT」メッセージを受けると偽(0)を戻す
    {
        TranslateMessage(&msg); // キーボード利用を可能にする
        DispatchMessage(&msg);  // 制御をWindowsに戻す
    }

    return msg.wParam;

}

//=============================================================================
//      ウィンドウプロシジャ関数(WindowProcedure)
//=============================================================================
LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_DESTROY: // 閉じるボタンをクリックした時
            PostQuitMessage(0); // WM_QUITメッセージを発行
            break;
        default: // 上記以外のメッセージはWindowsへ処理を任せる
            return DefWindowProc(hWnd, message, wParam, lParam);
    }

    return 0;

}

//=============================================================================
//  関数名 :InitApp
//  機能概要:表示するウィンドウの定義、登録、表示
//  戻り値 :正常終了のとき1、以上終了のとき0
//=============================================================================
BOOL InitApp(HINSTANCE hThisInst, int nWinMode)
{
    WNDCLASSEX wc;

    /* ウィンドウクラスを定義する */
    wc.hInstance = hThisInst;                   // このインスタンスへのハンドル
    wc.lpszClassName = szWinName;               // ウィンドウクラス名
    wc.lpfnWndProc = WinProc;                   // ウィンドウ関数
    wc.style = 0;                               // ウィンドウスタイル(デフォルト)
    wc.cbSize = sizeof(WNDCLASSEX);             // WNDCLASSEX構造体のサイズを設定
    wc.hIcon = LoadIcon(hThisInst, IDI_APPLICATION); // ラージアイコン
    wc.hIconSm = LoadIcon(hThisInst, IDI_WINLOGO);   // スモールアイコン
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);   // カーソルスタイル
    wc.lpszMenuName = NULL;                     // メニュー(なしに設定)
    wc.cbClsExtra = 0;                          // エキストラ(なしに設定)
    wc.cbWndExtra = 0;                          // 必要な情報(なしに設定)
    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); // ウィンドウの背景(黒に設定)

    /* ウィンドウクラスを登録する */
    if (!RegisterClassEx(&wc))
        return (FALSE);

    /* ウィンドウクラスの登録ができたので、ウィンドウを生成する */
    hWnd = CreateWindowEx(
        0,                     // 拡張ウィンドウスタイル
        szWinName,             // ウィンドウクラスの名前
        "Skeleton 背景を黒に", // ウィンドウタイトル
        WS_OVERLAPPEDWINDOW,   // ウィンドウスタイル
        0,                     // ウィンドウの左角X座標
        0,                     // ウィンドウの左角Y座標
        640,                   // ウィンドウの幅
        480,                   // ウィンドウの高さ
        NULL,                  // 親ウィンドウ(なし)
        NULL,                  // メニュー(なし)
        hThisInst,             // このプログラムのインスタンスのハンドル
        NULL                   // 追加引数(なし)
    );

    ShowWindow(hWnd, nWinMode); // ウィンドウを表示する
    UpdateWindow(hWnd);

    return (TRUE);

}

(a) 構造

次の3つの部分から成り立っている。

(1) WinMain関数
・表示ウィンドウの属性設定とWindowsへの登録
・いろいろな初期設定
・メッセージループ
(2) Windows関数
Windowsメッセージ処理を行う。
(3) その他のユーザ関数
WinMain関数、Windows関数あるいはほかのユーザ関数から呼び出される(自作)関数郡。

(b) プログラムを追いかけてみよう

(1) #include <windows.h>
・DOS、UNIXではstdio.hをインクルードする。
・Windowsではwindows.hまたはwindowsEX.hをインクルードする
(2) プログラムの開始はWinMain関数
・Windowsから一番最初に呼び出される関数。
・int WINAPIはWindowsへの戻り値がint型であるという意味。
Windowsから渡される引数は4つ。必ず記述する。
(3) HWND hWnd;
・Windowsが画面内の複数のウィンドウを区別するために使用する識別番号をウィンドウハンドルと呼ぶ。その値を格納する変数を定義。
・いろいろな関数にまたがって使用するので、グローバル変数として定義した。
(4) MSG msg;
・MSG構造体msg変数の定義。
(5) 表示するウィンドウの定義、登録、表示を行う(if (!(hWnd = InitApp(〜略〜)) return (hWnd);)
・InitApp関数を実行する
・InitApp関数の戻り値がゼロ以外の値でなかったら(戻り値が0だったら)、エラー番号を戻り値として関数を終了する(Windowsに戻る)

*** ここまでは、プログラム起動直後に1回だけ実行される ***

(6) メッセージループ
・将来、ゲームを作成するときにはゲームのメインループとして利用する。
・このプログラムでは
while (GetMessage(&msg))
{
  ・
  ・
}
・Windowsからメッセージが1つ来ると、ループが1回実行される。
・どのようなとき、このループが終了するか?
  1. GetMessage関数の戻り値が0(ゼロ)のとき
  2. Windowsはループ終了メッセージ(WM_QUIT)を受け取るとGetMessage関数の戻り値として0(ゼロ)を返してくるので、ループが終了する

Q:ウィンドウプロシジャ関数はいつ動いたか?

(c) ウィンドウプロシジャ関数について

Q:ウィンドウ関数はいつ動く?
A:Windowsからメッセージが届いたとき
Q:どんなメッセージがある?
A:用語集「ウィンドウメッセージの種類」を参照

(d) ウィンドウクラスの各メンバについて

ウィンドウを生成するには、WNDCLASSEX構造体変数を宣言し、各メンバに必要な値をセットしなければならない。スケルトン・プログラムでは、InitApp関数で行っている。
ここでは、WNDCLASSEX構造体の各メンバを紹介する。

hInstance ウィンドウのインスタンス
ウィンドウのインスタンス。WinMainの引数として受け取ったhInstanceをそのままセットする。
lpszClassName ウィンドウの名前
定義したウィンドウの名前。Windowsはこの名前によってウィンドウを特定する。ウィンドウのタイトルバーに表示される名前とは別(タイトルはCreateWindow関数で指定)。
lpfnWndProc WndProc関数のアドレスを指定
FAR PASCAL型の関数へのポインタ。Windowsからのメッセージの受け取り先であるWndProc関数のアドレスをセットする。
Windowsからのメッセージはここでセットされた関数を呼び出す(正確にはWindowsがメッセージを引数に与えて、ここでセットされた関数を呼び出す)。関数名はWndProcである必要はないが、慣習としてこの名前が用いられている。
style ウィンドウのスタイルを指定
作成するウィンドウのスタイルを指定する。スタイルを示す定数はwindows.hの中でCS_XXXXXXという形式で定義されている。複数のスタイルを組み合わせて指定する場合は、識別子を|で連結する。
cbSize WNDCLASSEX構造体のサイズ
WNDCLASSEX構造体のサイズを指定する。
hIcon, hIconSm アイコン
ウィンドウが最小化されたときやエクスプローラ内で表示されるアイコンの画像を指定する。スケルトン・プログラムではWindows標準のアイコン画像をそれぞれ指定している。
hCursor マウス・カーソルの形状
マウス・カーソルが自分のウィンドウに入ってきたときの、マウス・カーソルの形を指定する。スケルトン・プログラムではWindows標準のカーソル画像をそれぞれ指定している。
lpszMenuName メニューの付加
ウィンドウにメニューを追加する場合に使用。メニューは通常のウィンドウにある「ファイル(F)」「ヘルプ(H)」などの項目が並んだもので、これを追加するには、メニューの内容を記述したリソースが必要。スケルトン・プログラムでは「メニューなし」に指定している。
cbClsExtra
WNDCLASSEX構造体の最後尾に割り当てるメモリをバイト単位で指定。
cbWndExtra
生成されたウィンドウ(インスタンス)の最後尾に割り当てるメモリをバイト単位で指定。
hbrBackGround
ウィンドウの背景色を指定。指定にはGetStockObject関数を使う。

(e) Windows独自のデータ型

ウィンドウを生成するには、Windows独自のデータ型や構造体を利用しなければならない。

これらのデータ型、構造体は、wtypes.hwinuser.hwindef.hなどのヘッダ・ファイルで定義されている。


[ TOP ]