フックは、アプリケーションがメッセージ、マウス アクション、キーストロークなどのイベントをインターセプトできるメカニズムです。 特定の種類のイベントをインターセプトする関数は、 フック プロシージャと呼ばれます。 フック プロシージャは、受信した各イベントに対して動作し、イベントを変更または破棄できます。
フックの使用例を次に示します。
- デバッグ目的でメッセージを監視する
- マクロの記録と再生のサポートを提供する
- ヘルプ キーのサポートを提供する (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 内にある必要があります。 詳細については、「 Dynamic-Link ライブラリ」を参照してください。
注
グローバル フックは、デバッグ目的でのみ使用する必要があります。それ以外の場合は、それらを避ける必要があります。 グローバル フックはシステムのパフォーマンスを低下させ、同じ種類のグローバル フックを実装する他のアプリケーションとの競合を引き起こします。
フックの種類
フックの種類ごとに、アプリケーションはシステムのメッセージ処理メカニズムのさまざまな側面を監視できます。 次のセクションでは、使用可能なフックについて説明します。
- WH_CALLWNDPROC and 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 and WH_SYSMSGFILTER
- WH_SHELL
WH_CALLWNDPROC and WH_CALLWNDPROCRET
WH_CALLWNDPROCとWH_CALLWNDPROCRETフックを使用すると、ウィンドウ プロシージャに送信されたメッセージを監視できます。 システムは、メッセージを受信ウィンドウ・プロシージャーに渡す前に WH_CALLWNDPROC ・フック・プロシージャーを呼び出し、ウィンドウ・プロシージャーがメッセージを処理した後に WH_CALLWNDPROCRET ・フック・プロシージャーを呼び出します。
WH_CALLWNDPROCRETフックは、CWPRETSTRUCT 構造体へのポインターをフック プロシージャに渡します。 構造体には、メッセージを処理したウィンドウ プロシージャからの戻り値と、メッセージに関連付けられているメッセージ パラメーターが含まれています。 ウィンドウのサブクラス化は、プロセス間で設定されたメッセージでは機能しません。
詳細については、 CallWndProc および CallWndRetProc コールバック関数を参照してください。
WH_CBT
システムは、ウィンドウをアクティブ化、作成、破棄、最小化、最大化、移動、またはサイズ変更する前に、 WH_CBT フックプロシージャを呼び出します。システムコマンドを完了する前に;システム メッセージ キューからマウスまたはキーボード イベントを削除する前。入力フォーカスを設定する前に;またはシステム メッセージ キューと同期する前に行います。 フック・プロシージャーが戻す値は、システムがこれらの操作の 1 つを許可または禁止するかどうかを決定します。 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
Warnung
Journaling Hooks API は、Windows 11 以降ではサポートされておらず、今後のリリースで削除される予定です。 このため、代わりに、SendInput TextInput API を呼び出すように強くお勧めします。
WH_JOURNALPLAYBACK フックを使用すると、アプリケーションはシステム メッセージ キューにメッセージを挿入できます。 このフックを使用すると、WH_JOURNALRECORD を使用して、前に記録した一連のマウス イベントとキーボード イベントを再生できます。 WH_JOURNALPLAYBACKフックがインストールされている限り、通常のマウスとキーボードの入力は無効になります。 WH_JOURNALPLAYBACK フックはグローバル フックであり、スレッド固有のフックとして使用することはできません。
WH_JOURNALPLAYBACK フックはタイムアウト値を返します。 この値は、再生フックから現在のメッセージを処理するまでに待機するミリ秒数をシステムに通知します。 これにより、フックは再生されるイベントのタイミングを制御できます。
詳細については、 JournalPlaybackProc コールバック関数を参照してください。
WH_JOURNALRECORD
Warnung
Journaling Hooks 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 and 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 メッセージを受信しないことに注意してください。 そのため、既定のシェルとして自身を登録するすべてのアプリケーションは、WH_SHELLメッセージを受信する前に SystemParametersInfo 関数を呼び出す必要があります。 この関数は、 SPI_SETMINIMIZEDMETRICS と MINIMIZEDMETRICS 構造体を使用して呼び出す必要があります。 この構造体の iArrange メンバーをARW_HIDEに設定 します。
詳細については、 ShellProc コールバック関数を参照してください。