WindowsAPIでメッセージボックスを表示する

# Windows API

C言語についてズブの素人がWindows APIを説明してみる試み。
間違いは沢山あると思いますので、参考にするかしないかはあなた次第かも。

:::note info
#### そもそもこれなに？
Windows APIはC言語などから利用可能なWindowsの機能のことです。
Cの標準ライブラリではできないGUI周りのコードを書くことができます。
:::

#### WindowsAPIの種類
Windows APIには様々な種類があります。

| バージョン | 説明 |
|:-:|:-:|
|win16   |初期のWindowsからWindows 9x系まで利用される。   |
|win32   |Windows NT系で利用された。   |
|win64   |Windows XPから利用される   |

# メッセージボックスの表示
次のようなメッセージボックスを表示する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3737296/79739eef-3daf-75ef-9cd9-81a51004939c.png)

```c: HelloWorld.c
#include <windows.h>
#include <tchar.h>

int WINAPI WinMain(
	HINSTANCE hInstance, HINSTANCE hPrevInstance,
	LPSTR lpCmdLine, int nCmdShow)
{
	MessageBox(NULL, _T("Hello world"), _T("Hello Qiita"), MB_OK);
	
	return 0;
}
```

むずかしいところが多いので一つ一つ解説していきます。

## #include \<windows.h>
windows.hはWindows APIを利用するためのヘッダファイルです。
また、これはさらにいくつかの小さなヘッダファイルをインクルードするファイル（マスターインクルードファイル）です。
例えば以下のようなヘッダファイルをインクルードします。
* <b>windef.h</b>：固有の型定義(INT, LONG, FLOAT, CHAR, PSTR, etc)
* <b>winbase.h</b>：最低限の関数プロトタイプ、構造体、define
* <b>wingdi.h</b>：グラフィックス関連
* etc...

:::note info
<b>ヘッダファイルとは</b>
プログラムにおいて使用される定数、関数、変数その他さまざまの宣言する必要があるデータ・命令の宣言を記述したファイル。
ソースファイルの一部となってコンパイラに読み込まれる形となる。
:::

## int WINAPI WinMain(...

ここはちょっとむずかった

### WINAPIってなに？
先ほど説明したwindows.hの小ファイルであるwindef.hでは次のように説明されています。

```:windef.h
#define WINAPI __stdcall
```
次のように定義されていました。__stdcallというのはWin32 API関数を呼び出すときの<b>規約</b>です。この規則とは
* 関数が呼び出されたときに引数がどのようにメモリのスタックという位置に配置されるか
* 関数の戻り値がどのように扱われるか

を定義するルールのことです。
そしてほとんどのWindows関数はWin 32 API関数を呼び出す規約、要はWINAPI(__stdcall)で定義されています。

注意すべき点として、WINAPIは関数がとる引数の<b>型や引数の数を定義しているわけではない</b>ということです。

### WinMain関数ってなに？
重要なことですが、<b>Windowsプログラムにmain関数はない</b>です。
プログラムの開始点はWinMainとなります。このWinMainはWindowsアプリケーション専用のものであり、GUIアプリケーションに合わせた４つの引数をとります。

<b>第一引数は<ruby>HINSTANCE<rt>インスタンスハンドル</ruby>と呼ばれる型です。</b>
インスタンスハンドルとは、プログラムの識別をするためのハンドルです。
また、これはアプリケーションのリソース管理やウィンドウ作成など、アプリケーションの初期化、管理につかわれます。

:::note info
ハンドル
OSやアプリケーションが内部でリソースを管理するために使用する識別子です。この識別子はポインタや番号として現れます。
ファイルハンドルであるHANDLE型やウィンドウハンドルであるHWND型、リソースハンドルであるHINSTANCE型などで使われます。
:::

<b>第二引数は同様にインスタンスハンドルの型をとります</B>が、<b>32bit Windowsの場合は常に`NULL`をとります</b>。

16bit Windowsではアプリケーションが同時に複数実行されていることがありました。このhPrevInstanceは、現在のアプリケーションが起動する前に実行されていた同じアプリケーションのインスタンスのハンドルが示されており、
前回起動したインスタンスにアクセスすることができたのです。

32bit Windowsでは<b>アプリケーションは同じプロセス空間で動作するため</b>に、前回や今回などの区別はなくなり、hPrevInstanceはもはや意味を持たなくなりました。
その結果hPrevInstanceの値は常に`NULL`として渡される様になりました。

