C S: chọn chip.
4. Tạo và bắt các sự kiện
Trong hệđiều hành Windows, hook (câu móc) là cơ chế cho phép một hàm chặn một sự kiện (thông điệp, chuột, phím nhấn) trước khi đưa đến đối tượng cần xử lý. Hàm này cho
phân loại dựa theo loại sự kiện bị chặn. Để gọi được hàm lọc, ta cần phải thực hiện quá trình gắn (attach) vào quá trình câu móc (như câu móc bàn phím). Việc gắn một hay nhiều hàm lọc vào một quá trình câu móc được gọi là thiết lập (setting) một quá trình câu móc.
Nếu một quá trình câu móc có nhiều hơn một hàm lọc, Windows sẽ duy trì một chuỗi các hàm lọc trong đó hàm được cài đặt vào gần nhất sẽ nằm ởđầu chuỗi và hàm cài đặt lâu nhất sẽ nằm ở cuối chuỗi. Nếu sự kiện xảy ra làm khởi động quá trình câu móc, Windows sẽ
gọi hàm lọc đầu tiên trong chuỗi. Quá trình câu móc vào một sự kiện được sử dụng bằng hàm SetWindowsHookEx và hàm UnhookWindowsHookEx dùng để xóa bỏ hàm lọc khỏi quá trình.
Cơ chế câu móc cung cấp các khả năng mạnh mẽ cho một ứng dụng Windows. Các
ứng dụng này có thể dùng quá trình câu móc để:
- Xử lý và thay đổi các thông điệp gởi đến các dialog box, message box, scroll bar và menu của một ứng dụng (WH_MSGFILTER).
- Xử lý và thay đổi các thông điệp gởi đến các dialog box, message box, scroll bar và menu của hệ thống (WH_SYSMSGFILTER).
- Xử lý và thay đổi các thông điệp của hệ thống bất cứ khi nào hàm GetMessage
hay PeekMessageđược gọi (WH_GETMESSAGE).
- Xử lý và thay đổi các thông điệp của hệ thống bất cứ khi nào hàm SendMessage
được gọi (WH_CALLWNDPROC).
- Ghi hay thực hiện lại các sự kiện bàn phím và chuột (WH_JOURNALRECORD, WH_JOURNALPLAYBACK).
- Xử lý, sửa đổi hay cấm sự kiện chuột (WH_MOUSE).
- Xử lý, sửa đổi hay cấm sự kiện bàn phím (WH_KEYBOARD).
- Đáp ứng với các hoạt động nào đó của hệ thống, có khả năng phát triển CBT (computer-based training) cho ứng dụng (WH_CBT).
- Cấm các hàm lọc khác (WH_DEBUG). Các ứng dụng thường dùng quá trình câu móc để:
- Dùng phím F1 để hỗ trợ cho menu, dialog box và message box (WH_MSGFILTER).
- Lưu lại quá trình thực hiện khi nhấn phím hay chuột (thường dùng cho macro). Ví dụ như Windows Recorder sử dụng hook để hỗ trợ chức năng record và playback (WH_JOURNALRECORD, WH_JOURNALPLAYBACK).
- Quản lý thông điệp để xác nhận thông điệp được gởi tới cửa sổ hay được tạo ra (WH_GETMESAGE, WH_CALLWNDPROC).
- Mô phỏng ngõ vào chuột và bàn phím (WH_JOURNALPLAYBACK). Quá trình câu móc là phương pháp tin cậy để thực hiện hoạt động này. Nếu ta thực hiện mô phỏng bằng cách gởi thông điệp, Windows sẽ không thực hiện cập nhật trạng thái của bàn phím hay chuột dẫn đến các hoạt động không mong muốn. Nếu quá trình câu móc thực hiện điều này, nó sẽ được xử lý giống như sự kiện chuột hay bàn
phím xảy ra. Ví dụ như Microsoft Excel dùng hook để thực hiện macro SENDKEYS.
- Cung cấp khả năng CBT cho ứng dụng thực hiện trên môi trường Windows (WH_CBT) làm cho quá trình phát triển ứng dụng CBT dễ dàng hơn.
Phạm vi sử dụng: Một trong những đặc trưng của Win32 Hook là cho phép chỉđịnh quá trình câu móc là hệ thống hay ở dạng luồng (thread). Hook hệ thống cho phép tác động
đến các cửa sổ khác trong hệ thống còn hook luồng chỉ cho phép tác động đến cửa sổ hiện hành.
Cách thức sử dụng quá trình câu móc:
Để sử dụng quá trình câu móc, ta cần phải biết:
- Làm thế nào dùng hàm câu móc của Windows để thêm vào hay xóa bỏ một hàm lọc trong chuỗi hàm xử lý của một quá trình câu móc.
- Cần phải thực hiện các hoạt động gì để cài đặt một hàm lọc.
- Có thể thực hiện được hàm câu móc nào và chúng có thể làm được gì, gởi những thông tin nào.
4.1. Hàm câu móc của Windows
Các ứng dụng trên nền Windows sử dụng các hàm SetWindowsHookEx,
UnhookWindowsHookEx và CallNextHookEx để quản lý chuỗi hàm lọc trong một quá trình câu móc. Trước phiên bản 3.1, Windows thực hiện quản lý bằng các hàm
SetWindowsHook, UnhookWindowsHook và DefHookProc. Mặc dù các hàm này cũng có khả năng thực hiện được trên nền Win32 nhưng sẽ có một số đặc trưng không sử dụng
được như các phiên bản mới (Ex).
4.1.1. Hàm SetWindowsHookEx
Dùng để thêm một hàm lọc vào một quá trình câu móc.
Khai báo:
Public Declare Function SetWindowsHook Lib "user32" Alias "SetWindowsHookA" (ByVal nFilterType As Long, ByVal pfnFilterProc As Long) 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
Hàm SetWindowsHookEx gồm có 4 tham số:
- idHook: xác định loại hàm câu móc sẽ cài đặt. Thông số này gồm các giá trị sau: WH_KEYBOARD: cài đặt hàm câu móc quản lý thông điệp gởi đi khi nhấn phím (ngoại trừ tổ hợp Ctrl – Alt – Del).
WH_MOUSE: cài đặt hàm câu móc quản lý thông điệp khi điều khiển chuột.
WH_CALLWNDPROCRET: cài đặt hàm câu móc quản lý thông điệp sau khi cửa sổ đã xử lý. Loại này cho phép thay đổi giá trị trả về của thông điệp.
WH_MSGFILTER: cài đặt hàm câu móc quản lý các thông điệp được tạo ra giống như có một sự kiện của dialog box, message box, menu hay scroll bar.
WH_GETMESSAGE: cài đặt hàm câu móc quản lý các thông điệp được gởi tới hàng
đợi.
WH_CBT: cài đặt hàm câu móc để nhận thông báo từứng dụng CBT. WH_DEBUG: cài đặt hàm câu móc để gỡ rối một hàm câu móc khác.
WH_FOREGROUNDIDLE: cài đặt hàm câu móc trong đó hàm này được gọi khi luồng (thread) foreground của ứng dụng rảnh (idle). Quá trình này thường sử dụng để thực thi các tác vụ có độưu tiên thấp khi luồng ưu tiên rảnh.
WH_JOURNALPLAYBACK: cài đặt hàm câu móc để gởi các thông điệp đã được lưu bằng hàm câu móc WH_JOURNALRECORD.
WH_JOURNALRECORD: cài đặt hàm câu móc lưu lại các thông điệp đã gởi đến hàng đợi.
WH_KEYBOARD_LL: cài đặt hàm câu móc quản lý sự kiện bàn phím ở mức thấp (dùng cho Windows NT/2000/XP).
WH_MOUSE_LL: cài đặt hàm câu móc quản lý sự kiện chuột ở mức thấp (dùng cho Windows NT/2000/XP).
WH_SHELL: cài đặt hàm câu móc cho một ứng dụng shell.
WH_SYSMSGFILTER: cài đặt hàm câu móc quản lý các thông điệp được tạo ra giống như có một sự kiện của dialog box, message box, menu hay scroll bar. Hàm này quản lý cho tất cảứng dụng trong cùng một desktop.
- lpfn:
Con trỏ chỉđến địa chỉ của hàm lọc. Nếu tham số dwThreadId = 0 hay chỉđến một luồng được tạo bởi một tiến trình (process) khác, tham số lpfn phải chỉ đến một hàm câu móc trong một thư viện liên kết động (DLL). Ngược lại, lpfn chỉ đến hàm câu móc chứa trong bản thân tiến trình hiện hành.
- hMod:
handle chỉđến DLL chứa hàm xử lý xác định bằng tham sốlpfn. Tham sốhMod phải
đặt là NULL nếu hàm câu móc nằm trong tiến trình hiện hành - dwThreadId:
Xác định ID của luồng thực hiện quá trình câu móc. Nếu dwThreadId = 0, hàm câu móc sẽ tác động đến tất cả các luồng. Ứng dụng có thể dùng hàm GetCurrentThreadId để
Phạm vi thực hiện của hàm câu móc mô tả như sau: Hook Phạm vi WH_CALLWNDPROC Luồng hay hệ thống WH_CBT Luồng hay hệ thống WH_DEBUG Luồng hay hệ thống WH_GETMESSAGE Luồng hay hệ thống WH_JOURNALRECORD Hệ thống WH_JOURNALPLAYBACK Hệ thống WH_FOREGROUNDIDLE Luồng hay hệ thống WH_SHELL Luồng hay hệ thống WH_KEYBOARD Luồng hay hệ thống WH_MOUSE Luồng hay hệ thống WH_MSGFILTER Luồng hay hệ thống WH_SYSMSGFILTER Hệ thống
Hàm SetWindowsHookEx trả về handle của quá trình câu móc đã cài đặt và trả về
NULL nếu quá trình cài đặt không thành công. Handle này được dùng để xóa quá trình câu móc khi sử dụng hàm UnhookWindowsHookEx. Các thông báo lỗi khi quá trình câu móc không thành công là:
- ERROR_INVALID_HOOK_FILTER: mã câu móc sai - ERROR_INVALID_FILTER_PROC: hàm lọc sai
- ERROR_HOOK_NEEDS_HMOD: một quá trình câu móc toàn cục sử dụng tham số hMod = NULL hay chỉđến một luồng không tồn tại.
- ERROR_GLOBAL_ONLY_HOOK: một quá trình câu móc chỉ dùng được cho hệ thống nhưng được cài đặt cho một luồng xác định.
- ERROR_INVALID_PARAMETER: ID của luồng sai.
- ERROR_JOURNAL_HOOK_SET: Cài đặt thêm một quá trình câu móc dạng nhật ký (WH_JOURNALRECORD và WH_JOURNALPLAYBACK) trong khi một quá trình dạng này đang tồn tại (tại một thời điểm chỉ cho phép một quá trình dạng nhật ký).
- ERROR_MOD_NOT_FOUND: Tham số hMod chỉđến một hàm không xác định
được.
4.1.2. Hàm UnhookWindowsHookEx:
Dùng để xoá một hàm lọc ra khỏi chuỗi xử lý một quá trình câu móc. Hàm này lấy handle của quá trình câu móc trả về từ lệnh gọi hàm SetWindowsHookEx và luôn trả về giá trị TRUE.
Khai báo:
Public Declare Function UnhookWindowsHook Lib "user32"
Alias "UnhookWindowsHook" (ByVal nCode As Long, ByVal pfnFilterProc As Long) As Long
Public Declare Function UnhookWindowsHookEx Lib
"user32" Alias "UnhookWindowsHookEx" (ByVal hHook As Long) As Long
4.1.3. Hàm CallNextHookEx:
Dùng để chuyển thông tin câu móc đến hàm câu móc kế tiếp trong chuỗi xử lý.
Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal ncode As Long, ByVal wParam As Long, lParam As Any) As Long
- hHook: handle của quá trình câu móc, là giá trị trả về từ lệnh gọi hàm SetWindowsHookEx. Thông thường Windows bỏ qua giá trị này.
- nCode: mã của quá trình câu móc, hàm câu móc dùng mã này để xác định phương pháp xử lý thông tin.
- wParam: xác định tham sốđược xử lý bởi hàm câu móc. - lParam: giống như wParam.
Khi một quá trình câu móc khởi động, Windows gọi hàm đầu tiên trong chuỗi hàm lọc và kết thúc quản lý quá trình, các hàm lọc phía sau sẽ không xử lý. Để thực hiện các hàm ở phía sau trong chuỗi hàm, Windows cung cấp hàm CallNextHookEx cho phép gọi một hàm kế tiếp trong chuỗi hàm lọc. Như vậy, nếu một hàm lọc nào đó không thực hiện hàm CallNextHookEx thì các hàm lọc ở phía sau sẽ không thực hiện.
Một ví dụ sử dụng các hàm xử lý câu móc như sau:
'Ch•a trong m•t file module
Public Const WH_KEYBOARD = 2 Public Const VK_SHIFT = &H10 Public Const VK_CONTROL = &H11 Public Const VK_MENU = &H12
Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal ncode As Long, ByVal wParam As Long, lParam As Any) As Long
Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer ‘Xác ••nh tr•ng thái c•a m•t phím (Bit15)
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
Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
Public hHook As Long
Public Function KeyboardProc(ByVal idHook As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
If idHook < 0 Then 'G•i hàm x• lý k• ti•p
KeyboardProc = CallNextHookEx(hHook, idHook, wParam, ByVal lParam)
Else
'N•u nh•n Shift-C
If (GetKeyState(VK_SHIFT) And &H8000) And wParam = Asc("C") Then
'thì hi•n th• k•t qu•
Form1.Print "Shift-C pressed ..." End If
If (GetKeyState(VK_CONTROL) And &H8000) And wParam = Asc("C") Then
Form1.Print "Ctrl-C pressed ..." End If
If (GetKeyState(VK_MENU) And &H8000) And wParam = Asc("C") Then
Form1.Print "Alt-C pressed ..." End If
'G•i hàm x• lý k• ti•p
KeyboardProc = CallNextHookEx(hHook, idHook, wParam, ByVal lParam)
End If
End Function
---
'Ch•a trong form
Private Sub Form_Load()
'••t quá trình câu móc
hHook = SetWindowsHookEx(WH_KEYBOARD, AddressOf KeyboardProc, App.hInstance, App.ThreadID)
'Xoá quá trình câu móc UnhookWindowsHookEx hHook End Sub
4.2. Hàm lọc
Hàm lọc thường có dạng như sau:
Function FilterFunc (ByVal nCode As Integer, ByVal wParam As Long, ByVal lParam As Long)
Hàm lọc nhận 3 tham số:
- nCode: mã của quá trình câu móc, là một số nguyên xác định hàm lọc, ví dụ như
loại sự kiện làm khởi động quá trình câu móc. Mã này được xác định khi hàm lọc xử lý sự kiện hay gọi hàm DefHookProc. Nếu mã câu móc < 0 thì hàm lọc sẽ
không xử lý sự kiện mà sẽ gọi hàm DefHookProcđể truyền 3 tham số còn lại cho hàm lọc kế tiếp trong chuỗi hàm lọc bằng hàm CallNextHookEx.
- Tham số thứ hai wParam và thứ ba lParam chứa các thông tin cần thiết cho hàm lọc. Mỗi quá trình câu móc dùng các giá trị wParam và lParam khác nhau. Ví dụ
như, quá trình câu móc bàn phím WH_KEYBOARD chứa mã phím nhấn trong wParam và trạng thái bàn phím trong lParam. Hay quá trình câu móc WH_MSGFILTER chứa giá trị NULL trong wParam và một con trỏ chỉ đến thông điệp chứa trong lParam.
Hàm lọc dùng trong DLL:
Đối với các quá trình câu móc cục bộ, hàm lọc có thểđặt ngay trong mã lệnh của ứng dụng nhưng đối với các quá trình câu móc hệ thống, hàm lọc phải được đặt trong một DLL. Chỉ có quá trình câu móc dạng nhật ký (WH_JOURNALRECORD và WH_JOURNALPLAYBACK) là ngoại lệ. Hàm lọc của quá trình câu móc hệ thống phải chia sẻ dữ liệu cho tiến trình thực hiện quá trình câu móc. Các biến toàn cục sử dụng trong DLL phải được xác định rõ hay phải đặt trong vùng dữ liệu chia sẻ.
Chương 3
GIAO TIẾP THIẾT BỊ CHUẨN