Lập trình hệ thống phkkhanh bai3 tài liệu, giáo án, bài giảng , luận văn, luận án, đồ án, bài tập lớn về tất cả các lĩnh...
Trang 1BÀI 3: XỬ LÝ SỰ KIỆN
MỤC ĐÍCH THÍ NGHIỆM
Giúp sinh viên bằng thực nghiệm khảo sát các vấn đề chính sau đây :
- Tìm hiểu phương pháp chặn sự kiện
- Lập trình chặn sự kiện bàn phím
THIẾT BỊ SỬ DỤNG
1 Máy vi tính
PHẦN I : CƠ SỞ LÝ THUYẾT
Sự kiện (Event) là một tác động lên một đối tượng trong môi trường Windows Khi có một sự kiện xảy ra, Windows sẽ gởi thông điệp (message) đến đối tượng Các sự kiện thường xảy ra là:
- Sự kiện chuột: Click, Double Click, …
- Sự kiện bàn phím: nhấn phím, nhả phím, …
- Sự kiện cửa sổ: Activate, Load, Unload, …
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ép thay đổi hoặc thậm chí cấm sự kiện xảy ra Chúng được gọi là hàm lọc (filter) và được 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
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
SetWindowsHookEx: Dùng để thêm một hàm lọc vào một quá trình câu móc,
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:
Trang 2WH_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_CALLWNDPROC: cài đặt hàm câu móc quản lý thông điệp trước khi hệ thống gởi đến cửa sổ, chỉ cho phép xử lý thông điệp mà không được thay đổi thông điệp
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
đặt là NULL nếu hàm câu móc nằm trong tiến trình hiện hành
- dwThreadId:
Trang 3Xá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 để xác định ID của luồng hiện hành
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
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ý
- 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
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 Các tham số tương ứng trong hàm lọc ứng với các sự kiện chuột và bàn phím cho như sau:
- Hook bàn phím:
nCode: nếu nCode < 0, hàm lọc phải chuyển thông điệp bằng hàm
CallNextHookEx mà không xử lý
wParam: loại thông điệp (WM_KEYDOWN, WM_KEYUP,
WM_SYSKEYDOWN hay WM_SYSKEYUP)
lParam: con trỏ chỉ đến cấu trúc KBDLLHOOKSTRUCTURE
Public Type KBDLLHOOKSTRUCT
vkCode As Long scanCode As Long flags As Long time As Long
Trang 4dwExtraInfo As Long End Type
vkCode: mã phím nhấn scanCode: mã quét (phần cứng) flags:
=0: nhấn
=1: nhả
=1: nhấn ALT
=0: không nhấn
=1: phím mở rộng (phím F1 – F12, …)
=0: không phải
- Hook chuột:
nCode: giống như trên
wParam: loại thông điệp (WM_LBUTTONDOWN, WM_LBUTTONUP,
WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_RBUTTONDOWN hay WM_RBUTTONUP)
lParam: con trỏ chỉ đến cấu trúc MSLLHOOKSTRUCTURE
Public Type MSLLHOOKSTRUCT
pt As POINTAPI hWnd As Long wHitTestCode As Long dwExtraInfo As Long End Type
Public Type POINTAPI
x As Long
y As Long End Type
pt: toạ độ con trỏ chuột
hWnd: handle của window nhận sự kiện chuột
Trang 5PHẦN II : TIẾN TRÌNH THÍ NGHIỆM
- Khởi động Visual Basic
- Cửa sổ chương trình Visual Basic
- Vùng thiết kế:
Thiết kế giao diện của chương trình
- Project Explorer:
Hiển thị tất cả các Form và Module có trong chương trình
- Properties Window:
Hiển thị và cho phép sửa đổi thuộc tính của các đối tượng
- Thanh công cụ:
Tạo các đối tượng cho Project:
Vùng thiết kế
Properties Window
Trang 6- Dùng VB6 tạo giao diện sau:
Chương trình cho Form1:
Dim handleKeyBoard As Long
Private Sub cmdExit_Click()
Unload Me
End Sub
Private Sub cmdhook_Click()
If cmdHook.Caption = "Start Hook" Then
cmdHook.Caption = "Stop Hook"
Command Button
Name = cmdHook
Caption = Start Hook
Textbox
Name = txtResult
MultiLine = True
ScrollBars = Both
Command Button Name = cmdExit
Command Button Option
Check box Frame
Trang 7handleKeyBoard = SetWindowsHookEx(WH_KEYBOARD_LL, AddressOf LowLevelKeyboardProc, App.hInstance, 0)
Else
UnhookWindowsHookEx handleKeyBoard
handleKeyBoard = 0
cmdHook.Caption = "Start Hook"
End If
End Sub
Private Sub Form_Unload(Cancel As Integer)
If handleKeyBoard <> 0 Then UnhookWindowsHookEx handleKeyBoard
End Sub
- Tạo một module (Project > Add Module):
Trang 8- Mở module mới:
- Mở cửa sổ code của Module:
Chương trình cho Module1:
Public Declare Sub CopyMemory Lib "kernel32" Alias
"RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Public Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
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 CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal nCode As Long, ByVal wParam
As Long, lParam As Any) As Long
Public Declare Function UnhookWindowsHookEx Lib
"user32" (ByVal hHook As Long) As Long
Public Const HC_ACTION = 0
Public Const WM_KEYDOWN = &H100
Public Const WM_SYSKEYDOWN = &H104
Trang 9Public Const WH_KEYBOARD = 2
Public Type KBDLLHOOKSTRUCT
vkCode As Long scanCode As Long flags As Long time As Long dwExtraInfo As Long End Type
Dim kb_pointer As KBDLLHOOKSTRUCT
Public Function LowLevelKeyboardProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
If (nCode = HC_ACTION) Then
If wParam = WM_KEYDOWN Or wParam = WM_SYSKEYDOWN Then
CopyMemory kb_pointer, ByVal lParam, Len(kb_pointer)
Form1.txtResult.Text = Form1.txtResult.Text + Chr(kb_pointer.vkCode)
End If
End If
LowLevelKeyboardProc = CallNextHookEx(0, nCode, wParam, ByVal lParam)
End Function
- Lưu Project: File > Save Project (VD: bai3.vbp, bai3.frm, bai3.bas)
- Thực hiện biên dịch chương trình: File > Make bai3.exe
Trang 10- Thực thi file bai3.exe
Thay đoạn in đậm bằng đoạn chương trình sau:
If kb_pointer.vkCode = 65 Then
LowLevelKeyboardProc = -1 Exit Function
Else
Form1.txtResult.Text = Form1.txtResult.Text + Chr(kb_pointer.vkCode)
End If
- Biên dịch và thực thi
- Sửa đổi chương trình để chặn tất cả các phím số
- Dùng VB6 tạo giao diện sau:
Chương trình cho Form1:
Private Sub Command1_Click()
If Command1.Caption = "Hook" Then
SetHook
Command1.Caption = "UnHook"
Else
UnSetHook
Command1.Caption = "Hook"
End If
End Sub
Command Button
Name = cmdHook
Caption = Hook
Label
Caption = Mouse Position
Label Caption = X pos
Label Caption = Y pos
Label Name = lblX Caption = “”
Label Name = lblY Caption = “”
Trang 11If Command1.Caption = "UnHook" Then
UnSetHook
End If
End Sub
Chương trình cho Module1:
Type POINTAPI
x As Long
y As Long
End Type
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 UnhookWindowsHookEx Lib
"user32" (ByVal hHook As Long) As Long
Public Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal nCode As Long, ByVal wParam
As Long, lParam As Any) As Long
Public Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Public Const WH_MOUSE_LL = 14&
Public Const WH_MOUSE = 7&
Public Const HC_ACTION = 0&
Public Const WM_RBUTTONDOWN = &H204
Public Const WM_RBUTTONUP = &H205
Public Const WM_LBUTTONDOWN = &H201
Public Const WM_LBUTTONUP = &H202
Public Const WM_MOUSEMOVE = &H200
Public Const VK_RBUTTON = &H2
Private lMShook As Long
Private bHookEnabled As Boolean
Public Function MouseProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Dim p_cursor As POINTAPI
If nCode = HC_ACTION Then
If (wParam = WM_RBUTTONUP Or wParam = WM_RBUTTONDOWN) Then
MouseProc = -1
Exit Function
ElseIf (wParam = WM_LBUTTONUP Or wParam = WM_LBUTTONDOWN) Then
GetCursorPos p_cursor
Form1.lblX.Caption = Str(p_cursor.x)
Form1.lblY.Caption = Str(p_cursor.y)
End If
End If
MouseProc = CallNextHookEx(lMShook, nCode, wParam, lParam)
Trang 12End Function
Public Function SetHook()
If lMShook = 0 Then
lMShook = SetWindowsHookEx(WH_MOUSE_LL, AddressOf MouseProc, App.hInstance, 0&)
End If
If lMShook = 0 Then
MsgBox "failed to install hook :" & lMShook & " : " & WH_MOUSE_LL
bHookEnabled = False
Unload Form1
Exit Function
Else
bHookEnabled = True
End If
End Function
Public Function UnSetHook()
If bHookEnabled Then
Call UnhookWindowsHookEx(lMShook)
lMShook = 0
End If
bHookEnabled = False
End Function
Public Function InstalledHook()
MsgBox " installed hook is :" & lMShook
End Function
- Viết lại chương trình để hiển thị toạ độ con trỏ chuột mỗi khi di chuyển
- Viết lại chương trình cho cả hai cơ chế Hook bàn phím và chuột sao cho chỉ tác động lên cửa sổ hiện hành