>> WINAPI入門トップに戻る

ウィンドウプロシージャ

今回はウィンドウプロシージャについて説明します。
前回はメッセージループまで説明して、
メッセージをウィンドウプロシージャに渡すところまで説明しました。
そのメッセージを受け取って処理するために、ウィンドウプロシージャを定義します。
ウィンドウプロシージャは書きのように定義します。

1LRESULT CALLBACK WinProc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp)
2{
3    switch(msg){
4        case WM_DESTROY:
5            PostQuitMessage(0);
6            return 0;
7    }
8    return DefWindowProc(hwnd,msg,wp,lp);
9}

まず関数の定義部分ですが、ウィンドウプロシージャはLRESULT型の値を返します。
またCALLBACK関数として定義するため、CALLBACKという文字を
指定する必要があります。
CALLBACK関数とはその関数にある情報を渡して、関数側でその値に応じた処理をさせ、
値を返してもらうような関数のことを言います。
関数名(ウィンドウプロシージャ名)は好きな名前をつけることが出来ます。
第一引数はHWND型
第二引数はUINT型
第三引数はWPARAM型
第四引数はLPARAM型
をそれぞれ指定します。
先頭から、ウィンドウハンドル、ウィンドウメッセージ、パラメータ1、パラメータ2の値を示しています。

この関数内には受信したメッセージに応じた処理を書く必要があります。
第二引数がそのメッセージを表すので、
その値を使ってswitch文で分岐させてます。
最低限指定しないといけないのは、WM_DESTROYメッセージです。
このメッセージはウィンドウが閉じられる(破棄される)時に飛んできます。
ですが、その時にウィンドウを閉じるだけではプログラム自体は終了しないため、
プログラム側に終了ですよ、というメッセージを投げてやる必要があります。
そこで、このWM_DESTROYのメッセージを受信したときに、PostQuitMessage関数
実行させてます。
引数には終了コードを指定しますが、当然正常に終わらせるので0を指定します。
この関数を実行することによって、WM_QUITメッセージが発行されます。
つまり、前回説明したメッセージループの処理を抜けて、プログラム自体が終了させることができるわけです。

プログラム終了時の対応はこれでいいのですが、
このメッセージ以外にもアプリケーション上ではさまざまなメッセージが飛び交っています。
それを全部手で書いてたら書ききれないので、ある関数に渡して自動で処理させてやります。
その関数が、DefWindowProc関数です。
この関数に、ウィンドウプロシージャの引数をそのままの順番でそのまま渡してやると、
デフォルトのウィンドウプロシージャでそのメッセージに応じた処理を自動で行ってくれます。
処理を行った後は、その処理後の終了コードを返してくるので、
ウィンドウプロシージャ内で、それを戻り値として戻してやる必要があります。
つまり、特別な処理を行いたいメッセージだけ、switch文の中に書き、
不要なものはDefWindowProc関数へ渡して処理してもらえばよい、というわけです。

以上がウィンドウプロシージャの説明になります。
ウィンドウの登録、作成、メッセージループ、ウィンドウプロシージャの定義を
全てまとめたコードが以下のものになります。

01#include <windows.h>
02 
03#define MSG(m) {\
04    MessageBoxA(NULL,m,NULL,MB_OK);}
05 
06//ウィンドウハンドル
07HWND hwnd;
08//インスタンスハンドル
09HINSTANCE hinst;
10 
11//ウィンドウ横幅
12#define WIDTH 500
13#define HEIGHT 500
14 
15LRESULT CALLBACK WinProc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp)
16{
17    switch(msg){
18        case WM_DESTROY:
19            PostQuitMessage(0);
20            return 0;
21    }
22    return DefWindowProc(hwnd,msg,wp,lp);
23}
24 
25int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
26{
27    MSG msg;
28    WNDCLASS wc;
29 
30    wc.style=CS_HREDRAW | CS_VREDRAW;
31    wc.lpfnWndProc=WinProc;
32    wc.cbClsExtra=wc.cbWndExtra=0;
33    wc.hInstance=hInstance;
34    wc.hCursor=wc.hIcon=NULL;
35    wc.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
36    wc.lpszClassName="test";
37    wc.lpszMenuName=NULL;
38     
39    if(!RegisterClass(&wc)){
40        MSG("クラスの登録失敗");
41        return -1;
42    }
43 
44    hwnd=CreateWindowA("test","テストウィンドウ",WS_VISIBLE | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX,
45        0,0,WIDTH,HEIGHT,NULL,NULL,hinst,NULL);
46 
47    if(hwnd==NULL){
48        MSG("ウィンドウ作成失敗");
49        return -1;
50    }
51 
52    //インスタンスハンドル
53    hinst=hInstance;
54 
55    //エラーチェック用変数
56    int check;
57 
58    while(check=GetMessage(&msg,NULL,0,0)){
59        if(check==-1){
60            break;
61        }
62        DispatchMessage(&msg);
63    }
64 
65    //クラス解放
66    UnregisterClass("test",hinst);
67 
68    return 0;
69 
70}


これをそのままコピーして実行すれば、画面左上にウィンドウが表示されます。
以上がウィンドウ作成までの説明になります。
次回からはボタンやエディットボックス等の各種コントロールについて説明していきます。


>> 【ボタンの作成】に進む
>> WINAPI入門トップに戻る