ウィンドウ プロシージャの記述

DispatchMessage 関数は、メッセージのターゲットであるウィンドウのウィンドウ プロシージャを呼び出します。 ウィンドウ プロシージャのシグネチャは次のとおりです。

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

4 つのパラメーターがあります。

  • hwnd は、ウィンドウへのハンドルです。
  • uMsg はメッセージ コードです。たとえば、WM_SIZE メッセージは、ウィンドウのサイズが変更されたことを示します。
  • wParamlParam には、メッセージに関連する追加のデータが含まれています。 正確な意味はメッセージ コードによって決まります。

LRESULT は、プログラムが Windows に返す整数値です。 これには、特定のメッセージに対するプログラムの応答が含まれます。 この値の意味は、メッセージ コードによって決まります。 CALLBACK は、関数の呼び出し規則です。

一般的なウィンドウ プロシージャは、メッセージ コードに基づいて切り替えを行う大きな switch ステートメントに過ぎません。 処理するメッセージごとにケースを追加します。

switch (uMsg)
{
    case WM_SIZE: // Handle window resizing

    // etc
}

メッセージの追加データは、lParamwParam パラメーターに含まれています。 どちらのパラメーターも、ポインター幅 (32 ビットまたは 64 ビット) のサイズの整数値です。 それぞれの意味は、メッセージ コード (uMsg) によって決まります。 メッセージごとに、MSDN でメッセージ コードを検索し、パラメーターを正しいデータ型にキャストする必要があります。 通常、データは数値または構造体へのポインターです。 一部のメッセージにはデータがありません。

たとえば、WM_SIZE メッセージのドキュメントには、次のように書かれています。

  • wParam は、ウィンドウが最小化、最大化、またはサイズ変更されたかどうかを示すフラグです。
  • lParam には、ウィンドウの新しい幅と高さが、1 つの 32 ビットまたは 64 ビットの値にパックされた 16 ビット値として格納されます。 これらの値を取得するには、何らかのビット シフトを実行する必要があります。 幸い、ヘッダー ファイル WinDef.h には、これを行うヘルパー マクロが含まれています。

一般的なウィンドウ プロシージャは数十のメッセージを処理するため、非常に長くなる可能性があります。 コードのモジュール性を高める方法の 1 つは、各メッセージを処理するためのロジックを別の関数にすることです。 ウィンドウ プロシージャで、wParamlParam パラメーターを正しいデータ型にキャストし、それらの値を関数に渡します。 たとえば、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
}

LOWORDHIWORD マクロは、lParam から 16 ビットの幅と高さの値を取得します。 (MSDN ドキュメントで、メッセージ コードごとにこれらの種類の詳細を検索できます。)ウィンドウ プロシージャは、幅と高さを抽出し、これらの値を OnSize 関数に渡します。

既定のメッセージ処理

ウィンドウ プロシージャで特定のメッセージを処理しない場合は、メッセージ パラメーターを DefWindowProc 関数に直接渡します。 この関数は、メッセージの種類によって異なるメッセージの既定のアクションを実行します。

return DefWindowProc(hwnd, uMsg, wParam, lParam);

ウィンドウ プロシージャでのボトルネックの回避

ウィンドウ プロシージャは、実行中に、同じスレッドで作成されたウィンドウに対する他のメッセージをブロックします。 そのため、ウィンドウ プロシージャ内では長い処理を行わないようにします。 たとえば、プログラムが TCP 接続を開き、サーバーから応答があるまで無期限に待機するとします。 それをウィンドウ プロシージャの内部で行うと、要求が完了するまで UI は応答しなくなります。 その間、ウィンドウはマウスやキーボードの入力を処理したり、それ自体を再描画したりできず、閉じることさえできません。

代わりに、Windows に組み込まれているマルチタスク機能のいずれかを使って、作業を別のスレッドに移動する必要があります。

  • 新しいスレッドを作成する。
  • スレッド プールを使用する。
  • 非同期 I/O 呼び出しを使う。
  • 非同期プロシージャ呼び出しを使う。

次へ

ウィンドウの描画