C++を用いたWindowsプログラミングの基礎(第2回)

## はじめに
前回の続きでウィンドウの生成について、個人的によく使われる(であろうと思っている)ウィンドウスタイルを通して解説していきます。

## 枠なしウィンドウ
前回のウィンドウ生成にて`CreateWindowA`の第3引数に**WS_OVERLAPPEDWINDOW**を指定しました。
この第3引数はウィンドウのスタイルを定義するためものです。
**WS_OVERLAPPEDWINDOW**は最も標準的なスタイルで、最小化/最大化/閉じるボタンが有効、かつ、ウィンドウ枠で自在にサイズを変更できます。
しかし、自在にサイズ設定をされては、レイアウトの都合上ゲーム用のウィンドウとしては適していません。
また、ウィンドウの枠線も不要の場合が多々あります。
そこで、前回のソースコードを修正し、サイズ変更不可で枠なしのウィンドウを生成します。
ついでに画面の最前面に表示されるような設定も行います。

[枠なしウィンドウのサンプル](https://github.com/Puni2Samurai/VcppExample/blob/main/example001_002a.cpp)

```
    // ウィンドウ生成
    hwnd = CreateWindowExA(
        WS_EX_TOPMOST,
        szWinName,
        szWinTitle,
        WS_VISIBLE | WS_POPUP,
        CW_USEDEFAULT, CW_USEDEFAULT,
        640, 480,
        HWND_DESKTOP,
        NULL,
        hThisInst,
        NULL
    );
```

ウィンドウ生成時に呼び出す関数を`CreateWindowExA`に変更しています。
これは、拡張スタイルのウィンドウを生成するためです。
拡張スタイルにあたるものが**WS_EX_TOPMOST**の指定です。
これによりウィンドウの位置が最前面になります。
`WS_VISIBLE | WS_POPUP,`では、枠なし/タイトルバーなしウィンドウを表示させます。

```
    SetFocus(hwnd);
```

今回追加したコードです。
キーボード入力を生成ウィンドウに向けます。

さて、これにより枠なしウィンドウを表示できるようになりましたが、閉じるボタンがありません。
このままでは不親切なので、別途アプリの終了を行う処理を用意しましょう。

```
        // キーボード押下
        case WM_KEYDOWN:
            switch(wParam)
            {
                case VK_ESCAPE:
                    PostQuitMessage(0);
                    break;
            }
            break;
```

ウィンドウ関数に追加したコードです。
`case WM_KEYDOWN:`でキー押下状態のイベントを処理します。
**wParam**には押下されたキーの値がセットされています。
この処理ではESCキーが押下された場合にアプリを終了させます。


## メニュー付きウィンドウ
**WS_OVERLAPPEDWINDOW**のスタイルは標準的であると述べましたが、多くのアプリにあるものが存在しません。
タイトルバーの下にあるメニューです。

[メニュー付きウィンドウのサンプル一式](https://github.com/Puni2Samurai/VcppExample/tree/main/example001_002b)

メニュー作成には、2つのファイルを事前に用意します。
- メニュー項目を一意に識別する値が定義されたヘッダファイル(*.h)
- メニュー項目が定義されたリソースファイル(*.rc)

***.rc**ファイルは事前にリソースコンパイルする必要があります。
VSCodeのtasks.jsonのtasks配列に下記の設定を追加してください
(ファイルパスはご自身の環境に合わせて読み替えてください)。

```
{
    "type": "shell",
    "label": "C/C++: windres.exe resource compiler",
    "command": "C:\\gcc\\mingw64\\bin\\windres.exe",
    "args": [
        "-i",
        "${file}",
        "-o",
        "${fileDirname}\\${fileBasenameNoExtension}.o"
    ],
    "options": {
        "cwd": "C:\\gcc\\mingw64\\bin"
    },
    "group": "build",
    "detail": "compiler: C:\\gcc\\mingw64\\bin\\windres.exe"
}
```
また、既存の`g++.exe`の**args**にも、リソースコンパイルしたファイルをリンクするよう修正してください。
```
    "-mwindows",
    "-fdiagnostics-color=always",
    "-g",
    "${file}",
    "${fileDirname}\\${fileBasenameNoExtension}.o",
    "-o",
    "${fileDirname}\\${fileBasenameNoExtension}.exe"
```

リソースファイルでは、サブメニューを持つ/持たない2種類のメニューを定義しました。
どちらもアプリを終了するだけの簡単なメニューです。
重要な箇所は`MENU_EXAMPLE001_002 MENU MENU`と`MENUITEM "&Exit", IDM_EXIT`です。
**MENU_EXAMPLE001_002**はメニューの識別名で、ウィンドウ生成時に使用します。
**IDM_EXIT**はメニュー項目のIDで、ウィンドウ関数のパラメーターとして使用されます。
```
wcl.lpszMenuName = "MENU_EXAMPLE001_002";
```

WNDCLASSEXA構造体の`lpszMenuName`に、リソースファイルで定義したメニュー識別名を指定することで、メニューをロードします。

```
        // メニュー項目選択
        case WM_COMMAND:
            switch(LOWORD(wParam))
            {
                case IDM_EXIT:
                    MessageBoxA(hwnd, "Quit this app.", "EXIT", MB_OK);
                    PostQuitMessage(0);
                    break;
            }
            break;
```

ウィンドウ関数に追加したコードです。
`case WM_COMMAND:`でメニュー項目選択時のイベントを処理します。
**wParam**には選択されたメニュー項目のIDがセットされています(`example001_002b.h`で定義)。
**MessageBoxA**はダイアログ表示を行う関数です。ダイアログ表示後に終了処理を行います。

※なお、実際において、メニューを定義するrcファイルをテキストで編集することは稀です。
　GUIによるリソース用エディタを使用することがほとんどです。


## ダブルクリック対応ウィンドウ
ウィンドウにダブルクリック操作を検知させたい場合の処理を解説します。
これまでに生成したウィンドウはダブルクリックの操作に対応していません。

[ダブルクリック対応ウィンドウのサンプル](https://github.com/Puni2Samurai/VcppExample/blob/main/example001_002c.cpp)

```
wcl.style = CS_DBLCLKS;
```

WNDCLASSEXA構造体の`style`を設定することで、ウィンドウがダブルクリック操作イベントのメッセージを受け取るようになります。

```
    int iResp;
```
```
        // ダブルクリック(左ボタン)
        case WM_LBUTTONDBLCLK:
            iResp = MessageBoxA(hwnd, "Quit this app ?", "Confirm", MB_YESNO);
            if(iResp == IDYES)
            {
                PostQuitMessage(0);
            } 
            break;
```

ウィンドウ関数に追加したコードです。
`case WM_LBUTTONDBLCLK:`でダブルクリック時のイベントを処理します。
マウスカーソルがウィンドウ上にある状態でダブルクリックすると、修了確認のダイアログが表示されます。
「はい」を選択するとアプリの終了処理を行います。


## 次回予告
次回はいよいよ**画像の描画**について取り扱います。
Windowsアクセサリのペイントで作成可能なBMPファイルを用いて解説していきます。
ゲーム作成にはグラフィックは必須です。
生成したウィンドウ内に画像を表示させましょう。