把鼠標關標滑過一個窗口時該窗口的有關消息將顯示在主窗口中當您按下Unhook時應用程序將卸載鉤子主窗口使用一個對話框來作為它的主窗口它自定義了一個消息WM_MOUSEHOOK用來在主窗口和DLL之間傳遞消息當主窗口接收到該消息時wParam中包含了光標所在位置的窗口的句柄當然這是我們做的安排我這麼做只是為了方便您可以使用您自己的方法在主應用程序和DLL之間進行通訊
if HookFlag==FALSE
invoke InstallHookhDlg
if eax!=NULL
mov HookFlagTRUE
invoke SetDlgItemTexthDlgIDC_HOOKaddr UnhookText
endif
該應用程序有一個全局變量HookFlag它用來監視鉤子的狀態如果安裝來鉤子它就是TRUE否則是FALSE當用戶按下Hook按鈕時應用程序檢查鉤子是否已經安裝如果還沒有的話它將調用DLL中引出的函數InstallHook來安裝它注意我們把主對話框的句柄傳遞給了DLL這樣這個鉤子DLL就可以把WM_MOUSEHOOK消息傳遞給正確的窗口了當應用程序加載時鉤子DLL也同時加載時機上當主程序一旦加載到內存中後DLL就立即加載DLL的入口點函數載主程序的第一條語句執行前就前執行了所以當主程序執行時DLL已經初始化好了我們載入口點處放入如下代碼
if reason==DLL_PROCESS_ATTACH
push hInst
pop hInstance
endif
該段代碼把DLL自己的實例句柄放到一個全局變量中保存由於入口點函數是在所有函數調用前被執行的所以hInstance總是有效的我們把該變量放到data中使得每一個進程都有自己一個該變量的值因為當鼠標光標停在一個窗口上時鉤子DLL被映射進進程的地址空間加入在DLL缺省加載的地址處已經加載其它的DLL那鉤子DLL將要被映射到其他的地址hInstance將被更新成其它的值當用戶按下Unhook再按下Hook時SetWindowsHookEx將被再次調用這一次它將把新的地址作為實例句柄而在例子中這是錯誤的DLL裝載的地址並沒有變這個鉤子將變成一個局部的您只能鉤掛發生在您窗口中的鼠標事件這是很難讓人滿意的
InstallHook proc hwndDWORD
push hwnd
pop hWnd
invoke SetWindowsHookExWH_MOUSEaddr MouseProchInstanceNULL
mov hHookeax
ret
InstallHook endp
InstallHook 函數非常簡單它把傳遞過來的窗口句柄保存在hWnd中以備後用接著調用SetWindowsHookEx函數來安裝一個鼠標鉤子該函數的返回值放在全局變量hHook中將來在UnhookWindowsHookEx中還要使用在調用SetWindowsHookEx後鼠標鉤子就開始工作了無論什麼時候發生了鼠標事件MouseProc函數都將被調用
MouseProc proc nCodeDWORDwParamDWORDlParamDWORD
invoke CallNextHookExhHooknCodewParamlParam
mov edxlParam
assume edxPTR MOUSEHOOKSTRUCT
invoke WindowFromPoint[edx]ptx[edx]pty
invoke PostMessagehWndWM_MOUSEHOOKeax
assume edxnothing
xor eaxeax
ret
MouseProc endp
鉤子函數首先調用CallNextHookEx函數讓其它的鉤子處理該鼠標事件然後調用WindowFromPoint函數來得到給定屏幕坐標位置處的窗口句柄注意我們用lParam指向的MOUSEHOOKSTRUCT型結構體變量中的POINT成員變量作為當前的鼠標位置在我們調用PostMessage函數把WM_MOUSEHOOK消息發送到主程序您必須記住的一件事是在鉤子函數中不要使用SendMessage函數它會引起死鎖MOUSEHOOKSTRUCT的定義如下
MOUSEHOOKSTRUCT STRUCT DWORD
pt POINT <>
hwnd DWORD ?
wHitTestCode DWORD ?
dwExtraInfo DWORD ?
MOUSEHOOKSTRUCT ENDS
pt 是當前鼠標所在的屏幕位置
hwnd 是將接收鼠標消息的窗口的句柄通常它是鼠標所在處的窗口但是如果窗口調用了SetCapture鼠標的輸入將到向到這個窗口因我們不用該成員變量而是用WindowFromPoint函數
wHitTestCode 指定hittest值該值給出了更多的鼠標位置值它指定了鼠標在窗口的那個部位該值的完全列表請參考WIN API 指南中的WM_NCHITTEST消息
dwExtraInfo 該值包含了相關的信息一般該值由mouse_event函數設定可以調用GetMessageExtraInfo來獲得
當主窗口接收到WM_MOUSEHOOK 消息時它用wParam參數中的窗口句柄來查詢窗口的消息
elseif uMsg==WM_MOUSEHOOK
invoke GetDlgItemTexthDlgIDC_HANDLEaddr buffer
invoke wsprintfaddr bufferaddr templatewParam
invoke lstrcmpiaddr bufferaddr buffer
if eax!=
invoke SetDlgItemTexthDlgIDC_HANDLEaddr buffer
endif
invoke GetDlgItemTexthDlgIDC_CLASSNAMEaddr buffer
invoke GetClassNamewParamaddr buffer
invoke lstrcmpiaddr bufferaddr buffer
if eax!=
invoke SetDlgItemTexthDlgIDC_CLASSNAMEaddr buffer
endif
invoke GetDlgItemTexthDlgIDC_WNDPROCaddr buffer
invoke GetClassLongwParamGCL_WNDPROC
invoke wsprintfaddr bufferaddr templateeax
invoke lstrcmpiaddr bufferaddr buffer
if eax!=
invoke SetDlgItemTexthDlgIDC_WNDPROCaddr buffer
endif
為了避免重繪文本時的抖動我們把已經在編輯空間中線時的文本和我們將要顯示的對比如果相同就可以忽略掉得到類名調用GetClassName得到窗口過程調用GetClassLong並傳入GCL_WNDPROC標志然後把它們格式化成文本串並放到相關的編輯空間中去
invoke UninstallHook
invoke SetDlgItemTexthDlgIDC_HOOKaddr HookText
mov HookFlagFALSE
invoke SetDlgItemTexthDlgIDC_CLASSNAMENULL
invoke SetDlgItemTexthDlgIDC_HANDLENULL
invoke SetDlgItemTexthDlgIDC_WNDPROCNULL
當用戶按下Unhook後主程序調用DLL中的UninstallHook函數該函數調用UnhookWindowsHookEx函數然後它把按鈕的文本換回HookHookFlag的值設成FALSE再清除掉編輯控件中的文本
鏈接器的開關選項如下
Link /SECTIONbssS /DLL /DEF$(NAME)def /SUBSYSTEMWINDOWS
它指定bss段作為一個共享段以便所有映射該DLL的進程共享未初始化的數據段如果不用該開關您DLL中的鉤子就不能正常工作了
From:http://tw.wingwit.com/Article/Common/201311/4835.html