ホーム
Windows API Primer
Windows 3.1 / Borland Turbo C++
Win16 API を始めるための Windows 3.1 と Borland Turbo C++ のインストールと設定方法は、Environment Windows 3.1 をご覧ください。
ウィンドウ
Windows APIでウィンドウを表示するには、独自のウィンドウクラスを作成して、そのウィンドウクラスをシステム(Windows OS)に登録します。そして、その登録されたウィンドウクラスからウィンドウを作成して表示します。
ウィンドウクラスを作成する。
作成したウィンドウクラスをシステム(Windows OS)に登録する。
システム(Windows OS)に登録されたウィンドウクラスからウィンドウを作成して表示する。
イベントループ
GUI アプリケーションは、終了メッセージを受け取るまで、イベントループなどと呼ばれる無限ループで起動し続けます。
このような無限ループをプログラミング用語ではイベントループやメインループと言いますが、Windows APIでは、メッセージループとも言います。
window.c
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int PASCAL WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASS wc;
HWND hwnd;
MSG msg;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = "WINDOW";
RegisterClass(&wc);
hwnd = CreateWindow("WINDOW",
"Window",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, 300, 200,
NULL, NULL, hInstance, NULL);
while (GetMessage(&msg, NULL, 0, 0))
{
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
実行結果
コード説明
windows.h
Windows API の関数・型・定数と C の関数・型・定数を定義したヘッダーです。
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
ウィンドウのためのウィンドウプロシージャのプロトタイプ(前方宣言)です。
ウィンドウプロシージャとは、ウィンドウの発するメッセージ(イベント)を処理する関数です。
int PASCAL WinMain
Winsows API では、アプリケーションは WinMain 関数から始まる決まりになっています。戻り値は int です。WinMain 関数には、引数の扱い方を決めた「呼び出し規約」というものが必要です。WinMain 関数の呼び出し規約は一般的に WINAPI ですが、Borland Turbo C++ では、PASCAL になります。WinMain 関数の引数は次のとおりです。
HINSTANCE hInstance
そのアプリケーション自体を表す引数です。
HINSTACE hPrevInstance
16bit アプリケーションを表す引数です。
LPSTR lpCmdLine
コマンドラインを表す引数です。
int nCmdShow
アプリケーションの表示状態を表す引数です。
WinMain 関数の冒頭で設定されている各変数の型の意味は次のようになります。
WNDCLASS
ウィンドウクラスの各設定値を格納する構造体です。
HWND
ウィンドウのハンドルが入る型です。プログラミングおいてハンドル(hundle)とは、データやコードの場所が変わる場合に、必ずその場所を追跡するポインターのポインターですが、Windows API ではデータやコードを識別するためのユニーク(一意)な整数値です。Hやhで始まる型やメンバーはハンドルです。
MSG
アプリケーションやシステムは色々なイベントを発します。そのイベントは、メッセージとして、この MSG 構造体に格納されます。イベントをきっかけに、アプリケーションの処理や振る舞いが決まる仕組みのことをイベント駆動(イベントドリブン、event driven)と言います。
ウィンドウクラス構造体のメンバーの意味は次のようになります。
style
ここには通常、ウィンドウが水平方向に変更された時に再描画することを意味するCS_HREDRAW定数と、ウィンドウが垂直方向に変更された場合に再描画することを意味するCS_VREDRAW定数を | でつなげて設定します。CS はクラススタイルの略だと思えば覚えやすいでしょう。
lpfnWndProc
Windows APIでは、ウィンドウがイベント(メッセージ)を発した場合に、それを処理する関数を決めておかなければなりません。ここでは自作関数の WndProc を設定しています。Windows API で使われるメンバー名などの識別子には一定の接頭辞(プリフィックス、prefix)がつきます。l はロング、p はポインター、fn は関数(ファンクション、function)を表しています。
cbClsExtra と cbWndExtra
ここには、ウィンドウに追加で格納するデータ領域を設定しますが、通常は使わないので 0 を設定します。
hInstance
このウィンドウを使うアプリケーションを指定します。hInstance は、メイン関数の引数で指定された、このアプリケーションを表すハンドルです。
hIcon
アイコンを指定します。 NULL を指定した場合は標準のアイコンが設定されます。
hCursor
カーソルの形を指定します。LoadCursor(NULL, IDC_ARROW) で矢印カーソルを指定できます。
hbrBackground
ウィンドウの背景色を設定します。HBRUSHは、塗り潰しの情報が入ったハンドルです。ここでは WHITE_BRUSH(白色)を取得しています。
lpszMenuName
ウィンドウで使われるメニューを識別する文字列が入ります。メニューを使わない場合は NULL を指定します。sz は、終了文字 \0 で終わる文字列を意味しています。
lpszClassName
このウィンドウクラスの名前を設定します。後ほど、このウィンドウクラスからウィンドウを作成する場合に、この名前を使います。
RegisterClass関数でウィンドウクラスをシステム (Windows OS) に登録します。引数には登録したいウィンドウクラスのポインターを指定します。
CreateWindow関数でウィンドウを作成します。引数は次のとおりです。
第1引数に、どのウィンドウクラスからウィンドウを作るかを、そのウィンドウクラスの名前で指定します。
第2引数に、そのウィンドウのタイトルバーに表示する文字列を指定します。
第3引数に、作成するウィンドウの種類や状態を定数で指定します。WS_OVERLAPPEDWINDOWは他のウィンドウと重なり合うことを許可します。WS_VISIBLEは、ウィンドウを可視状態にします。通常作成されたウィンドウのデフォルトは不可視になっています。
WS はウィンドウスタイルを略していると思えば覚えやすいでしょう。
第4引数に、ウィンドウが表示される位置を、デスクトップのX座標で指定します。CW_USEDEFAULTを指定するとシステムが適当な位置を選んでくれます。
第5引数に、ウィンドウが表示される位置を、デスクトップのY座標で指定します。CW_USEDEFAULTを指定するとシステムが適当な位置を選んでくれます。
第6引数に、ウィンドウの横幅を指定します。ここでもCW_USEDEFAULTを使うことができます。
第7引数に、ウィンドウの縦幅を指定します。ここでもCW_USEDEFAULTを使うことができます。
第8引数に、親ウィンドウを指定します。親ウィンドウのないメインウィンドウを作成したい場合は、NULL を指定します。
第9引数に、メニューを指定します。メニューを使わない場合は、NULL を指定します。
第10引数に、そのウィンドウを使用するアプリケーションのハンドルを指定します。
第11引数は、ウィンドウ作成時に発生するイベントにデータを渡す手段として使用するそうですが、実際の使い方がわかりません。通常は、NULL で良いみたいです。
while 文でメッセージループを始めます。
GetMessage関数は、ウィンドウが発するイベント(メッセージ)を取得すします。引数は次のとおりです。
第1引数に、用意しておいた MSG 構造体のポインタを指定します。ここに取得したメッセージが格納されます。
第2引数に、メッセージを取得したいウィンドウを指定します。NULLを指定すると、そのアプリケーションのすべてのウィンドウからメッセージを取得します。
第3引数に、取得するメッセージの最小値を指定します。最小値を限定したくない場合は 0 を指定します。
第4引数に、取得するメッセージの最大値を指定します。最大値を限定したくない場合は 0 を指定します。
DispatchMessage 関数でメッセージをとりにいきます。
この位置によく TranslateMessage という関数を見かけます。TranslateMessage はアプリケーションで文字入力を扱う場合に必要です。文字入力を受け付けない場合は不要です。
return msg.wParam;
WinMain 関数は最後に整数値を返してアプリケーションを終了します。msg の wParam には終了コードが入っています。終了コードは通常 0 です。つまり return で 0 を返して、アプリケーションを終了しています。
LRESULT CALLBACK WndProc
ウィンドウプロシージャは LRESULT 型の整数値を戻り値とします。CALLBACK はウィンドウプロシージャの呼び出し規約です。ウィンドウプロシージャは、メッセージを処理する関数です。引数は次のとおりです。
第1引数に、メッセージを送ってくるウィンドウのハンドルを指定します。
第2引数に、MSG構造体のmessageメンバーを指定します。messageメンバーはメッセージの種類を表す正数値です。
第3引数に、MSG構造体のwParamメンバーを指定します。wParamメンバーは、メッセージに付随する追加のデータが格納されている16bit整数値です。
第4引数に、MSG構造体のlParamメンバーを指定します。lParamメンバーは、メッセージに付随する追加のデータが格納されている32bit整数値です。
*ここで少し疑問。Win16の場合もそれぞれ16bitと32bitなんだろうか?
WndProc 関数の中では、msg の整数値を利用して switch 文でメッセージを選別します。
case WM_DESTROY:
WM_DESTROY は、ウィンドウが破棄された時に発生するメッセージです。WM はウィンドウメッセージの略だと思えば覚えやすいでしょう。
PostQuitMessage は、アプリケーションを終了させるメッセージです。引数の 0 は、終了時に返されるコードです。
return DefWindowProc(hwnd, msg, wParam, lParam);
switch 文の中で記述しなかったメッセージは、Windows API に用意されている DefWindowPorc 関数で処理します。DefWindowProc 関数はウィンドウで発生する色々なメッセージを受け取りますが、実際には、それに対して何もしない設計になっています。しかし記述しておかなければエラーになります。
Win16 API プログラミングでは、ソースコードの最後に空行を1行入れておかないと(つまり最後に改行を入れておかないと)コンパイル時に警告が出ます。
Posted: Jul. 17, 2020
Update: Jul. 18, 2020