Win32/64アプリ開発 003 基礎の理解続き
次の記事:Win32/64アプリ開発 004
概要
前の記事の続きです。
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
…省略
}
LRESULT型の戻り値や関数規約のCALLBACKとかがついてますが、ウィンドウプロシージャ関数の定義です。関数規約によって特殊な関数としてコンパイラが扱ってくれます。CALLBACKは実際は__stdcallというキーワードになっています。LRESULTはLONG_PTR型を意味していて更に、LONG_PTR型はlong long型が元になっています。ようするに64ビットの整数です。そんなに長いビットが必要な返り値ではないですが、このように定義することになっています。
Windowsから送られてくるメッセージから4つの引数が受け取ることが出来るようになっています。それぞれの引数について確認しておきます。
■WndProc(HWND, UINT, WPARAM, LPARAM)
第1引数: HWND hWnd
メッセージを受け取ったウィンドウハンドル番号。どのウィンドウに対して送られてきたものなのかがわかります。
第2引数: UINT msg
送られてきたメッセージの番号。ものすごい数の種類がありますが、受け取る側は、必要なメッセージだけを見つけて処理する感じになります。
第3引数: WPARAM wParam
送られてきたメッセージによって異なるパラメータです。メッセージによっては、wParamの上位ビットだけで意味を持っていたり、下位ビットだけで意味を持っていたりもします。
第4引数: LPARAM lParam
こちらも送られてきたメッセージによって異なるパラメータです。メッセージによっては、lParamの上位ビットだけで意味を持っていたり、下位ビットだけで意味を持っていたりもします。
次に以下のswitch文について確認しましょう。
switch (msg){
case WM_CREATE:
…省略…
break;
case WM_SIZE:
…省略…
break;
case WM_DESTROY:
…省略…
break;
default:
return (DefWindowProc(hWnd, msg, wParam, lParam));
}
これで受け取ったmsg毎の処理に分けています。全てのメッセージ番号には別名がついています。windows.hを読み込んでいれば、様々な定数が定義されています。これまでにも何の気なしにキーワードを使えていたのも、windows.hのおかげです。今回メッセージを受け取って処理をするのは3つのメッセージですので、その3つについて説明します。ここで一気に説明したいところですが、おびただしい数のメッセージがありますので、用途ごとに覚えた方が頭に入りやすいと思うので、目的をもってプログラムをする上で必要になったときに覚えていったほうが良いと思います。
WM_CREATE:
ウィンドウを生成されるような処理が起こった後に呼び出されます。最初のウィンドウ表示のShowWindow関数の後すぐにWM_CREATEが呼ばれるわけではなく、その関数を実行した後にやってくる2個ほどのメッセージが処理されるとウィンドウが表示されます。このあとでWM_CREATEというメッセージが送られてきます。ここでは最初のウィンドウが出来上がった所で次のウィンドウ作成処理を行うような処理を実施しようと思っています。
WM_SIZE:
ウィンドウのサイズ変更を検出する都度送られてくるメッセージです。マウスでウィンドウの縁をつかんで、ドラッグしたときには連続して送られてきます。このとき、lParamの上位32ビットに新しいWindow高さ値、下位32ビットに新しいWindowの横幅値が格納されています。ウィンドウの大きさが変わったので中身の表示も再描画してほしいことがほとんどですから、処理の終わりにはWM_PAINTというメッセージも発行して欲しいので、UpdateWindow関数を実行をすることが多いです。その前に再描画すべき無効領域の指定も必要となります。その辺の細かいところは、後ほど。
WM_DESTROY:
通常はWM_CLOSEメッセージのような閉じるボタンを押した時に送信されるメッセージを受け取って、DestroyWindow関数が呼ばれた時にWM_DESTROYメッセージが送信されます。次にPostQuitMessage関数を実行してWM_QUITメッセージを送るという手順になります。
このようにメッセージ毎に次々と処理をリレー形式で行うこともあれば、メッセージにあわせてアプリケーション独自の処理を実行したりすることになります。
メッセージを全部網羅して処理することはできないので、捕まえるメッセージ以外が来たときはswitchのdefault処理で規定値の動きをしてもらう関数DefWindowProc(ウィンドウプロシージャ関数の引数をそのまま4つ設定する)という関数を呼び出すことができます。
それではひとつづつのメッセージ毎の処理を確認してみましょう。
HWNDg_hEdit = CreateWindowEx(
0,
L"EDIT", // エディットコントロールのクラス名
L"Hello, World!",//エディットコントロールの初期値
WS_CHILD | WS_VISIBLE | WS_BORDER | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | WS_HSCROLL | WS_VSCROLL,
0, 0, // エディットコントロールの位置(ウィンドウの左上に配置)
0, 0, // エディットコントロールのサイズ
hWnd, NULL, NULL, NULL
);
break;
2回目のCreateWindowEx関数呼び出しです。これで既に描画されたWindowの中にWindowを描画します。但し、ここではシステムの定義済みコントロールのクラス名を第2引数で設定しました。L"EDIT"としています。これでWindowの中にテキスト編集が可能なエディットコントロールが内蔵されます。後は、最初のWindow生成の要領と同じですが、最初はウィンドウの左上隅に大きさ0として、サイズ0の見えないウィンドウとして初期描画します。第3引数は、ウィンドウの場合はタイトルの文字列でしたが、エディットコントロールでは、テキストの初期値になります。第9引数も最初のウィンドウでは親のウィンドウというものが無いのでNULLとしていましたが、最初のWindowのハンドル値が入ってるWndProc関数の引数でもあるhWndを設定しています。グローバル変数にも最初のWindowのハンドル値を格納してありますので、HWNDg_hWndと指定しても同じことです。
WM_CREATEのメッセージが処理された後、InitializeWindow()関数というものを実行されます。メッセージ処理時の戻り値が-1ならInitializeWindow()関数が実行されることはありません。親ウィンドウを持つCreateWindowsEx関数を呼び出しても、再びWM_CREATEメッセージが投げられることはありません。
テキストを変更しても、ウィンドウを最大化したり、サイズ変更したり、元のサイズに戻したりするとテキストの初期値に戻ります。表示するテキスト値は、編集する都度、メモリ上で文字列を更新して、文字列値を保持し、ウィンドウの表示内容を更新する処理が行われる都度、設定しなおすなどして編集している内容が表示されるようにプログラムで制御しなければなりませんが、ここでは、ウィンドウ処理の基礎として、初期値を表示するだけのプログラムとしてきました。
次の記事:Win32/64アプリ開発 004