Hi QuynhGiao!
Tất cả các ứng dụng chạy trong môi trường Windows đều hoạt động dựa trên hệ thống message. Mỗi khi có một hành động nào đó xảy ra (thời gian thay đổi, user di chuột, gõ phím....) thì Windows sẽ tạo ra các message và gửi nó đến các window (bao gồm cả các control trong VB...).
Nhằm mang lại thuận tiện và sự dễ dàng nhất cho lập trình viên, VB tự động xử lý tất cả các message gửi đến ứng dụng và từ các message đó nó tạo ra các event cho lập trình viên sử dụng. Không may là không phải message nào cũng được tạo ra một event tương ứng. Vì vậy, lập trình viên bị hạn chế rất nhiều.
Subclassing (có từ VB5.0) cho các VBprogrammer một cơ hội để "vượt qua rào cản đó". Với kĩ thuật này, chúng ta có thể biết khi nào một message được gửi đến một window (control) và vì vậy, chúng ta có thể đón nhận, xử lý và đưa ra một kết quả theo ý mình.
Một ví dụ: menu mà VB cung cấp chỉ đơn giản là text. Thay vì vậy, nếu ta chặn message WM_PAINT (được gửi đến nếu menu cần được vẽ lại) thì ta sẽ có cơ hội thay đổi lại hình thức menu, giống như menu trong bộ OfficeXP chẳng hạn (tất nhiên, đấy là nói về lý thuyết còn thực tế thì để làm hoàn chỉnh thì sẽ tốn rất nhiều công sức).
Thi hành kĩ thuật này không quá khó khăn, các bước như sau:
- Khai báo:
Code:
Declare Function SetWindowLong Lib "user32" _
Alias "SetWindowLongA" (ByVal hwnd As Long, _
Byval nIndex As Long, ByVal dwNewLong As Long) As Long
- Tạo một WindowProcedure mới:
Code:
Function MyWndProc(ByVal hWnd As Long, _
ByVal uMsg As Long, ByVal wParam As Long, _
ByVal lParam As Long) As Long
'gọi thủ tục window gốc
MyProc = CallWindowProc(oldAddress, hWnd, _
uMsg, wParam, lParam)
'phát thiện cần phải vẽ lại menu
If uMsg = WM_PAINT Then
'xử lý
End If
End Function
hay
Function MyWndProc(ByVal hWnd As Long, _
ByVal uMsg As Long, ByVal wParam As Long, _
ByVal lParam As Long) As Long
'phát thiện cần phải vẽ lại menu
If uMsg = WM_PAINT Then
'xử lý
End If
'gọi thủ tục window gốc
MyProc = CallWindowProc(oldAddress, hWnd, _
uMsg, wParam, lParam)
End Function
- Khởi tạo
Code:
oldAddress = SetWindowLong(hWnd, _
GWL_WNDPROC, AddressOf MyWindowProc)
'lưu ý hWnd chính là handle của window (control)
'được subclassing
- Sau khi kết thúc chương trình, nhớ phục hồi lại nếu không thì chương trình bị crash là điều tất yếu
Code:
SetWindowLong hWnd, GWL_WNDPROC, oldAddress
Hook cũng tương tự như Subclassing nhưng nó khác với Subclassing ở chỗ nó không hướng đến một window (control) cụ thể nào. Mỗi khi có một loại message nào đó được tạo ra thì thủ tục mà ta đã gài vào chuỗi mắt xích (hook chain) sẽ được kích hoạt trước khi message đó được hướng đến một window(control) cụ thể. Có 14 loại hook khác nhau nhưng phần lớn không thể sử dụng trong VB (do nó không thể tạo ra các DLL), số còn lại cũng bị sử dụng hạn chế (do không thể hook toàn cục trong VB được).
Một số hook hay được sử dụng: WH_KEYBOARD, WH_MOUSE
Thi hành hooking như sau:
- Khai báo:
Code:
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" _
Alias "CallNextHookEx" (ByVal hHook As Long, _
ByVal ncode As Long, ByVal wParam As Long, _
lParam As Any) As Long
Public Declare Function UnhookWindowsHookEx Lib "user32" _
Alias "UnhookWindowsHookEx" (ByVal hHook As Long) As Long
- Tạo một procedure để xử lý
Code:
Function MyMsgProc(ByVal lMsg As Long, _
MyVal wParam As Long, ByVal lParam As Long) As Long
If lMsg = HCBT_SETFOCUS Then
'Xử lý
End If
MyMsgProc = CallNextHookEx ( _
hHook, lMsg, wParam, lParam)
End Function
- Thiết lập
Code:
hHook = SetWindowsHookEx(IdHook, _
AddressOf MyMsgProc, hInst, hThread)
- Loại bỏ khi kết thúc:
Code:
Call UnHookWindowsHookEx(hHook)
Có thể tham khảo thêm hai bài viết sau:
http://www.diendantinhoc.com/showthr...threadid=11032 (Subclassing)
http://www.diendantinhoc.com/showthr...&threadid=7749 (Hooking)
Bookmarks