フックの使用
次のコード例は、フックに関連付けられている次のタスクを実行する方法を示しています。
フックプロシージャのインストールと解放
フック プロシージャをインストールするには、 SetWindowsHookEx 関数を呼び出し、プロシージャを呼び出すフックの種類、プロシージャを呼び出し元のスレッドと同じデスクトップ内のすべてのスレッドに関連付ける必要があるかどうか、または特定のスレッドに関連付ける必要があるかどうか、およびプロシージャ エントリ ポイントへのポインターを指定します。
フック プロシージャをインストールするアプリケーションとは別の DLL にグローバル フック プロシージャを配置する必要があります。 インストールするアプリケーションは、フック プロシージャをインストールする前に、DLL モジュールへのハンドルを持っている必要があります。 DLL モジュールのハンドルを取得するには、DLL の名前を指定して LoadLibrary 関数を呼び出します。 ハンドルを取得したら、 GetProcAddress 関数を呼び出して、フック プロシージャへのポインターを取得できます。 最後に、 SetWindowsHookEx を使用して、適切なフック チェーンにフック プロシージャ アドレスをインストールします。 SetWindowsHookEx は 、モジュール ハンドル、フック プロシージャ エントリ ポイントへのポインター、およびスレッド識別子の 0 を渡します。これは、呼び出し元のスレッドと同じデスクトップ内のすべてのスレッドにフック プロシージャを関連付ける必要があることを示します。 このシーケンスを次の例に示します。
HOOKPROC hkprcSysMsg;
static HINSTANCE hinstDLL;
static HHOOK hhookSysMsg;
hinstDLL = LoadLibrary(TEXT("c:\\myapp\\sysmsg.dll"));
hkprcSysMsg = (HOOKPROC)GetProcAddress(hinstDLL, "SysMessageProc");
hhookSysMsg = SetWindowsHookEx(
WH_SYSMSGFILTER,
hkprcSysMsg,
hinstDLL,
0);
UnhookWindowsHookEx 関数を呼び出し、解放するフック プロシージャへのハンドルを指定することで、スレッド固有のフック プロシージャを解放できます (フック チェーンからアドレスを削除します)。 アプリケーションで不要になったフック プロシージャをすぐに解放します。
UnhookWindowsHookEx を使用してグローバル フック プロシージャを解放できますが、この関数はフック プロシージャを含む DLL を解放しません。 これは、デスクトップ内のすべてのアプリケーションのプロセス コンテキストでグローバル フック プロシージャが呼び出され、それらのすべてのプロセスに対して LoadLibrary 関数が暗黙的に呼び出されるためです。 FreeLibrary 関数を別のプロセスに対して呼び出すことができないため、DLL を解放する方法はありません。 DLL に明示的にリンクされているすべてのプロセスが FreeLibrary を終了または呼び出し、フック プロシージャを呼び出したすべてのプロセスが DLL の外部で処理を再開した後、システムは最終的に DLL を解放します。
グローバル フック プロシージャをインストールする別の方法は、フック プロシージャと共に DLL にインストール関数を提供することです。 この方法では、インストールするアプリケーションは DLL モジュールへのハンドルを必要としません。 DLL とリンクすることで、アプリケーションはインストール関数にアクセスできるようになります。 インストール関数は、 SetWindowsHookEx の呼び出しで DLL モジュール ハンドルとその他の詳細を提供できます。 DLL には、グローバル フック プロシージャを解放する関数を含めることもできます。アプリケーションは、終了時にこのフック解放関数を呼び出すことができます。
システム イベントの監視
次の例では、さまざまなスレッド固有のフック プロシージャを使用して、スレッドに影響するイベントがないかシステムを監視します。 次の種類のフック プロシージャのイベントを処理する方法を示します。
- WH_CALLWNDPROC
- WH_CBT
- WH_DEBUG
- WH_GETMESSAGE
- WH_KEYBOARD
- WH_MOUSE
- WH_MSGFILTER
ユーザーは、メニューを使用してフック プロシージャをインストールおよび削除できます。 フック プロシージャがインストールされ、プロシージャによって監視されるイベントが発生すると、プロシージャはイベントに関する情報をアプリケーションのメイン ウィンドウのクライアント領域に書き込みます。
#include <windows.h>
#include <strsafe.h>
#include "app.h"
#pragma comment( lib, "user32.lib")
#pragma comment( lib, "gdi32.lib")
#define NUMHOOKS 7
// Global variables
typedef struct _MYHOOKDATA
{
int nType;
HOOKPROC hkprc;
HHOOK hhook;
} MYHOOKDATA;
MYHOOKDATA myhookdata[NUMHOOKS];
HWND gh_hwndMain;
// Hook procedures
LRESULT WINAPI CallWndProc(int, WPARAM, LPARAM);
LRESULT WINAPI CBTProc(int, WPARAM, LPARAM);
LRESULT WINAPI DebugProc(int, WPARAM, LPARAM);
LRESULT WINAPI GetMsgProc(int, WPARAM, LPARAM);
LRESULT WINAPI KeyboardProc(int, WPARAM, LPARAM);
LRESULT WINAPI MouseProc(int, WPARAM, LPARAM);
LRESULT WINAPI MessageProc(int, WPARAM, LPARAM);
void LookUpTheMessage(PMSG, LPTSTR);
LRESULT WINAPI MainWndProc(HWND hwndMain, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static BOOL afHooks[NUMHOOKS];
int index;
static HMENU hmenu;
gh_hwndMain = hwndMain;
switch (uMsg)
{
case WM_CREATE:
// Save the menu handle
hmenu = GetMenu(hwndMain);
// Initialize structures with hook data. The menu-item identifiers are
// defined as 0 through 6 in the header file app.h. They can be used to
// identify array elements both here and during the WM_COMMAND message.
myhookdata[IDM_CALLWNDPROC].nType = WH_CALLWNDPROC;
myhookdata[IDM_CALLWNDPROC].hkprc = CallWndProc;
myhookdata[IDM_CBT].nType = WH_CBT;
myhookdata[IDM_CBT].hkprc = CBTProc;
myhookdata[IDM_DEBUG].nType = WH_DEBUG;
myhookdata[IDM_DEBUG].hkprc = DebugProc;
myhookdata[IDM_GETMESSAGE].nType = WH_GETMESSAGE;
myhookdata[IDM_GETMESSAGE].hkprc = GetMsgProc;
myhookdata[IDM_KEYBOARD].nType = WH_KEYBOARD;
myhookdata[IDM_KEYBOARD].hkprc = KeyboardProc;
myhookdata[IDM_MOUSE].nType = WH_MOUSE;
myhookdata[IDM_MOUSE].hkprc = MouseProc;
myhookdata[IDM_MSGFILTER].nType = WH_MSGFILTER;
myhookdata[IDM_MSGFILTER].hkprc = MessageProc;
// Initialize all flags in the array to FALSE.
memset(afHooks, FALSE, sizeof(afHooks));
return 0;
case WM_COMMAND:
switch (LOWORD(wParam))
{
// The user selected a hook command from the menu.
case IDM_CALLWNDPROC:
case IDM_CBT:
case IDM_DEBUG:
case IDM_GETMESSAGE:
case IDM_KEYBOARD:
case IDM_MOUSE:
case IDM_MSGFILTER:
// Use the menu-item identifier as an index
// into the array of structures with hook data.
index = LOWORD(wParam);
// If the selected type of hook procedure isn't
// installed yet, install it and check the
// associated menu item.
if (!afHooks[index])
{
myhookdata[index].hhook = SetWindowsHookEx(
myhookdata[index].nType,
myhookdata[index].hkprc,
(HINSTANCE) NULL, GetCurrentThreadId());
CheckMenuItem(hmenu, index,
MF_BYCOMMAND | MF_CHECKED);
afHooks[index] = TRUE;
}
// If the selected type of hook procedure is
// already installed, remove it and remove the
// check mark from the associated menu item.
else
{
UnhookWindowsHookEx(myhookdata[index].hhook);
CheckMenuItem(hmenu, index,
MF_BYCOMMAND | MF_UNCHECKED);
afHooks[index] = FALSE;
}
default:
return (DefWindowProc(hwndMain, uMsg, wParam,
lParam));
}
break;
//
// Process other messages.
//
default:
return DefWindowProc(hwndMain, uMsg, wParam, lParam);
}
return NULL;
}
/****************************************************************
WH_CALLWNDPROC hook procedure
****************************************************************/
LRESULT WINAPI CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CHAR szCWPBuf[256];
CHAR szMsg[16];
HDC hdc;
static int c = 0;
size_t cch;
HRESULT hResult;
if (nCode < 0) // do not process message
return CallNextHookEx(myhookdata[IDM_CALLWNDPROC].hhook, nCode, wParam, lParam);
// Call an application-defined function that converts a message
// constant to a string and copies it to a buffer.
LookUpTheMessage((PMSG) lParam, szMsg);
hdc = GetDC(gh_hwndMain);
switch (nCode)
{
case HC_ACTION:
hResult = StringCchPrintf(szCWPBuf, 256/sizeof(TCHAR),
"CALLWNDPROC - tsk: %ld, msg: %s, %d times ",
wParam, szMsg, c++);
if (FAILED(hResult))
{
// TODO: writer error handler
}
hResult = StringCchLength(szCWPBuf, 256/sizeof(TCHAR), &cch);
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 2, 15, szCWPBuf, cch);
break;
default:
break;
}
ReleaseDC(gh_hwndMain, hdc);
return CallNextHookEx(myhookdata[IDM_CALLWNDPROC].hhook, nCode, wParam, lParam);
}
/****************************************************************
WH_GETMESSAGE hook procedure
****************************************************************/
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CHAR szMSGBuf[256];
CHAR szRem[16];
CHAR szMsg[16];
HDC hdc;
static int c = 0;
size_t cch;
HRESULT hResult;
if (nCode < 0) // do not process message
return CallNextHookEx(myhookdata[IDM_GETMESSAGE].hhook, nCode,
wParam, lParam);
switch (nCode)
{
case HC_ACTION:
switch (wParam)
{
case PM_REMOVE:
hResult = StringCchCopy(szRem, 16/sizeof(TCHAR), "PM_REMOVE");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case PM_NOREMOVE:
hResult = StringCchCopy(szRem, 16/sizeof(TCHAR), "PM_NOREMOVE");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
default:
hResult = StringCchCopy(szRem, 16/sizeof(TCHAR), "Unknown");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
}
// Call an application-defined function that converts a
// message constant to a string and copies it to a
// buffer.
LookUpTheMessage((PMSG) lParam, szMsg);
hdc = GetDC(gh_hwndMain);
hResult = StringCchPrintf(szMSGBuf, 256/sizeof(TCHAR),
"GETMESSAGE - wParam: %s, msg: %s, %d times ",
szRem, szMsg, c++);
if (FAILED(hResult))
{
// TODO: write error handler
}
hResult = StringCchLength(szMSGBuf, 256/sizeof(TCHAR), &cch);
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 2, 35, szMSGBuf, cch);
break;
default:
break;
}
ReleaseDC(gh_hwndMain, hdc);
return CallNextHookEx(myhookdata[IDM_GETMESSAGE].hhook, nCode, wParam, lParam);
}
/****************************************************************
WH_DEBUG hook procedure
****************************************************************/
LRESULT CALLBACK DebugProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CHAR szBuf[128];
HDC hdc;
static int c = 0;
size_t cch;
HRESULT hResult;
if (nCode < 0) // do not process message
return CallNextHookEx(myhookdata[IDM_DEBUG].hhook, nCode,
wParam, lParam);
hdc = GetDC(gh_hwndMain);
switch (nCode)
{
case HC_ACTION:
hResult = StringCchPrintf(szBuf, 128/sizeof(TCHAR),
"DEBUG - nCode: %d, tsk: %ld, %d times ",
nCode,wParam, c++);
if (FAILED(hResult))
{
// TODO: write error handler
}
hResult = StringCchLength(szBuf, 128/sizeof(TCHAR), &cch);
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 2, 55, szBuf, cch);
break;
default:
break;
}
ReleaseDC(gh_hwndMain, hdc);
return CallNextHookEx(myhookdata[IDM_DEBUG].hhook, nCode, wParam, lParam);
}
/****************************************************************
WH_CBT hook procedure
****************************************************************/
LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CHAR szBuf[128];
CHAR szCode[128];
HDC hdc;
static int c = 0;
size_t cch;
HRESULT hResult;
if (nCode < 0) // do not process message
return CallNextHookEx(myhookdata[IDM_CBT].hhook, nCode, wParam,
lParam);
hdc = GetDC(gh_hwndMain);
switch (nCode)
{
case HCBT_ACTIVATE:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_ACTIVATE");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case HCBT_CLICKSKIPPED:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_CLICKSKIPPED");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case HCBT_CREATEWND:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_CREATEWND");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case HCBT_DESTROYWND:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_DESTROYWND");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case HCBT_KEYSKIPPED:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_KEYSKIPPED");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case HCBT_MINMAX:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_MINMAX");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case HCBT_MOVESIZE:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_MOVESIZE");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case HCBT_QS:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_QS");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case HCBT_SETFOCUS:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_SETFOCUS");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case HCBT_SYSCOMMAND:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_SYSCOMMAND");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
default:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "Unknown");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
}
hResult = StringCchPrintf(szBuf, 128/sizeof(TCHAR), "CBT - nCode: %s, tsk: %ld, %d times ",
szCode, wParam, c++);
if (FAILED(hResult))
{
// TODO: write error handler
}
hResult = StringCchLength(szBuf, 128/sizeof(TCHAR), &cch);
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 2, 75, szBuf, cch);
ReleaseDC(gh_hwndMain, hdc);
return CallNextHookEx(myhookdata[IDM_CBT].hhook, nCode, wParam, lParam);
}
/****************************************************************
WH_MOUSE hook procedure
****************************************************************/
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CHAR szBuf[128];
CHAR szMsg[16];
HDC hdc;
static int c = 0;
size_t cch;
HRESULT hResult;
if (nCode < 0) // do not process the message
return CallNextHookEx(myhookdata[IDM_MOUSE].hhook, nCode,
wParam, lParam);
// Call an application-defined function that converts a message
// constant to a string and copies it to a buffer.
LookUpTheMessage((PMSG) lParam, szMsg);
hdc = GetDC(gh_hwndMain);
hResult = StringCchPrintf(szBuf, 128/sizeof(TCHAR),
"MOUSE - nCode: %d, msg: %s, x: %d, y: %d, %d times ",
nCode, szMsg, LOWORD(lParam), HIWORD(lParam), c++);
if (FAILED(hResult))
{
// TODO: write error handler
}
hResult = StringCchLength(szBuf, 128/sizeof(TCHAR), &cch);
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 2, 95, szBuf, cch);
ReleaseDC(gh_hwndMain, hdc);
return CallNextHookEx(myhookdata[IDM_MOUSE].hhook, nCode, wParam, lParam);
}
/****************************************************************
WH_KEYBOARD hook procedure
****************************************************************/
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CHAR szBuf[128];
HDC hdc;
static int c = 0;
size_t cch;
HRESULT hResult;
if (nCode < 0) // do not process message
return CallNextHookEx(myhookdata[IDM_KEYBOARD].hhook, nCode,
wParam, lParam);
hdc = GetDC(gh_hwndMain);
hResult = StringCchPrintf(szBuf, 128/sizeof(TCHAR), "KEYBOARD - nCode: %d, vk: %d, %d times ", nCode, wParam, c++);
if (FAILED(hResult))
{
// TODO: write error handler
}
hResult = StringCchLength(szBuf, 128/sizeof(TCHAR), &cch);
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 2, 115, szBuf, cch);
ReleaseDC(gh_hwndMain, hdc);
return CallNextHookEx(myhookdata[IDM_KEYBOARD].hhook, nCode, wParam, lParam);
}
/****************************************************************
WH_MSGFILTER hook procedure
****************************************************************/
LRESULT CALLBACK MessageProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CHAR szBuf[128];
CHAR szMsg[16];
CHAR szCode[32];
HDC hdc;
static int c = 0;
size_t cch;
HRESULT hResult;
if (nCode < 0) // do not process message
return CallNextHookEx(myhookdata[IDM_MSGFILTER].hhook, nCode,
wParam, lParam);
switch (nCode)
{
case MSGF_DIALOGBOX:
hResult = StringCchCopy(szCode, 32/sizeof(TCHAR), "MSGF_DIALOGBOX");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case MSGF_MENU:
hResult = StringCchCopy(szCode, 32/sizeof(TCHAR), "MSGF_MENU");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case MSGF_SCROLLBAR:
hResult = StringCchCopy(szCode, 32/sizeof(TCHAR), "MSGF_SCROLLBAR");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
default:
hResult = StringCchPrintf(szCode, 128/sizeof(TCHAR), "Unknown: %d", nCode);
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
}
// Call an application-defined function that converts a message
// constant to a string and copies it to a buffer.
LookUpTheMessage((PMSG) lParam, szMsg);
hdc = GetDC(gh_hwndMain);
hResult = StringCchPrintf(szBuf, 128/sizeof(TCHAR),
"MSGFILTER nCode: %s, msg: %s, %d times ",
szCode, szMsg, c++);
if (FAILED(hResult))
{
// TODO: write error handler
}
hResult = StringCchLength(szBuf, 128/sizeof(TCHAR), &cch);
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 2, 135, szBuf, cch);
ReleaseDC(gh_hwndMain, hdc);
return CallNextHookEx(myhookdata[IDM_MSGFILTER].hhook, nCode, wParam, lParam);
}