マウスのグローバルフックを試してみる
今回もVC6.0で、DLLを作成
呼び出し側のアプリは全く同じものなので省略で。
キーボードのフックとほとんど同じかと。
※追記:C++ Builder版のDLL側を改めて作成しました。詳しくはこちらで。
※フック関数や、用語についてはこちらにまとめてます。
※CallNextHookExの第1引数はNULLでも問題ないです
・[新規作成] → [プロジェクト]タブ → Win32 Dynamic-Link Library を選んで
プロジェクト名 "MouseHook"で作成してから...
<DLL側 MouseHook.cpp>
//---------------------------------------------------------------------------
#include "stdafx.h"
#define DLLEXPORT extern "C" __declspec(dllexport)
// 宣言
// フック開始用
DLLEXPORT void HookStart(void);
// フック停止用
DLLEXPORT void HookStop(void);
// フック処理用 DLLにする事によってグローバルフックが出来るようになります
DLLEXPORT LRESULT CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam);
//---------------------------------------------------------------------------
// 必ず初期化しないと動いてくれない
#pragma data_seg(".shared")
HHOOK g_hHook = NULL; // フックハンドル
#pragma data_seg()
#pragma comment(linker, "/section:.shared,rws")
HINSTANCE g_hInst;
//---------------------------------------------------------------------------
// DLLエントリポイント
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
if ( ul_reason_for_call == DLL_PROCESS_ATTACH ){
g_hInst = (HINSTANCE)hModule; // DLLモジュールのハンドル取得
}
return TRUE;
}
//---------------------------------------------------------------------------
// フック開始
DLLEXPORT void HookStart()
{
g_hHook = SetWindowsHookEx(WH_MOUSE, (HOOKPROC)MouseProc, g_hInst, 0);
if ( g_hHook == NULL ){
MessageBox(NULL, "フック開始は失敗しました", "HookStart", MB_OK);
return;
}
MessageBox(NULL, "フック開始は成功しました", "HookStart", MB_OK);
}
//---------------------------------------------------------------------------
// フック処理
DLLEXPORT LRESULT CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam)
{
char sMsg[100]; // メッセージ表示用
// この構造体から位置,ハンドル,ヒットテストコード,追加情報を取得出来ます
MOUSEHOOKSTRUCT *mmsg;
// lParamをMOUSEHOOKSTRUCT型でキャストし
// 構造体のメンバを指定出来るようにします
mmsg = (MOUSEHOOKSTRUCT *)lParam;
if ( code < 0 ){
return CallNextHookEx(g_hHook, code, wParam, lParam);
}
// 今回は右クリックと位置を確認します
if ( wParam == WM_RBUTTONDOWN ){
wsprintf(sMsg,
"位置 X : %d, Y : %d で\r\n右クリックされました!"
, mmsg->pt.x, mmsg->pt.y);
MessageBox(mmsg->hwnd, sMsg, "MouseProc", MB_OK);
}
// 最大化ボタン上かどうかも確認してみます
// マウスカーソルを最大化ボタン上に持っていくとメッセージが表示されます
if ( mmsg->wHitTestCode == HTMAXBUTTON ){
MessageBox(mmsg->hwnd, "最大化ボタン!", "MouseProc", MB_OK);
}
// 最後は次のフックへ渡します
return CallNextHookEx(g_hHook, code, wParam, lParam);
}
//---------------------------------------------------------------------------
// フック停止
DLLEXPORT void HookStop(void)
{
BOOL bResult;
if ( g_hHook == NULL ) return;
bResult = UnhookWindowsHookEx(g_hHook);
if ( bResult == 0 ){
MessageBox(NULL, "フック解除は失敗しました", "HookStop", MB_OK);
return;
}
MessageBox(NULL, "フック解除は成功しました", "HookStop", MB_OK);
}
//---------------------------------------------------------------------------
と、まぁどうすかね。
SetWindowsHookExの第1引数をWH_MOUSEに変更してある点、
MOUSEHOOKSTRUCT型による、マウス座標やヒットテストコードの取得
この辺りが、キーボードフックと異なる点です。
ここでひとつ。
MessageBoxで確認をしていますが、コードの書き方がマズイと
大量のMessageBoxが出現し、どうにもならなくなってしまう場合がありますので
その辺、上手くやるなりなんなりで注意してください。
・参考
typedef struct tagMOUSEHOOKSTRUCT {
POINT pt; // pt.x pt.y マウスのスクリーン座標
HWND hwnd; // メッセージを受け取ったウィンドウのハンドル
UINT wHitTestCode; // ヒットテストコード
DWORD dwExtraInfo; // 追加情報
} MOUSEHOOKSTRUCT;
ヒットテストコードにはマウスカーソルがどの位置にあるのか等の
情報が入ります。(タイトルバー、クライアント領域、閉じるボタン上など)
MSDN「WM_NCHITTES」にて説明があります。