熱點推薦:
您现在的位置: 電腦知識網 >> 電腦常識 >> 正文

編程基礎之WINDOWS鉤子函數

2013-11-11 13:56:21  來源: 電腦常識 

  把鼠標關標滑過一個窗口時該窗口的有關消息將顯示在主窗口中當您按下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
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.