小议钩子函数

       最近一个同学去面试兼职,被问到什么是回调函数。我以前是听说过的,也看到BBS的C++版讨论过,但是没有很深理解,随便看看就完事了!想不到这次在兼职面试中出现了,我就顺便看看!后来又发现在实际工程中使用最多的回调函数例子试钩子函数。
        什么是钩子函数呢? Windows的钩子函数分两种,一种是全局的,一种是线程的。全局的钩子函数可以捕获任何应用程序的消息,但必须是标准的DLL才能实现,VB做不了。VB可以实现线程的,就是当前应用程序的消息,这对鼠标消息的捕捉有影响。
    SetWindowsHookEx定义如下:
    Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
    idHook是钩子类型,如WH_KEYBOARD捕捉键盘消息,而WH_MOUSE捕捉鼠标消息。hmod用于全局钩子,VB要实现钩子,必须设为0。dwThreadId用于线程钩子VB中可以设置为App.ThreadID。lpfn为钩子函数,在VB中可以使用AddressOf获得钩子函数的地址。这个函数因为钩子类型不同而有所不同。如键盘钩子为:
    Public Function KeyboardProc(ByVal nCode As Long, _
     ByVal wParam As Long, _
     ByVal lParam As Long) As Long
    如果Code不为0,钩子函数必须调用CallNextHookEx,将消息传递给下面的钩子。wParam和lParam不是按键。
    下面是msdn上一篇关于钩子的例子:

SUMMARY

This article illustrates how to position a message box on the screen.

MORE INFORMATION

You can create a CBT hook for your application so that it receives notifications when windows are created and destroyed. If you display a message box with this CBT hook in place, your application will receive a HCBT_ACTIVATE message when the message box is activated. Once you receive this HCBT_ACTIVATE message, you can position the window with the SetWindowPos API function and then release the CBT hook if it is no longer needed.

Step-by-Step Example

1. Start a new Standard EXE project. Form1 is created by default.
2. Add a module to the project and add the following code to the new module:
      Type RECT
         Left As Long
         Top As Long
         Right As Long
         Bottom As Long
      End Type

      Public Declare Function UnhookWindowsHookEx Lib "user32" ( _
         ByVal hHook As Long) As Long
      Public Declare Function GetWindowLong Lib "user32" Alias _
         "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) _
         As Long
      Public Declare Function GetCurrentThreadId Lib "kernel32" () As Long
      Public Declare Function SetWindowsHookEx Lib "user32" Alias _
         "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, _
         ByVal hmod As Long, ByVal dwThreadId As Long) As Long
      Public Declare Function SetWindowPos Lib "user32" ( _
         ByVal hwnd As Long, ByVal hWndInsertAfter As Long, _
         ByVal x As Long, ByVal y As Long, ByVal cx As Long, _
         ByVal cy As Long, ByVal wFlags As Long) As Long
      Public Declare Function GetWindowRect Lib "user32" (ByVal hwnd _
         As Long, lpRect As RECT) As Long

      Public Const GWL_HINSTANCE = (-6)
      Public Const SWP_NOSIZE = &H1
      Public Const SWP_NOZORDER = &H4
      Public Const SWP_NOACTIVATE = &H10
      Public Const HCBT_ACTIVATE = 5
      Public Const WH_CBT = 5

      Public hHook As Long

      Function WinProc1(ByVal lMsg As Long, ByVal wParam As Long, _
         ByVal lParam As Long) As Long

         If lMsg = HCBT_ACTIVATE Then
            'Show the MsgBox at a fixed location (0,0)
            SetWindowPos wParam, 0, 0, 0, 0, 0, _
                         SWP_NOSIZE Or SWP_NOZORDER Or SWP_NOACTIVATE
            'Release the CBT hook
            UnhookWindowsHookEx hHook
         End If
         WinProc1 = False

      End Function

      Function WinProc2(ByVal lMsg As Long, ByVal wParam As Long, _
         ByVal lParam As Long) As Long

      Dim rectForm As RECT, rectMsg As RECT
      Dim x As Long, y As Long

         'On HCBT_ACTIVATE, show the MsgBox centered over Form1
         If lMsg = HCBT_ACTIVATE Then
            'Get the coordinates of the form and the message box so that
            'you can determine where the center of the form is located
            GetWindowRect Form1.hwnd, rectForm
            GetWindowRect wParam, rectMsg
            x = (rectForm.Left + (rectForm.Right - rectForm.Left) / 2) - _
                ((rectMsg.Right - rectMsg.Left) / 2)
            y = (rectForm.Top + (rectForm.Bottom - rectForm.Top) / 2) - _
                ((rectMsg.Bottom - rectMsg.Top) / 2)
            'Position the msgbox
            SetWindowPos wParam, 0, x, y, 0, 0, _
                         SWP_NOSIZE Or SWP_NOZORDER Or SWP_NOACTIVATE
            'Release the CBT hook
            UnhookWindowsHookEx hHook
         End If
         WinProc2 = False

      End Function

                                    
3. Add two CommandButtons to Form1.
4. Add the following code to Form1:
      Private Sub Command1_Click()
      Dim hInst As Long
      Dim Thread As Long

         'Set up the CBT hook
         hInst = GetWindowLong(Me.hwnd, GWL_HINSTANCE)
         Thread = GetCurrentThreadId()
         hHook = SetWindowsHookEx(WH_CBT, AddressOf WinProc1, hInst, _
                                  Thread)

         'Display the message box
         MsgBox "This message box has been positioned at (0,0)."

      End Sub

      Private Sub Command2_Click()
      Dim hInst As Long
      Dim Thread As Long

         'Set up the CBT hook
         hInst = GetWindowLong(Me.hwnd, GWL_HINSTANCE)
         Thread = GetCurrentThreadId()
         hHook = SetWindowsHookEx(WH_CBT, AddressOf WinProc2, hInst, _
                                  Thread)

         'Display the message box
         MsgBox "This message box is centered over Form1."
      End Sub

                                    
5. Press the F5 key to run the program. Click Command1 and the message box appears at the upper-left corner of the screen (0,0). Click OK to dismiss the message box. Click Command2 and the message box appears at the center of Form1. Click OK to dismiss the message box.

我按照这些step已经试过了,可以看到上面例子两个按钮分别调用winproc1和winproc2两个钩子函数!
posted @ 2005-01-18 11:16  小白天地  阅读(2800)  评论(5)    收藏  举报