VB.net中HOOK的應用(二) (轉)

worldblog發表於2007-12-15
VB.net中HOOK的應用(二) (轉)[@more@]

中HOOK的應用(二)

 

二、那麼,在vb.net中對的和Hook的實現上作了什麼樣的變化呢?

我們對應著一個問題一個問題來看:

1.  新建一個module,先寫一下API的宣告:

  Declare Function SetHookEx Lib "user32" Alias  "SetWindowsHookExA" (ByVal idHook As HookType, ByVal lpfn As HOOKPROC,  ByVal hmod As Integer, ByVal dwThreadId As Integer) As Integer:namespace prefix = o ns = "urn:schemas--com::office" />

  Declare Function UnhookWindowsHookEx Lib "user32"  (ByVal hHook As Integer) As Integer

  Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Integer,  ByVal ncode As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

和上面vb6裡的宣告比一下,你發現了什麼?是不是資料型別發生了變化?integer代替了long。這個好理解,因為vb.net中integer定義為32位(4位元組)的整數,值的範圍是-231到231(首位是符號位),這與中long的定義是一致的,因此,我們必須做一下這樣的轉換。

等等,還有一個變化,就是SetWindowsHookEx的引數lpfn的型別變成了HOOKPROC,那……那是什麼意思。噢,wait,我再補一句宣告先:

