ウィンドウ プロシージャの使用

このセクションでは、ウィンドウ プロシージャに関連付けられている次のタスクを実行する方法について説明します。

ウィンドウ プロシージャの設計

次の例は、一般的なウィンドウ プロシージャの構造を示しています。 ウィンドウ プロシージャでは、 switch ステートメントの message 引数を使用し、個別の case ステートメントで処理される個々のメッセージを使用します。 各ケースは、各メッセージの特定の値を返していることに注意してください。 処理されないメッセージの場合、ウィンドウ プロシージャは DefWindowProc 関数を呼び出します。

LRESULT CALLBACK MainWndProc(
    HWND hwnd,        // handle to window
    UINT uMsg,        // message identifier
    WPARAM wParam,    // first message parameter
    LPARAM lParam)    // second message parameter
{ 
 
    switch (uMsg) 
    { 
        case WM_CREATE: 
            // Initialize the window. 
            return 0; 
 
        case WM_PAINT: 
            // Paint the window's client area. 
            return 0; 
 
        case WM_SIZE: 
            // Set the size and position of the window. 
            return 0; 
 
        case WM_DESTROY: 
            // Clean up window-specific data objects. 
            return 0; 
 
        // 
        // Process other messages. 
        // 
 
        default: 
            return DefWindowProc(hwnd, uMsg, wParam, lParam); 
    } 
    return 0; 
} 

WM_NCCREATE メッセージはウィンドウが作成された直後に送信されますが、アプリケーションが FALSE を返してこのメッセージに応答すると、CreateWindowEx 関数は失敗します。 WM_CREATE メッセージは、ウィンドウが既に作成された後に送信されます。

WM_DESTROY メッセージは、ウィンドウが破棄されるときに送信されます。 DestroyWindow 関数は、破棄されるウィンドウの子ウィンドウを破棄する処理を行います。 WM_NCDESTROY メッセージは、ウィンドウが破棄される直前に送信されます。

少なくとも、ウィンドウ プロシージャは、 WM_PAINT メッセージを処理して描画する必要があります。 通常は、マウスとキーボードのメッセージも処理する必要があります。 個々のメッセージの説明を参照して、ウィンドウ プロシージャで処理する必要があるかどうかを判断します。

アプリケーションは、メッセージの処理の一部として DefWindowProc 関数を呼び出すことができます。 このような場合、アプリケーションは、 メッセージを DefWindowProc に渡す前にメッセージ パラメーターを変更するか、独自の操作を実行した後に既定の処理を続行できます。

ダイアログ ボックス プロシージャは 、WM_CREATE メッセージではなくWM_INITDIALOG メッセージを 受け取り、未処理のメッセージを DefDlgProc 関数に渡しません。 それ以外の場合、ダイアログ ボックス プロシージャはウィンドウ プロシージャとまったく同じです。

ウィンドウ プロシージャとウィンドウ クラスの関連付け

クラスを登録するときに、ウィンドウ プロシージャをウィンドウ クラスに関連付けます。 WNDCLASS 構造体には クラスに関する情報を入力する必要があり、lpfnWndProc メンバーはウィンドウ プロシージャのアドレスを指定する必要があります。 クラスを登録するには、 WNDCLASS 構造体のアドレスを RegisterClass 関数に渡します。 ウィンドウ クラスが登録されると、ウィンドウ プロシージャは、そのクラスで作成された新しいウィンドウごとに自動的に関連付けられます。

次の例は、前の例のウィンドウ プロシージャをウィンドウ クラスに関連付ける方法を示しています。

int APIENTRY WinMain( 
    HINSTANCE hinstance,  // handle to current instance 
    HINSTANCE hinstPrev,  // handle to previous instance 
    LPSTR lpCmdLine,      // address of command-line string 
    int nCmdShow)         // show-window type 
{ 
    WNDCLASS wc; 
 
    // Register the main window class. 
    wc.style = CS_HREDRAW | CS_VREDRAW; 
    wc.lpfnWndProc = (WNDPROC) MainWndProc; 
    wc.cbClsExtra = 0; 
    wc.cbWndExtra = 0; 
    wc.hInstance = hinstance; 
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); 
    wc.hCursor = LoadCursor(NULL, IDC_ARROW); 
    wc.hbrBackground = GetStockObject(WHITE_BRUSH); 
    wc.lpszMenuName =  "MainMenu"; 
    wc.lpszClassName = "MainWindowClass"; 
 
    if (!RegisterClass(&wc)) 
       return FALSE; 
 
    // 
    // Process other messages. 
    // 
 
} 

ウィンドウのサブクラス化

ウィンドウのインスタンスをサブクラス化するには、 SetWindowLong 関数を呼び出し、ウィンドウへのハンドルを指定して、GWL_WNDPROC フラグとサブクラス プロシージャへのポインターをサブクラス化します。 SetWindowLong は、元のウィンドウ プロシージャへのポインターを返します。このポインターを使用して、元のプロシージャにメッセージを渡します。 サブクラス ウィンドウ プロシージャでは、元のウィンドウ プロシージャを 呼び出すために CallWindowProc 関数を使用する必要があります。

Note

32 ビットバージョンと 64 ビットバージョンの両方の Windows と互換性のあるコードを記述するには、 SetWindowLongPtr 関数を使用します。

 

次の例は、ダイアログ ボックスで編集コントロールのインスタンスをサブクラス化する方法を示しています。 サブクラス ウィンドウ プロシージャを使用すると、コントロールが入力フォーカスを持つたびに、Enter キーと Tab キーを含むすべてのキーボード入力を編集コントロールで受け取ることができます。

WNDPROC wpOrigEditProc; 
 
LRESULT APIENTRY EditBoxProc(
    HWND hwndDlg, 
    UINT uMsg, 
    WPARAM wParam, 
    LPARAM lParam) 
{ 
    HWND hwndEdit; 
 
    switch(uMsg) 
    { 
        case WM_INITDIALOG: 
            // Retrieve the handle to the edit control. 
            hwndEdit = GetDlgItem(hwndDlg, ID_EDIT); 
 
            // Subclass the edit control. 
            wpOrigEditProc = (WNDPROC) SetWindowLong(hwndEdit, 
                GWL_WNDPROC, (LONG) EditSubclassProc); 
            // 
            // Continue the initialization procedure. 
            // 
            return TRUE; 
 
        case WM_DESTROY: 
            // Remove the subclass from the edit control. 
            SetWindowLong(hwndEdit, GWL_WNDPROC, 
                (LONG) wpOrigEditProc); 
            // 
            // Continue the cleanup procedure. 
            // 
            break; 
    } 
    return FALSE; 
        UNREFERENCED_PARAMETER(lParam); 
} 
 
// Subclass procedure 
LRESULT APIENTRY EditSubclassProc(
    HWND hwnd, 
    UINT uMsg, 
    WPARAM wParam, 
    LPARAM lParam) 
{ 
    if (uMsg == WM_GETDLGCODE) 
        return DLGC_WANTALLKEYS; 
 
    return CallWindowProc(wpOrigEditProc, hwnd, uMsg, 
        wParam, lParam); 
}