Windows Hook經驗總結之三:Mouse Hook實踐

前面已經寫過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,0, 0, 0);     
    pSharedMem->HookActived = FALSE;
    pSharedMem->MouseDown   = FALSE;
    memcpy(pSharedMem, pAppSharedMem, sizeof(HOOK_SHARED_MEM));

    /*安裝鉤子函數*/
    return SetWindowsHookEx(WH_MOUSE, HookMouseProc, hInstance, 0);
    /*用完卸載鉤子則需調用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,0, 0, 0);
            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(), 0);
                        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 = 0;                   
    CreateThread(NULL, 0, HookMonitorThread, m_hAppWnd, 0, &dwThreadId);        

    return TRUE;    
}

/*監控線程函數*/
DWORD   WINAPI  HookMonitorThread(LPVOID lpParam)
{   
    Sleep(500);
    /*隱藏V2*/
    ShowWindow((HWND)lpParam, SW_HIDE);

    HOOK_SHARED_MEM hMem;

    while(1)
    {
        Sleep(50);

        /*獲取共享內存中的HOOK_SHARED_MEM接口*/

        /*是否激活*/
        if (!hMem->HookActived)
        {
            /*檢查V1進程是否存在*/

            /*不存在,則關閉hook終止V2*/         
            TerminateProcess(GetCurrentProcess(), 0);
        }
        else
        {
            /*顯示V2並激活V2de文件選擇對話框*/
            ShowWindow((HWND)lpParam, SW_SHOW);
            PostMessage((HWND)lpParam, WM_FILE_OPEN, 0, 0);
            break;
        }
    }

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章