さて、フックです。通常ユーティリティアプリケーションで使用するのは「システムフック」ですが、その前に、フックを理解するために「ローカルフック」について見てみようと思います。
|
メッセージの流れ
MFCユーザーもいると思うので、まずメッセージの流れについて見てみましょう。 まずメッセージは、ウィンドウズのシステムから送られてきます。キー入力やマウス操作、SendMessage()等を使用して送られてくるメッセージはすべてシステムからによるものです。 送られてきたメッセージは、一部を除いてメッセージキューと呼ばれるものに順番に蓄えられます。キューはひとつのスレッドにつきひとつだけ存在するので、スレッドが持つすべてのウィンドウ宛のメッセージがごちゃ混ぜになって積み重ねられることになります。
ここまでは規定のシステムで、何もしなくても普通にプログラムを組めば行えるものですが、ここからは実際にプログラムを組まなければならない部分です。 |
MSG stMsg;
while( GetMessage( &stMsg, NULL, 0, 0 ) )
{
TranslateMessage( &stMsg );
DispatchMessage( &stMsg );
}
GetMessage()はキューからメッセージを取得し、MSG構造体へと格納します。これを半永久的に繰り返すのが、メッセージループの役割です。
キューから取り出したメッセージはTranslateMessage()によって処理されたあと、DispatchMessage()によって、メッセージの送り先となるウィンドウが持つ関数、ウィンドウプロシージャへと転送されます。
ウィンドウプロシージャは、ウィンドウクラス登録時に特定のウィンドウへと結びつけられる関数のことで、例えば次のような関数を用意します。 |
LRESULT CALLBACK WndProc( HWND p_hWnd, UINT p_uiMsg, WPARAM wParam, LPARAM lParam )
{
// メッセージを処理します。
switch( p_uiMsg )
{
case WM_DESTROY: //×ボタンが押されたとき。
PostQuitMessage( 0 ); //アプリケーションを終了させます。
return 0;
}
return DefWindowProc( p_hWnd, p_uiMsg, wParam, lParam );
}
ウィンドウプロシージャはウィンドウごとに与えられる、メッセージを処理するための関数です。DispatchMessage()に渡されたメッセージはこのウィンドウプロシージャへと送られます。また、システムから送られてくるメッセージの一部(例えばSendMessage()を用いて送られたもの)は、メッセージキューを介さず直接プロシージャへと送られます。
このような手順でウィンドウプロシージャはメッセージを受け取り、プログラマーはそのための処理をプログラムすることになります。MFCではメッセージループを内部に持ち、メッセージは「メッセージハンドラ」と呼ばれる関数へと送られ、そのなかに処理を組み込むことになります。
この辺の話は「MFCユーザーのためのAPI講座」の中でそれなりに詳しく書いてあるので、そちらもご覧ください。 |
フックとは
このメッセージの流れを見れば分かるとおり、プログラミングする部分はわずかです。基本的には、メッセージループとウィンドウプロシージャを組むだけです。そして逆に言えば、それ以外の部分に手を出すことができないということでもあります。 例えば特定のキー入力やマウスクリックを無効化したいときなどにはどうすればいいのでしょう。ウィンドウプロシージャの中で処理を組む場合、複数の種類のウィンドウが存在したら、そのすべてのプロシージャで処理しなければならなくなります。また、組み込みコントロール(ボタンとか)は、プロシージャを内部に持つため、プログラムで変更することができません(「サブクラス化」すればできますが、それはのちほど)。 さらに、MFCを使うにしても、SDKにしても、メッセージループの中で処理を行うのは難しいところがあります。メッセージループはプログラムの中でももっとも深い部分ですので、この部分に手を加えたらどんな影響が出てくるのか心配です。
このような問題に対して、違うアプローチとして存在するのがフックです。
この便利さゆえ、フックはしばしばアプリケーションに致命的なダメージを与えることがあります。そうならないようできる限り回避するため、フックにはいくつか種類があり、拾えるメッセージや拾う場所の違う色々な種類のフックが用意されています。 |
フックの種類
フックにはまずローカルフックとグローバルフック(システムフック)の2週類があります。
ローカルフックは、自分のスレッドのみに働くフックのことです。それほど使い道はありませんが、モーダレスダイアログをモーダルダイアログに見せかけたり、作製されたダイアログのボタン等を手当たり次第取得したい場合などに使用します。
このふたつははっきりと目的が違います。ローカルフックは自分のアプリケーションで特殊な処理を行いたいときに使用し、システムフックはユーティリティアプリケーションでシステムをコントロールしたいときに使用します。
このふたつとは別に、フックには様々な種類があります。以下に主なフックを表としてまとめておきます(筆者は以下の各フックについて詳しくはありません。実際に使用するときには、各フックプロシージャのリファレンスをよく読んでください)。 |
|
以上のフックを目的に合わせて使い分けることが重要です。
|
つづく
というわけで、概念の説明はここまで。次回からは実際にフックを使用して、どんな感じになるのか見てみましょう。 |
(C)KAB-studio 1998 ALL RIGHTS RESERVED. |