<b>第三引数はLPSTR（Windows標準の文字型）の型をとります。</b>
コマンドラインから引数をうけとります。なお、Windows APIではスペースで区切っても、一つの文字列として認識されます。

<b>第四引数は整数型をとります。</b>
ここにはウィンドウの表示状態を表す整数値が入ります。`ShowWindow`関数に渡してウィンドウの表示方法を最大化、最小化、通常表示にするかを指定したりに使います。

## MessageBox(...)
名前の通りメッセージボックスを表示に表示します。
これは４つの引数をとります。

<b>第一引数にはhInstance型をとります。</b>
ここにウィンドウハンドルを指定すると、メッセージボックスがそのウィンドウの上に表示されたり、親ウィンドウの操作をメッセージボックスの操作を終えるまで制限したりします。
ここでは主な親ウィンドウが無いのでNULLにします。

<b>第二引数にはLPCSTR型をとります。</b>
これは`Long Pointer to Constant TString`という意味で文字列を表します。
要は文字列型です。ここに入力された引数はメッセージボックスの表示内容となります。TEXT関数は文字列をTCHARの文字列リテラルに変換することができます。

<b>第三引数にはLPCSTR型をとります。</b>
ここに入力された引数はメッセージボックスのタイトルとなります。

<b>第四引数にはUINT型をとります。</b>
これはunsigned intのことで非負整数を指しています。
通常のINT型では正の数は
$2^{31} - 1$ = $2,147,483,647$まで表現可能ですが、
正だけしか使えない反面、使用できるデータは1bit分増えて表現できる正の数が
$2^{32} - 1$ = $4,294,967,295$まで表現可能です。
ただ、これは普通、定数で指定します。`MB_OK`はOKボタンを表示します。
これらの定数は`winuser.h`で定義されています。
以下の表が定義された定数です。
```
// ボタンの種類
#define MB_OK                   0x00000000  // OKボタンのみ
#define MB_OKCANCEL             0x00000001  // OKとキャンセルボタン
#define MB_ABORTRETRYIGNORE     0x00000002  // 中止、再試行、無視ボタン
#define MB_YESNOCANCEL          0x00000003  // はい、いいえ、キャンセルボタン
#define MB_YESNO                0x00000004  // はいといいえボタン
#define MB_RETRYCANCEL          0x00000005  // 再試行とキャンセルボタン

// アイコンの種類
#define MB_ICONHAND             0x00000010  // ハンドアイコン (停止)
#define MB_ICONQUESTION         0x00000020  // クエスチョンアイコン (疑問)
#define MB_ICONEXCLAMATION      0x00000030  // 警告アイコン (感嘆)
#define MB_ICONASTERISK         0x00000040  // 情報アイコン (アスタリスク)

// デフォルトボタンの種類
#define MB_DEFBUTTON1           0x00000000  // デフォルトボタン1
#define MB_DEFBUTTON2           0x00000100  // デフォルトボタン2
#define MB_DEFBUTTON3           0x00000200  // デフォルトボタン3
#define MB_DEFBUTTON4           0x00000300  // デフォルトボタン4

// モーダルの種類
#define MB_APPLMODAL            0x00000000  // アプリケーションモーダル
#define MB_SYSTEMMODAL          0x00001000  // システムモーダル
#define MB_TASKMODAL            0x00002000  // タスクモーダル

// その他
#define MB_ICONMASK             0x000000F0  // アイコン用ビットマスク
#define MB_DEFMASK              0x00000300  // デフォルトボタン用ビットマスク

```
また、ボタン、アイコン、デフォルトボタン、モーダルなどはビット単位の論理和演算子｜で組み合わせて使うことができます。

```c: HelloWorld.c
#include <windows.h>

int WINAPI WinMain(
	HINSTANCE hInstance, HINSTANCE hPrevInstance,
	LPSTR lpCmdLine, int nCmdShow)
{
	MessageBox(NULL, TEXT("Hello World"), TEXT("Hello Qiita"), MB_YESNOCANCEL | MB_ICONASTERISK);
	
	return 0;
}
```
これを実行すると

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3737296/f5642aee-83dd-e169-e8aa-03fbbae3176b.png)

と表示されました。アイコンとして情報マークが表示され、選択肢は`YESNOCANCEL`のまま出力されました。

# 終わりに
細かい知識が身についた気がする。
難しいというかさまざまな定義を暗記する作業のような気がした。
意外と面白いのでこれからもWindowsAPIを触ってみたい。