天天看點

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,, , );     
    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 ;
}
           

繼續閱讀