|
|
|
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 を指定して、制限を設けません。 複雑なメッセージループ 上記のメッセージループのコードは、一番単純な基本形です。普通のアプリケーションではもう少し複雑になります。 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 で通常のメッセージ処理を行ないます。
|