Tài liệu Lập trình hệ thống - Chương 2: Ngắt và sự kiện

Tài liệu Lập trình hệ thống  
Chương 2  
Chương 2  
NGẮT VÀ SỰ KIỆN  
1. Khái niệm  
Ngắt (interrupt) là quá trình dừng chương trình chính đang chạy để ưu tiên thực hiện  
một chương trình khác, chương trình này được gọi là chương trình phục vụ ngắt (ISR –  
Interrupt Service Routine). ISR hoàn toàn giống với một chương trình bình thường trên máy  
tính, nghĩa là nó có khả năng truy xuất đến tất cả các lệnh ngôn ngữ máy của µP. Tuy nhiên  
cuối ISR sẽ kết thúc bằng lệnh IRET (Interrupt Return) để µP tiếp tục thực hiện lệnh đã kết  
thúc trước đây.  
Các nguyên nhân dẫn đến ngắt là:  
- Bản thân chương trình đang thực hiện bị lỗi, ví dụ như: chia cho 0, …  
- Do tác động của thiết bị ngoại vi, ví dụ như: thực hiện lệnh in nhưng máy in lỗi,  
ghi dữ liệu vào đĩa nhưng không có đĩa, …  
- Do lập trình viên chủ động gọi các ngắt có sẵn.  
Một cách đơn giản, chúng ta có thể xem ngắt như là quá trình gọi chương trình con  
nhưng các chương trình con này được tạo ra sẵn trong máy tính và quá trình gọi này có thể  
xảy ra tại thời điểm không xác định trước.  
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, …  
2. Các loại ngắt và bảng vector ngắt  
Quá trình ngắt có thể mô tả như sau:  
Chương trình chính  
ISR  
Lưu trữ các thanh ghi cần thiết  
…
Khôi phục các thanh ghi  
Quay về chương trình chính (IRET)  
Hình 2.1 – Quá trình thực hiện ngắt  
Phạm Hùng Kim Khánh  
Trang 34  
Tài liệu Lập trình hệ thống  
Chương 2  
Trong các quá trình ngắt, ta phân biệt thành 2 loại: ngắt cứng và ngắt mềm. Ngắt  
mềm là ngắt được gọi bằng một lệnh trong chương trình ngôn ngữ máy. Ngắt mềm được  
thục hiện trên hợp ngữ thông qua lệnh INT. Đối với các ngôn ngữ bậc cao hơn, vẫn cho  
phép thực hiện gọi ngắt nhưng phải được biên dịch thành lệnh INT trong hợp ngữ rồi mời  
thực hiện.  
Khác với ngắt mềm, ngắt cứng không được khởi động bên trong máy tính mà do các  
linh kiện điện tử tác đông lên hệ thống. Ngắt cứng cũng được chia thành 2 loại: ngắt che  
được và ngắt không che được. Ngắt che được là ngắt có thể cho phép hay không cho phép  
thực thi bằng phần mềm thông qua cờ ngắt IF (Interrupt Flag): lệnh CLI (Clear Interrupt  
Flag) sẽ cấm ngắt và lệnh STI (Set Interrupt Flag) sẽ cho phép các ngắt này hoạt động.  
Các loại ngắt khác nhau có thể mô tả như sau:  
Ngắt  
Ngắt mềm  
Ngắt cứng  
Ngắt hệ thống  
Ngắt do người  
sử dụng  
Trong  
Ngoài  
HĐH  
BIOS  
Che được  
Không  
che được  
Hình 2.2 – Các loại ngắt  
Khi thực hiện lệnh gọi một ngắt nào đó, chương trình con phục vụ cho ngắt sẽ được  
gọi. Để thực hiện các ngắt tương ứng, địa chỉ thực hiện các chương trình con phục vụ ngắt  
được đặt trong một bảng, gọi là bảng vector ngắt.  
Bảng vector ngắt gồm có 256 phần tử, mỗi phần tử gồm 4 byte ứng với 256 ngắt (từ  
ngắt 0 đến ngắt 0FFh). Mỗi phần tử trong bảng vector ngắt chứa 2 địa chỉ: địa chỉ thanh ghi  
đoạn đưa vào CS và địa chỉ offset của chương trình phục vụ ngắt đưa vào IP.  
Phạm Hùng Kim Khánh  
Trang 35  
Tài liệu Lập trình hệ thống  
Chương 2  
Bảng vector ngắt có thể mô tả như sau:  
Địa chỉ  
Địa chỉ ISR Số thứ tự ngắt  
0000h:0000h  
0000h:0002h  
0000h:0004h  
0000h:0006h  
0000h:0008h  
0000h:000Ah  
…
CS  
0
IP  
CS  
1
IP  
CS  
2
IP  
…
CS  
IP  
…
0000h:03FCh  
0000h:03FEh  
255  
Khi có một quá trình ngắt xảy ra, CPU sẽ tìm địa chỉ bắt đầu của chương trình ngắt  
được chứa trong bảng vector ngắt theo số thự tự ngắt. Do một phần tử trong bảng vector  
ngắt chiếm 4 byte nên để tìm giá trị địa chỉ trong bảng vector ngắt, ta chỉ cần nhân số thứ tự  
ngắt với 4.  
Danh sách các ngắt mô tả như sau:  
STT  
00h  
Địa chỉ  
Chức năng  
0000h – 0003h  
0004h – 0007h  
CPU: chia cho 0  
CPU: thực hiện từng lệnh  
01h  
02h  
0008h – 000Bh CPU: Lỗi RAM  
03h  
000Ch – 000Fh CPU: thực hiện đến điểm dừng  
04h  
0010h – 0013h  
0014h – 0017h  
CPU: tràn số  
05h  
In trang màn hình (Print Screen)  
06h, 07h  
08h  
0018h – 001Fh Dành riêng  
0020h – 0023h  
0024h – 0027h  
IRQ0: ngắt đồng hồ (18.2 lần / giây)  
IRQ1: ngắt bàn phím  
09h  
0Ah  
0Bh  
0Ch  
0Dh  
0028h – 002Bh IRQ2: Dành riêng  
002Ch – 002Fh IRQ3: Giao tiếp nối tiếp 1  
0030h – 0033h  
0034h – 0037h  
IRQ4: Giao tiếp nối tiếp 2  
IRQ5: Đĩa cứng  
Phạm Hùng Kim Khánh  
Trang 36  
Tài liệu Lập trình hệ thống  
Chương 2  
0Eh  
0Fh  
10h  
11h  
12h  
13h  
14h  
15h  
16h  
17h  
18h  
19h  
1Ah  
1Bh  
1Ch  
1Dh  
1Eh  
1Fh  
20h  
21h  
22h  
23h  
24h  
25h  
26h  
27h  
0038h – 003Bh IRQ6: Đĩa mềm  
003Ch – 003Fh IRQ7: Máy in  
0040h – 0043h  
0044h – 0047h  
BIOS: màn hình  
BIOS: xác định cấu hình máy tính  
0048h – 004Bh BIOS: xác định kích thước RAM  
004Ch – 004Fh BIOS: truy nhập đĩa cứng / đĩa mềm  
0050h – 0053h  
0054h – 0057h  
BIOS: truy nhập giao tiếp nối tiếp  
BIOS: truy nhập cassette hay mở rộng ngắt  
0058h – 005Bh BIOS: kiểm tra bàn phím  
005Ch – 005Fh BIOS: truy nhập máy in  
0060h – 0063h  
0064h – 0067h  
Chương trình xâm nhập ROM BASIC  
BIOS: khởi động hệ thống (khi nhấn Ctrl-Alt-Del)  
0068h – 006Bh BIOS: đọc / ghi ngày / giờ  
006Ch – 006Fh Nhấn phím Break  
0070h – 0073h  
0074h – 0077h  
Gọi sau INT 08h  
Địa chỉ bảng tham số màn hình  
0078h – 007Bh Địa chỉ bảng tham số đĩa mềm  
007Ch – 007Fh Địa chỉ bảng font có ký tự mở rộng  
0080h – 0083h  
0084h – 0087h  
DOS: kết thúc chương trình  
DOS: gọi các hàm của DOS  
0088h – 008Bh Địa chỉ kết thúc chương trình  
008Ch – 008Fh Nhấn Ctrl-Break  
0090h – 0093h  
0094h – 0097h  
Địa chỉ chương trình xử lý lỗi  
DOS: đọc đĩa mềm / đĩa cứng  
0098h – 009Bh DOS: ghi đĩa mềm / đĩa cứng  
009Ch – 009Fh DOS: kết thúc chương trình và thường trú  
28h – 3Fh 00A0h – 00FFh Dành riêng cho DOS  
40h  
41h  
0100h – 0103h  
0104h – 0107h  
BIOS: phục vụ đĩa mềm  
Địa chỉ bảng tham số đĩa cứng 1  
Dành riêng  
42h – 45h 0108h – 0117h  
46h  
47h – 49h 011Ch – 0127h Dành cho user  
0118h – 011Bh Địa chỉ của bảng tham số đĩa cứng 2  
Phạm Hùng Kim Khánh  
Trang 37  
Tài liệu Lập trình hệ thống  
Chương 2  
4Ah  
0128h – 012Bh Hẹn giờ  
4Bh – 67h 012Ch – 019Fh Dành cho user  
68h – 6Fh 01A0h – 01BFh Không dùng  
70h  
71h  
72h  
73h  
74h  
75h  
76h  
77h  
01C0h – 01C3h IRQ8: đồng hồ thời gian thực  
01C4h – 01C7h IRQ9  
01C8h – 01CBh IRQ10  
01CCh – 01CFh IRQ11  
01D0h – 01D3h IRQ12  
01D4h – 01D7h IRQ13: từ 80x87  
01D8h – 01DBh IRQ14: đĩa cứng  
01DCh – 01DFh IRQ15  
78h – 7Fh 01E0h – 01FFh Dành riêng  
80h – F0h 0200h – 03C3h Dùng cho bộ thông dịch BASIC  
F1h – FFh 03C4h – 03FFh Không sử dụng  
3. Gọi ngắt và chặn ngắt  
Quá trình gọi ngắt từ hợp ngữ đơn giản là thực hiện lệnh INT STT_ngắt sau khi nạp  
các tham số cần thiết cho ngắt. Khi thực hiện lệnh gọi ngắt, CPU sẽ tìm kiếm trong bảng  
vector ngắt địa chỉ của chương trình phục vụ ngắt. Người sử dụng cũng có thể xây dựng môt  
chương trình cơ sở như các chương trình xử lý ngắt. Sau đó, các chương trình khác có thể  
gọi ngắt ra để sử dụng. Một chương trình có thể gọi chương trình con loại này mà không cần  
biết địa chỉ của nó.  
Như vậy, nếu muốn thay đổi ngắt, ta có thể thay đổi nội dung trong bảng vector ngắt  
để chỉ đến chương trình phục vụ do người sử dụng tự xây dựng và chương trình này sẽ được  
thực hiện khi ngắt được gọi. Để làm điều này, ta chỉ cần tìm vị trí của vector ngắt tương ứng  
trong bảng và thay đổi giá trị của nó. Điều này thực hiện được do bảng vector ngắt đặt trong  
RAM và được nạp mỗi khi khởi động hệ thống.  
Quá trình lấy và gán địa chỉ của chương trình con phục vụ ngắt có thể thực hiện  
thông qua ngắt 21h bằng các hàm sau:  
Hàm 35h: lấy địa chỉ của ngắt  
Vào: AL = số thứ tự ngắt  
Ra: ES:BX = địa chỉ của chương trình phục vụ ngắt  
Hàm 25h: gán địa chỉ của một chương trình phục vụ cho một ngắt  
Vào: AL = số thứ tự ngắt, DS:DX  
Ra: không có  
Phạm Hùng Kim Khánh  
Trang 38  
Tài liệu Lập trình hệ thống  
Chương 2  
Để thực hiện chặn một ngắt, ta cần thực hiện như sau:  
Dùng hàm 35h lấy  
địa chỉ của ngắt  
Dùng hàm 25h gán  
địa chỉ mới cho ngắt  
Dùng hàm 25h khôi  
phục lại địa chỉ cũ  
cho ngắt  
Hình 2.2 – Quá trình chặn một ngắt  
Một ví dụ cho quá trình chặn ngắt như sau:  
;*******************************************************************************  
;*  
;*  
*
LAB6-2.ASM - Assembler Laboratory ZMiTAC  
;*  
;* Sample program that converts lowercase to uppercase when key pressed  
*
;*  
;*******************************************************************************  
.MODEL SMALL  
.STACK 100h  
.CODE  
;*******************************************************************************  
;*  
Variables  
;*******************************************************************************  
old_proc  
dot_flag  
dd 0  
db 0  
; address of original interrupt handler  
; dot flag  
;*******************************************************************************  
;* 09h interrupt handler  
;*******************************************************************************  
segment_kb  
wsk_kb  
kb_buf_begin  
buffer  
EQU 40h  
EQU 1Ch  
EQU 80h  
; beggining of keyboard data segment  
; offset of pointer to keyboard buffer  
; offset of address of begining of the  
kb_buf_end  
EQU 82h  
; offset of address of end of the buffer  
keys  
PROC FAR  
;-------------------------------------------------------------------------------  
Calling of original interrupt handler  
;-------------------------------------------------------------------------------  
;
Phạm Hùng Kim Khánh  
Trang 39  
Tài liệu Lập trình hệ thống  
Chương 2  
int 60h  
;-------------------------------------------------------------------------------  
Prepare registers  
;-------------------------------------------------------------------------------  
;
push ax  
; push registers on the stack  
push bx  
push dx  
push ds  
mov ax,segment_kb  
mov ds,ax  
; address of keyboard data segment to DS  
;-------------------------------------------------------------------------------  
Read the character and check ASCII code  
;-------------------------------------------------------------------------------  
;
mov bx,ds:[wsk_kb]  
mov ax,ds:[kb_buf_begin]  
cmp bx,ax  
; actual pointer to BX  
; buffer beggining to AX  
; is the beggining of the buffer ?  
jne mid_buf  
mov bx,ds:[kb_buf_end]  
; last character is at the end of the  
buffer  
mid_buf:  
mov ax,ds:[bx-2]  
; read last character  
cmp al,'.'  
je dot_found  
; compare with dot  
; if dot  
cmp al,'Z'  
ja check_lowercase  
cmp al,'A'  
; compare with 'Z'  
; if above check lowercase  
; compare with 'A'  
; end if less  
jb keys_end  
mov dot_flag,0  
jmp keys_end  
; uppercase - clear flag  
; return  
check_lowercase:  
cmp al,'z'  
; compare with 'z'  
; end if above  
; compare with 'a'  
ja keys_end  
cmp al,'a'  
jb keys_end  
cmp dot_flag,0  
je keys_end  
; end if less  
; was dot pressed?  
; end if not  
;-------------------------------------------------------------------------------  
Change lowercase to uppercase  
;-------------------------------------------------------------------------------  
;
sub al,'a'-'A'  
mov ds:[bx-2],ax  
mov dot_flag,0  
jmp keys_end  
; sub difference between cases  
; uppercase - clear flag  
; return  
dot_found:  
mov dot_flag,1  
jmp keys_end  
; set flag  
; return  
;-------------------------------------------------------------------------------  
Pop registers and return from interrupt  
;
;-------------------------------------------------------------------------------  
keys_end:  
pop ds  
pop dx  
pop bx  
pop ax  
Phạm Hùng Kim Khánh  
Trang 40  
Tài liệu Lập trình hệ thống  
Chương 2  
iret  
keys  
ENDP  
;*******************************************************************************  
;* Main program  
;*******************************************************************************  
;-------------------------------------------------------------------------------  
;
Get interrupt  
;-------------------------------------------------------------------------------  
start  
proc  
mov ah,35h  
mov al,09h  
; function 35h - read handler address  
; of interrupt 09h  
int 21h  
mov word ptr old_proc,bx  
mov word ptr old_proc+2,es  
push cs  
; store 32-bit address  
; of original interrupt handler  
pop ds  
mov dx,offset keys  
mov ah,25h  
; handler code segment to DS  
; offset of handler address to DX  
; function 25h - set new handler  
; of interrupt 09h  
mov al,09h  
int 21h  
mov dx,word ptr old_proc+2  
mov ds,dx  
mov dx,word ptr old_proc  
mov ah,25h  
mov al,60h  
; function 25h - set new adress  
; of original interrupt handler  
; 60h instead of 09h  
int 21h  
;-------------------------------------------------------------------------------  
Main loop  
;-------------------------------------------------------------------------------  
;
looping:mov ah,08h  
; function 08h - read character  
; ASCII code is returned in AL  
; ESC  
; if ESC end of the loop  
; not ESC - move char to DL  
; function 02h - display character  
; ASCII code of char in DL  
int 21h  
cmp al,1Bh  
je ending  
mov dl,al  
mov ah,02h  
int 21h  
jmp looping  
;-------------------------------------------------------------------------  
ending: mov dx,word ptr old_proc+2  
mov ds,dx  
mov dx,word ptr old_proc  
mov ah,25h  
mov al,09h  
int 21h  
; function 25h - set old handler  
; of interrupt 09h  
mov ah,4Ch  
int 21h  
endp  
; end of the program  
start  
END  
start  
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é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ạm Hùng Kim Khánh  
Trang 41  
Tài liệu Lập trình hệ thống  
Chương 2  
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 Hùng Kim Khánh  
Trang 42  
Tài liệu Lập trình hệ thống  
Chương 2  
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_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.  
Phạm Hùng Kim Khánh  
Trang 43  
Tài liệu Lập trình hệ thống  
Chương 2  
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 để  
xác định ID của luồng hiện hành.  
Phạm Hùng Kim Khánh  
Trang 44  
Tài liệu Lập trình hệ thống  
Chương 2  
Phạm vi thực hiện của hàm câu móc mô tả như sau:  
Hook  
WH_CALLWNDPROC  
WH_CBT  
Phạm vi  
Luồng hay hệ thống  
Luồng hay hệ thống  
Luồng hay hệ thống  
Luồng hay hệ thống  
Hệ thống  
WH_DEBUG  
WH_GETMESSAGE  
WH_JOURNALRECORD  
WH_JOURNALPLAYBACK Hệ thống  
WH_FOREGROUNDIDLE Luồng hay hệ thống  
WH_SHELL  
Luồng hay hệ thống  
Luồng hay hệ thống  
Luồng hay hệ thống  
Luồng hay hệ thống  
Hệ thống  
WH_KEYBOARD  
WH_MOUSE  
WH_MSGFILTER  
WH_SYSMSGFILTER  
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.  
- Khác: không cho phép do bảo mật của hệ thống hay bộ nhớ tràn.  
Phạm Hùng Kim Khánh  
Trang 45  
Tài liệu Lập trình hệ thống  
Chương 2  
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)  
Phạm Hùng Kim Khánh  
Trang 46  
Tài liệu Lập trình hệ thống  
Chương 2  
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  
ByVal lParam)  
=
CallNextHookEx(hHook, idHook, wParam,  
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  
ByVal lParam)  
=
CallNextHookEx(hHook, idHook, wParam,  
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)  
End Sub  
Private Sub Form_Unload(Cancel As Integer)  
Phạm Hùng Kim Khánh  
Trang 47  
Tài liệu Lập trình hệ thống  
Chương 2  
'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ẻ.  
Phạm Hùng Kim Khánh  
Trang 48  
pdf 15 trang myanh 28180 Free
Bạn đang xem tài liệu "Tài liệu Lập trình hệ thống - Chương 2: Ngắt và sự kiện", để tải tài liệu gốc về máy hãy click vào nút Download ở trên

File đính kèm:

  • pdftai_lieu_lap_trinh_he_thong_chuong_2_ngat_va_su_kien.pdf