ウィンドウ プロシージャの記述
DispatchMessage 関数は、メッセージのターゲットであるウィンドウのウィンドウ プロシージャを呼び出します。 ウィンドウ プロシージャのシグネチャは次のとおりです。
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
4 つのパラメーターがあります。
- hwnd は、ウィンドウへのハンドルです。
- uMsg はメッセージ コードです。たとえば、WM_SIZE メッセージは、ウィンドウのサイズが変更されたことを示します。
- wParam と lParam には、メッセージに関連する追加のデータが含まれています。 正確な意味はメッセージ コードによって決まります。
LRESULT は、プログラムが Windows に返す整数値です。 これには、特定のメッセージに対するプログラムの応答が含まれます。 この値の意味は、メッセージ コードによって決まります。 CALLBACK は、関数の呼び出し規則です。
一般的なウィンドウ プロシージャは、メッセージ コードに基づいて切り替えを行う大きな switch ステートメントに過ぎません。 処理するメッセージごとにケースを追加します。
switch (uMsg)
{
case WM_SIZE: // Handle window resizing
// etc
}
メッセージの追加データは、lParam と wParam パラメーターに含まれています。 どちらのパラメーターも、ポインター幅 (32 ビットまたは 64 ビット) のサイズの整数値です。 それぞれの意味は、メッセージ コード (uMsg) によって決まります。 メッセージごとに、メッセージ コードを検索し、パラメーターを正しいデータ タイプにキャストする必要があります。 通常、データは数値または構造体へのポインターです。 一部のメッセージにはデータがありません。
たとえば、WM_SIZE メッセージのドキュメントには、次のように書かれています。
- wParam は、ウィンドウが最小化、最大化、またはサイズ変更されたかどうかを示すフラグです。
- lParam には、ウィンドウの新しい幅と高さが、1 つの 32 ビットまたは 64 ビットの値にパックされた 16 ビット値として格納されます。 これらの値を取得するには、何らかのビット シフトを実行する必要があります。 幸い、ヘッダー ファイル WinDef.h には、これを行うヘルパー マクロが含まれています。
一般的なウィンドウ プロシージャは数十のメッセージを処理するため、非常に長くなる可能性があります。 コードのモジュール性を高める方法の 1 つは、各メッセージを処理するためのロジックを別の関数にすることです。 ウィンドウ プロシージャで、wParam と lParam パラメーターを正しいデータ型にキャストし、それらの値を関数に渡します。 たとえば、WM_SIZE メッセージを処理するためのウィンドウ プロシージャは次のようになります。
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_SIZE:
{
int width = LOWORD(lParam); // Macro to get the low-order word.
int height = HIWORD(lParam); // Macro to get the high-order word.
// Respond to the message:
OnSize(hwnd, (UINT)wParam, width, height);
}
break;
}
}
void OnSize(HWND hwnd, UINT flag, int width, int height)
{
// Handle resizing
}
LOWORD と HIWORD マクロは、lParam から 16 ビットの幅と高さの値を取得します。 ウィンドウ プロシージャは、幅と高さを抽出し、これらの値を OnSize
関数に渡します。
既定のメッセージ処理
ウィンドウ プロシージャで特定のメッセージを処理しない場合は、メッセージ パラメーターを DefWindowProc 関数に直接渡します。 この関数は、メッセージの種類によって異なるメッセージの既定のアクションを実行します。
return DefWindowProc(hwnd, uMsg, wParam, lParam);
ウィンドウ プロシージャでのボトルネックの回避
ウィンドウ プロシージャは、実行中に、同じスレッドで作成されたウィンドウに対する他のメッセージをブロックします。 そのため、ウィンドウ プロシージャ内では長い処理を行わないようにします。 たとえば、プログラムが TCP 接続を開き、サーバーから応答があるまで無期限に待機するとします。 それをウィンドウ プロシージャの内部で行うと、要求が完了するまで UI は応答しなくなります。 その間、ウィンドウはマウスやキーボードの入力を処理したり、それ自体を再描画したりできず、閉じることさえできません。
代わりに、Windows に組み込まれているマルチタスク機能のいずれかを使って、作業を別のスレッドに移動する必要があります。
- 新しいスレッドを作成する。
- スレッド プールを使用する。
- 非同期 I/O 呼び出しを使う。
- 非同期プロシージャ呼び出しを使う。