アークピットのホームページに戻る

WinAPIトピックのトップページに戻る

APIトピックの各章に移動する

ダウンロードのページに移動する
ダウンロードができ
ない場合の対処法
 

ページ移動

1-3-6. メッセージループ

 Windowsのプログラミングは、イベントドリブン型だと良く言われます。これを具現しており、理解の難しいループが次にきます。
    while (GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
 最初見たとき、これを理解するのは非常に困難でした。WinMainが、この「おまじない」のようなループを描いているだけなのですから、当たりまえです。
 これを理解するには、GUIの特徴を検討しなければいけません。GUIは、ユーザがマウスやキーを操作して、何らかのきっかけを与えなければ、何ら処理は発生しません。つまりマウスやキーの操作を行なうことで、イベントが発生します。そしてイベントはメッセージの形で、システムのキューに溜まります。メッセージは、「いつ・どこで・何が」起こったことを表すデータです。またキューとは、メッセージを先入れ先出し(FIFO)形式で保存するリングバッファのことです。ここまではシステムは自動的に行なっています。

 さてここで、上記コードに戻ります。まず、GetMessage でキューにある、このスレッドまたはアプリケーションに属するウィンドウに対するメッセージを取得します。取得したメッセージは、msg の構造体に納めれら、キューからは除かれます。この関数の第2パラメータには、ウィンドウのハンドルを渡します。すると、GetMessage はそのウィンドウに関したメッセージしか取得しません。NULL の場合は、呼び出したスレッドに属するすべてのウィンドウに送られるメッセージを取得します。つまりWinMainで1つだけループを作成するのであれば、ここで、アプリケーションのすべてのウィンドウのメッセージ処理を一括して処理します。よってウィンドウを特定するのは間違いです。よって、NULL を指定します。この関数の後の2つのパラメータは、取得するメッセージの範囲です。これも 0,0 を指定して、制限を設けません。
 TranslateMessage 関数は、 仮想キーのメッセージを文字メッセージに変換します。文字メッセージは呼び出し側のスレッドのメッセージのキューにポストされ、 次にスレッドが GetMessage 関数や PeekMessage 関数を呼び出すときに読み取られます。
 DispatchMessage 関数は、 メッセージを対象のウィンドウのプロシージャに送出(ディスパッチ ) します。送出するとは、システムがプロシージャをコールすることを意味します。
 GetMessage 関数は、WM_QUIT のメッセージを得ると、FLASE を返します。すると、このループを抜けます。WM_QUIT のメッセージは、プロシージャ内で、PostQuitMessage 関数をコールすると発生します。そしてメッセージデータの wParam メンバを返します。

複雑なメッセージループ

 上記のメッセージループのコードは、一番単純な基本形です。普通のアプリケーションではもう少し複雑になります。
    while (GetMessage(&msg,NULL,0,0))
    {
        if (hFindWnd && IsDialogMessage(hFindWnd,&msg)) continue;
        if (hHLPWnd)
        {
             if (PropSheet_GetCurrentPageHwnd(hHLPWnd) == NULL)
             {
                 DestroyWindow(hHLPWnd);
                 hHLPWnd = NULL;
             }
             else if (PropSheet_IsDialogMessage(hHLPWnd,&msg))continue;
        }
        if (!TranslateAccelerator(hMainWnd,hAccel,&msg)
                         && !TranslateMDISysAccel(hClientWnd,&msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
 ダイアログボックスボックスは、通常は表示すると、クローズするまで管理はダイアログボックスの処理に移ります。つまりその間はダイアログボックスだけしか操作できません。それをモーダルタイプと言います。それとは別にモードレスタイプと言うダイアログボックスボックスがあり、CreateDialog 関数で作成します。このタイプは作成すると、すぐ戻ってきます。よってメインのウィンドウもダイアログボックスも操作が可能です。モーダルタイプの場合は、システム内でループ処理を行ないますので、問題はありません。しかしモードレスの場合は、WinMain内のメッセージループでメッセージの配信を処理することになります。ダイアログボックスもウィンドウですので、大部分のメッセージは通常と何ら変わることはありません。1つだけ、ダイアログボックスの場合は、[Tab]や[↓]キーでコントロールを移動できます。このメッセージの処理を、IsDialogMessage 関数で行ないます。メッセージがキーで対象の場合は、この関数は真を返しますので、その場合は、このメッセージの処理は終わりました。continue で、GetMessage に戻ります。ここでは、「検索」ウィンドウの処理を行なっています。
 プロパティシートもダイアログボックスと同じことが言えます。PropSheet_IsDialogMessage でキーの処理を行ないます。プロパティシートは、コントロールの章で説明します。その他に、クローズ処理も行なっています。

 アクセラレータキーは、良く使用する機能です。しかし使用する場合は、TranslateAccelerator 関数で、キーの変換を行ないます。指定されたアクセラレータがあるときに、この関数は、WM_KEYUP メッセージや WM_KEYDOWN メッセージを、 WM_COMMANDメッセージや、WM_SYSCOMMAND メッセージに変換し、 これらのメッセージを対応するプロシージャに直接送ります。この処理を行なわない時には、偽を返しますので、その場合だけ、TranslateMessage と DispatchMessage で通常のメッセージ処理を行ないます。
 TranslateMDISysAccel 関数は、MDIに関するアクセラレータキーの処理を行ないます。MDIタイプのウィンドウの場合は、これを入れる必要があります。MDIは、クラスとウィンドウの章で説明します。

ページ移動