Public Delegate Function HOOKPROC(ByVal nCode As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

看出來什麼了嗎?HOOKPROC其實就是一個宣告,但是前面有一個Delegate(委託)是什麼意思?為什麼在vb.net中不能用integer表示lpfn的型別了呢?我們回頭看一下vb6中呼叫API的句子:

hnextHookproc = SetWindowsHookEx(WH_KEYBOARD, AddressOf _

   MyKBHFunc, App.hInstance, 0)

Lpfn在這裡被表示為AddressOf  MyKBHFunc,即說明Hook發生作用時,呼叫的子程是MyKBHFunc。也就是說lpfn表示的是函式或過程的地址。在vb6中用long型別就可以記錄下函式或過程的地址。

在vb.net中,有了一點小變化嘍,AddressOf 運算子建立的是一個指向指定的子程的子程委託。當指定的子程是一個例項方法時,子程委託同時引用例項和方法,以便當呼叫該子程委託時,呼叫指定例項的指定方法。AddressOf 運算子可以用作委託建構函式的運算元,或可以用在能夠確定委託型別的上下文中。

所以,正是由於Addressof建立的不再只是簡單的函式指標了,而是子程委託!打住先,什麼是委託?(^?^)

解釋一下:事件是傳送的訊息,以發訊號通知操作的發生。操作可能是由互動(例如滑鼠單擊)引起的,也可能是由某些其他的邏輯觸發的。引發(觸發)事件的物件叫做事件傳送方。捕獲事件並對其作出響應的物件叫做事件接收方。在事件通訊中,事件傳送方類不知道哪個物件或方法將接收到(處理)它引發的事件。所需要的是在源和接收方之間存在一個媒介(或類似指標的機制)。.NET 定義了一個特殊的型別(Delegate),該型別提供函式指標的功能。看,這裡提到了.net框架,所以等vs.net中的語言都可以有這個型別嘍。

委託就是可用於呼叫其他物件方法的物件。與其他的類不同,委託類具有一個簽名,並且它只能對與其簽名匹配的方法進行引用。這樣,委託就等效於一個型別函式指標或一個回撥。因為它們與其他語言中所使用的函式指標相似。但不同於函式指標,.NET 委託是基於 System.Delegate 類的引用型別,它可以引用共享方法—無需特定即可呼叫的方法—和例項方法。(具體內容請自已去查閱一下MSDN或等我的後續文章再說明)

回過頭來總結一下,也就是說,Addressof建立的是DelegateType(委託型別)。而不是簡單的子程指標了,所以它的表示法就不是地址型別的long了,而是與呼叫的子程相一致的委託型別表示形式。因此,我定義了一個與MyKBHFunc宣告同形的委託函式HOOKPROC來表示lpfn的型別。

(呼,一頭汗,還不知道說清楚了沒有。希望是說清楚了……)

繼續,我又接著宣告瞭一個API:

Declare Function GetCurrentThreadId Lib "kernel32" Alias "GetCurrentThreadId" () As Integer

函式說明:本函式是用於獲取當前執行緒一個唯一的執行緒識別符號。返回值:當前的執行緒識別符號。這個有什麼用,一會再說,反正是個簡單的問題,不如賣個關子,哈哈……(不要砸我)

2. 定義的常量是:

Public hnextHookproc As Long

Public Const WH_KEYBOARD = 2 ‘這個是表明Hook的種類是鍵盤Hook

Public Const PM_KEY_SPACE = &H20 ‘空格鍵

或者,實際上也是,我在程式中對上面的第二句寫法改變了一下,也沒什麼了,就是多交待一點東西給朋友們嘛:

Public Enum HookType

    WH_KEYBOARD = 2

  End Enum

定義成了一個列舉。其實Hook的種類真的很多,比如有:WH_CALLWNDPROC、WH_CALLWNDPROCRET、WH_C、WH_DE、WH_GETMESSAGE等等。所以你不妨寫一個列舉,以達到一勞永逸的目的。

3.  程式碼段

Module Module1

  Public frm1 As New Form1() ‘這個的作用,最後再說

  Declare Function GetCurrentThreadId Lib "kernel32" Alias "GetCurrentThreadId" () As Integer

  Declare Function SetWindowsHookEx Lib "user32" Alias _

  "SetWindowsHookExA" (ByVal idHook As Integer, ByVal lpfn As HOOKPROC, _

  ByVal hmod As Integer, ByVal dwThreadId As Integer) As Integer

  Declare Function UnhookWindowsHookEx Lib "user32" _

  (ByVal hHook As Integer) As Integer

  Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Integer, _

  ByVal ncode As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

   Public Delegate Function HOOKPROC(ByVal nCode As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

  Public hnexthookproc As Integer

  Public Const PM_KEY_SPACE = &H20

Public Enum HookType

  WH_KEYBOARD = 2

End Enum

 

  Public Sub UnHook()  ‘解Hook

  If hnexthookproc <> 0 Then

  UnhookWindowsHookEx(hnexthookproc)

  hnexthookproc = 0

  End If

  End Sub

  Public Function SetHook()  ‘設定Hook

  If hnexthookproc <> 0 Then

  Exit Function

  End If

  hnexthookproc = SetWindowsHookEx(HookType.WH_KEYBOARD, AddressOf MyKeyboardProc, 0, GetCurrentThreadId())

  我把第三個引數設為0(即NULL),表示的是此Hook的程式碼在此程式中。第四個引數用了一個API去取Hook子程相關聯的執行緒的識別符號。(參見前面的API宣告)

  End Function

 

  Public Function MyKeyboardProc(ByVal nCode As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

  MyKeyboardProc = 0

  If nCode < 0 Then

  MyKeyboardProc = CallNextHookEx(hnexthookproc, nCode, wParam, lParam)

  Exit Function

  End If

  If wParam = PM_KEY_SPACE Then 

  MyKeyboardProc = 1

‘寫入你自己的程式碼

frm1.textbox1.text=”HOOK成功!”

  End If

  End Function

  Sub main()

  Application.Run(frm1)

  End Sub

End Module

同時請在:

解決方案管理器-〉windowsapplication1.sln -〉右點滑鼠 -〉屬性 -〉通用屬性->常規->啟動物件 -〉改為Module1

4.在Form1中的程式碼:

Private Sub Form1_Load(ByVal sender As System., ByVal e As System.EventArgs) Handles MyBase.Load

  Call SetHook()

  End Sub

  ‘vb.net中沒有form_unload事件了,而是用closing

  Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing

   Call UnHook()

End Sub

 

最後簡單說明一下,為什麼我在module1裡用了Public frm1 As New Form1()這句話,及啟動物件 -〉改為Module1的作法。這是由於vb.net已經是OO的了,如果你是CSDN上vb.net版的常客,你就會很熟悉這個問題,我們已經討論過N次了。我也回過不知多少貼子來說明這一問題。由於和本文主題與篇幅所限,您要是對這個問題不明白,請先看一下:

獲得一些概念。我會在後續的文章中進行更為詳細和的介紹(其實它也是我最想先寫的問題之一)。

 

結束語:關於API的呼叫,本文只涉及了冰山之一角,關於具體的呼叫變化,我會根據vb.net版上的具體情況再寫相關的文章來說明的。

對了,補充一點,vb.net不再認any型別了,因此,在宣告時要具體宣告成你想要用的型別即可。

 

 

                           By Henry

  2002.9.21(中秋夜)

 

 

如果你看過此文,程式出了問題,想要獲得vb.net HOOK的原始碼,可以和我聯絡(但實際上,我已經把程式碼全部寫在上面了)

e-:

qq: 18349592

----

  宣告:本文版權與解釋權歸韓睿所有,如需轉載,請保留完整的內容及此宣告。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-993747/,如需轉載,請註明出處,否則將追究法律責任。

相關文章