フックの概要
フックは、アプリケーションがメッセージ、マウスアクション、キーストロークなどのイベントをインターセプトできるメカニズムです。 特定の種類のイベントをインターセプトする関数は、 フック プロシージャと呼ばれます。 フック プロシージャは、受け取る各イベントに対して動作し、イベントを変更または破棄できます。
次の例では、 をフックに使用しています。
- デバッグ目的でメッセージを監視する
- マクロの記録と再生のサポートを提供する
- ヘルプ キーのサポートを提供する (F1)
- マウスとキーボードの入力をシミュレートする
- コンピューターベースのトレーニング (CBT) アプリケーションを実装する
注意
フックは、各メッセージに対してシステムが実行する必要がある処理の量が増えるので、システムの速度が低下する傾向があります。 必要な場合にのみフックをインストールし、できるだけ早く削除する必要があります。
このセクションでは、次について説明します。
フック チェーン
このシステムでは、さまざまな種類のフックがサポートされています。各型は、メッセージ処理メカニズムのさまざまな側面にアクセスできます。 たとえば、アプリケーションでは 、WH_MOUSE フックを使用して、マウス メッセージのメッセージ トラフィックを監視できます。
システムは、フックの種類ごとに個別のフック チェーンを保持します。 フック チェーンは、フック プロシージャと呼ばれる特殊なアプリケーション定義コールバック関数へのポインターの一覧です。 特定の種類のフックに関連付けられているメッセージが発生すると、システムは、フック チェーンで参照されている各フック プロシージャにメッセージを 1 つずつ渡します。 フック プロシージャが実行できるアクションは、関連するフックの種類によって異なります。 一部の種類のフックのフック プロシージャでは、メッセージのみを監視できます。他のユーザーは、メッセージを変更したり、チェーンを介して進行状況を停止したりして、次のフック プロシージャや宛先ウィンドウに到達できないようにすることができます。
フック プロシージャ
特定の種類のフックを利用するために、開発者はフック プロシージャを提供し、 SetWindowsHookEx 関数を使用してフックに関連付けられているチェーンにインストールします。 フック プロシージャには、次の構文が必要です。
LRESULT CALLBACK HookProc(
int nCode,
WPARAM wParam,
LPARAM lParam
)
{
// process event
...
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
HookProc は、アプリケーション定義名のプレースホルダーです。
nCode パラメーターは、フック プロシージャが実行するアクションを決定するために使用するフック コードです。 フック コードの値は、フックの種類によって異なります。各タイプには、フック コードの独自の特性セットがあります。 wParam パラメーターと lParam パラメーターの値はフック コードによって異なりますが、通常は送信または投稿されたメッセージに関する情報が含まれます。
SetWindowsHookEx 関数は、常にフック チェーンの先頭にフック プロシージャをインストールします。 特定の種類のフックによって監視されるイベントが発生すると、システムはフックに関連付けられているフック チェーンの先頭でプロシージャを呼び出します。 チェーン内の各フック プロシージャは、イベントを次のプロシージャに渡すかどうかを決定します。 フック プロシージャは 、CallNextHookEx 関数を呼び出して、次のプロシージャにイベントを渡します。
一部の種類のフックのフック プロシージャでは、メッセージのみを監視できることに注意してください。 システムは、特定のプロシージャが CallNextHookEx を呼び出すかどうかに関係なく、各フック プロシージャにメッセージを渡します。
グローバル フックは、呼び出し元スレッドと同じデスクトップ内のすべてのスレッドのメッセージを監視します。 スレッド固有のフックは、個々のスレッドについてのみメッセージを監視します。 グローバル フック プロシージャは、呼び出し元のスレッドと同じデスクトップ内の任意のアプリケーションのコンテキストで呼び出すことができるため、プロシージャは別の DLL モジュール内にある必要があります。 スレッド固有のフック プロシージャは、関連付けられたスレッドのコンテキストでのみ呼び出されます。 アプリケーションが独自のスレッドの 1 つに対してフック プロシージャをインストールする場合、フック プロシージャは、アプリケーションのコードの残りの部分と同じモジュールまたは DLL 内に置くことができます。 アプリケーションが別のアプリケーションのスレッドのフック プロシージャをインストールする場合、プロシージャは DLL 内にある必要があります。 詳細については、「 ダイナミック リンク ライブラリ」を参照してください。
注意
グローバル フックは、デバッグ目的でのみ使用する必要があります。それ以外の場合は、それらを避ける必要があります。 グローバル フックはシステムのパフォーマンスを低下させ、同じ種類のグローバル フックを実装する他のアプリケーションとの競合を引き起こします。
フックの種類
フックの種類ごとに、アプリケーションはシステムのメッセージ処理メカニズムのさまざまな側面を監視できます。 次のセクションでは、使用可能なフックについて説明します。
- WH_CALLWNDPROCとWH_CALLWNDPROCRET
- WH_CBT
- WH_DEBUG
- WH_FOREGROUNDIDLE
- WH_GETMESSAGE
- WH_JOURNALPLAYBACK
- WH_JOURNALRECORD
- WH_KEYBOARD_LL
- WH_KEYBOARD
- WH_MOUSE_LL
- WH_MOUSE
- WH_MSGFILTERとWH_SYSMSGFILTER
- WH_SHELL
WH_CALLWNDPROCとWH_CALLWNDPROCRET
WH_CALLWNDPROCとWH_CALLWNDPROCRETフックを使用すると、ウィンドウ プロシージャに送信されたメッセージを監視できます。 システムは、メッセージ を 受信ウィンドウ プロシージャに渡す前にWH_CALLWNDPROCフック プロシージャを呼び出し、ウィンドウ プロシージャがメッセージを処理した後に WH_CALLWNDPROCRET フック プロシージャを呼び出します。
WH_CALLWNDPROCRETフックは、CWPRETSTRUCT 構造体へのポインターをフック プロシージャに渡します。 構造体には、メッセージを処理したウィンドウ プロシージャからの戻り値と、メッセージに関連付けられているメッセージ パラメーターが含まれます。 プロセス間で設定されたメッセージに対してウィンドウをサブクラス化することはできません。
詳細については、 CallWndProc および CallWndRetProc コールバック関数に関するページを参照してください。
WH_CBT
システムは、ウィンドウをアクティブ化、作成、破棄、最小化、最大化、移動、またはサイズ変更する前に、 WH_CBT フック プロシージャを呼び出します。システム コマンドを完了する前に。システム メッセージ キューからマウスまたはキーボード イベントを削除する前に。入力フォーカスを設定する前に。または をシステム メッセージ キューと同期する前に行います。 フック プロシージャが返す値は、システムがこれらの操作のいずれかを許可または禁止するかどうかを決定します。 WH_CBT フックは、主にコンピューター ベースのトレーニング (CBT) アプリケーションを対象としています。
詳細については、 CBTProc コールバック関数に関するページを参照してください。
詳細については、「 WinEvents」を参照してください。
WH_DEBUG
システムは、 システム内 の他のフックに関連付けられているフック プロシージャを呼び出す前に、WH_DEBUGフック プロシージャを呼び出します。 このフックを使用して、システムが他のタイプのフックに関連付けられたフック・プロシージャーを呼び出せるようにするかどうかを判別できます。
詳細については、 DebugProc コールバック関数に関するページを参照してください。
WH_FOREGROUNDIDLE
WH_FOREGROUNDIDLEフックを使用すると、フォアグラウンド スレッドがアイドル状態のときに優先度の低いタスクを実行できます。 アプリケーションのフォアグラウンド スレッドがアイドル状態になると、システムは WH_FOREGROUNDIDLE フック プロシージャを呼び出します。
詳細については、 ForegroundIdleProc コールバック関数に関するページを参照してください。
WH_GETMESSAGE
WH_GETMESSAGEフックを使用すると、GetMessage 関数または PeekMessage 関数によって返されるメッセージをアプリケーションで監視できます。 WH_GETMESSAGE フックを使用して、マウスとキーボードの入力、およびメッセージ キューに投稿されたその他のメッセージを監視できます。
詳細については、 GetMsgProc コールバック関数に関するページを参照してください。
WH_JOURNALPLAYBACK
警告
ジャーナリング フック API は、Windows 11以降サポートされておらず、今後のリリースで削除される予定です。 このため、代わりに SendInput TextInput API を呼び出すように強くお勧めします。
WH_JOURNALPLAYBACK フックを使用すると、アプリケーションはシステム メッセージ キューにメッセージを挿入できます。 このフックを使用すると、 WH_JOURNALRECORDを使用して、前に記録した一連のマウス イベントとキーボード イベントを再生できます。 WH_JOURNALPLAYBACKフックがインストールされている限り、通常のマウスとキーボードの入力は無効になります。 WH_JOURNALPLAYBACK フックはグローバル フックであり、スレッド固有のフックとして使用することはできません。
WH_JOURNALPLAYBACK フックはタイムアウト値を返します。 この値は、再生フックから現在のメッセージを処理するまでに待機するミリ秒数をシステムに通知します。 これにより、フックは再生するイベントのタイミングを制御できます。
詳細については、 JournalPlaybackProc コールバック関数に関するページを参照してください。
WH_JOURNALRECORD
警告
ジャーナリング フック API は、Windows 11以降サポートされておらず、今後のリリースで削除される予定です。 このため、代わりに SendInput TextInput API を呼び出すように強くお勧めします。
WH_JOURNALRECORDフックを使用すると、入力イベントを監視および記録できます。 通常、このフックを使用して、WH_JOURNALPLAYBACKを使用して後で再生する一連のマウス イベントとキーボード イベント を記録します。 WH_JOURNALRECORD フックはグローバル フックであり、スレッド固有のフックとして使用することはできません。
詳細については、 JournalRecordProc コールバック関数に関するページを参照してください。
WH_KEYBOARD_LL
WH_KEYBOARD_LLフックを使用すると、スレッド入力キューにポストされようとしているキーボード入力イベントを監視できます。
詳細については、 LowLevelKeyboardProc コールバック関数に関するページを参照してください。
WH_KEYBOARD
WH_KEYBOARD フックを使用すると、アプリケーションは GetMessage または PeekMessage 関数によって返されるWM_KEYDOWNメッセージとWM_KEYUPメッセージのメッセージ トラフィックを監視できます。 WH_KEYBOARD フックを使用して、メッセージ キューにポストされたキーボード入力を監視できます。
詳細については、 KeyboardProc コールバック関数に関するページを参照してください。
WH_MOUSE_LL
WH_MOUSE_LLフックを使用すると、スレッド入力キューにポストされようとしているマウス入力イベントを監視できます。
詳細については、 LowLevelMouseProc コールバック関数に関するページを参照してください。
WH_MOUSE
WH_MOUSEフックを使用すると、GetMessage 関数または PeekMessage 関数によって返されるマウス メッセージを監視できます。 WH_MOUSE フックを使用して、メッセージ キューにポストされたマウス入力を監視できます。
詳細については、 MouseProc コールバック関数に関するページを参照してください。
WH_MSGFILTERとWH_SYSMSGFILTER
WH_MSGFILTERとWH_SYSMSGFILTERフックを使用すると、メニュー、スクロール バー、メッセージ ボックス、またはダイアログ ボックスで処理されるメッセージを監視したり、ユーザーが Alt + Tab キーまたは Alt + Esc キーの組み合わせを押した結果として、別のウィンドウがアクティブ化されようとしている状況を検出したりできます。 WH_MSGFILTER フックは、フック プロシージャをインストールしたアプリケーションによって作成されたメニュー、スクロール バー、メッセージ ボックス、またはダイアログ ボックスに渡されたメッセージのみを監視できます。 WH_SYSMSGFILTERフックは、すべてのアプリケーションに対してこのようなメッセージを監視します。
WH_MSGFILTERとWH_SYSMSGFILTERフックを使用すると、モーダル ループ中にメッセージ フィルター処理を実行できます。これは、メイン メッセージ ループで実行されるフィルター処理と同じです。 たとえば、アプリケーションは、キューからメッセージを取得してからメッセージをディスパッチする時間までの間に、メイン ループ内の新しいメッセージを調べて、必要に応じて特別な処理を実行します。 ただし、モーダル ループ中に、システムはメッセージを取得してディスパッチします。これにより、メイン メッセージ ループ内のメッセージをアプリケーションがフィルター処理できるようになります。 アプリケーションが WH_MSGFILTER または WH_SYSMSGFILTER フック プロシージャをインストールした場合、システムはモーダル ループ中にプロシージャを呼び出します。
アプリケーションは CallMsgFilter 関数を呼び出すことによって、WH_MSGFILTER フックを直接呼び出すことができます。 この関数を使用すると、アプリケーションは同じコードを使用して、メイン メッセージ ループで使用するモーダル ループ中にメッセージをフィルター処理できます。 そのためには、フィルター処理操作をWH_MSGFILTERフック プロシージャにカプセル化し、GetMessage 関数と DispatchMessage 関数の呼び出しの間で CallMsgFilter を呼び出します。
while (GetMessage(&msg, (HWND) NULL, 0, 0))
{
if (!CallMsgFilter(&qmsg, 0))
DispatchMessage(&qmsg);
}
CallMsgFilter の最後の引数は、フック プロシージャに渡されるだけです。任意の値を入力できます。 フック プロシージャは、 MSGF_MAINLOOPなどの定数を定義することで、この値を使用してプロシージャの呼び出し元を特定できます。
詳細については、 MessageProc および SysMsgProc コールバック関数に関するページを参照してください。
WH_SHELL
シェル アプリケーションでは、 WH_SHELL フックを使用して重要な通知を受信できます。 システムは、シェル・アプリケーションがアクティブ化されようとしているとき、およびトップレベル・ウィンドウが作成または破棄されるときに、 WH_SHELL フック・プロシージャーを呼び出します。
カスタム シェル アプリケーションは、 WH_SHELLメッセージを 受信しないことに注意してください。 したがって、それ自体を既定のシェルとして登録するアプリケーションは、メッセージを受信する前に SystemParametersInfo 関数 (またはその他のアプリケーション) を 呼び出す必要がありますWH_SHELL。 この関数は、 SPI_SETMINIMIZEDMETRICS と MINIMIZEDMETRICS 構造体を使用して呼び出す必要があります。 この構造体の iArrange メンバーを ARW_HIDEに設定します。
詳細については、 ShellProc コールバック関数に関するページを参照してください。