前面已經寫過API注入的Hook應用場景,本文則展示Hook的另一個應用場景:監控mouse事件(包括keyboard等輸入事件)。
問題背景:
一個工具多個版本(比如V1,V2)根據輸入檔案動态切換,要求V1能切到V2,V2也能切回V1。
但切換控制代碼隻能在最新版(比如V2)上添加,V1已釋出且穩定不能做更改。
解決思路:
V2上響應輸入button事件時判斷是否需要切到V1;
如果不切,則顯示V2主界面;
如果要切,則隐藏V2界面、建立V1程序、安裝WH_MOUSE鈎子,并建立線程監控V1的運作狀況(主要是mouse輸入事件);
Mouse鈎子運作後檢查V1中滑鼠輸入條件是否觸發檔案選擇button,如果觸發則終止V1并激活顯示V2(結束mouse hook);
同時,V1激活時使用者如果關閉V1,則必須hook到此事件并關閉V2(即退出工具)
具體實作:
直接上代碼Hook.dll
/*自定義結構,V2與V1的資料交換*/
typedef struct
{
DWORD HookPID;/*V1程序pid*/
BOOL HookActived;/*hook是否有效*/
BOOL MouseDown;/*mouse是否被按下*/
RECT Client; /*V1待hook的button坐标區域*/
}HOOK_SHARED_MEM;
/*安裝鈎子*/
HOOK WINAPI InstallHook(int nID, HINSTANCE hInstance, LPVOID pAppSharedMem)
{
HANDLE hMemMap = ::OpenFileMapping( FILE_MAP_WRITE, false, HOOK_MEM_SHARE);
HOOK_SHARED_MEM* pSharedMem = (HOOK_SHARED_MEM*)MapViewOfFile(hMemMap, FILE_MAP_WRITE,, , );
pSharedMem->HookActived = FALSE;
pSharedMem->MouseDown = FALSE;
memcpy(pSharedMem, pAppSharedMem, sizeof(HOOK_SHARED_MEM));
/*安裝鈎子函數*/
return SetWindowsHookEx(WH_MOUSE, HookMouseProc, hInstance, );
/*用完解除安裝鈎子則需調用UnhookWindowsHookEx*/
}
/*具體的mouse hook響應處理函數,重點*/
LRESULT WINAPI HookMouseProc(int code, WPARAM wParam, LPARAM lParam)
{
if (wParam == WM_LBUTTONDOWN || wParam == WM_LBUTTONUP || wParam == WM_LBUTTONDBLCLK)
{
HANDLE hMemMap = ::OpenFileMapping( FILE_MAP_WRITE, false, HOOK_MEM_SHARE);
if (hMemMap)
{
HOOK_SHARED_MEM* pSharedMem = (HOOK_SHARED_MEM*)MapViewOfFile(hMemMap, FILE_MAP_WRITE,, , );
if (pSharedMem->HookPID == GetCurrentProcessId())
{
PMOUSEHOOKSTRUCT p = (PMOUSEHOOKSTRUCT)lParam;
POINT pt = p->pt;
::ScreenToClient(p->hwnd, &pt);
if (PtInRect(&pSharedMem->Client, pt))
{
if (wParam == WM_LBUTTONDOWN)
{
pSharedMem->MouseDown = TRUE;
}
else if ((wParam == WM_LBUTTONUP && pSharedMem->MouseDown)
|| wParam == WM_LBUTTONDBLCLK)
{
/*單擊或輕按兩下觸發檔案選擇,結束V1回到V2進行判斷*/
pSharedMem->HookActived = TRUE;
TerminateProcess(GetCurrentProcess(), );
return TRUE;
}
}
}
}
}
return(CallNextHookEx(GetHook(WH_MOUSE), code, wParam, lParam));
}
主程式,調用hook.dll
BOOL DoSwitchV1
{
/*建立共享記憶體寫入HOOK_SHARED_MEM結構*/
/*建立V1程序并執行,隐藏V2界面*/
/*Load Hook.dll并執行InstallHook接口 */
/*建立監控線程*/
DWORD dwThreadId = ;
CreateThread(NULL, , HookMonitorThread, m_hAppWnd, , &dwThreadId);
return TRUE;
}
/*監控線程函數*/
DWORD WINAPI HookMonitorThread(LPVOID lpParam)
{
Sleep();
/*隐藏V2*/
ShowWindow((HWND)lpParam, SW_HIDE);
HOOK_SHARED_MEM hMem;
while()
{
Sleep();
/*擷取共享記憶體中的HOOK_SHARED_MEM接口*/
/*是否激活*/
if (!hMem->HookActived)
{
/*檢查V1程序是否存在*/
/*不存在,則關閉hook終止V2*/
TerminateProcess(GetCurrentProcess(), );
}
else
{
/*顯示V2并激活V2de檔案選擇對話框*/
ShowWindow((HWND)lpParam, SW_SHOW);
PostMessage((HWND)lpParam, WM_FILE_OPEN, , );
break;
}
}
return ;
}