Cấu trúc TEXTMETRIC chứa thông tin căn bản về font vật lý. Tất cả các
kích thước được đưa ra trong các đơn vị luận lý tức là chúng phụ thuộc vào chế độ
ánh xạ hiện hành ngữ cảnh màn hình.
138 trang |
Chia sẻ: lylyngoc | Lượt xem: 2459 | Lượt tải: 0
Bạn đang xem trước 20 trang tài liệu Đề tài Nghiên cứu các phương pháp nhận dạng từ dưới cursor mouse trên Desktop Windows, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
ải dùng phông chữ (font) để xuất văn bản.
Font là một đối tượng của GDI dùng để định nghĩa những ký tự để xuất ra trong
một chương trình Windows. Font thường là một căn cứ dữ liệu họa tiết mô tả hình
dáng và kích thước của mỗi chữ cái, số và dấu. Mỗi thiết bị GDI đều có thể hỗ trợ
được một hoặc nhiều font.
II – Các hàm căn bản để kết xuất văn bản:
Cũng như các đối tượng GDI khác, font cũng phải được sử dụng với một DC
và bị ảnh hưởng bởi tình trạng hiện hành của DC này như mapping mode, màu sắc.
Trong Win 16bit mà đại diện là Windows 3.X thì có 5 hàm chủ yếu để kết
xuất văn bản, đó là: TextOut(), ExtTextOut(), DrawText(), TabbedTextOut() và
cuối cùng là GrayString().
Trong đó:
- TextOut(): xuất một chuỗi ký tự lên một DC được chỉ định sử dụng font
chữ hiện được chọn.
- ExtTextOut(): xuất một chuỗi ký tự trong một hình chữ nhật sử dụng font
chữ hiện được chọn, vùng chữ nhật này có thể bị opaque tức là bị tô đầy bởi
màu nền hiện hành hoặc có thể là một vùng xén (clipping region).
- DrawText(): xuất văn bản được định dạng trong một hình chữ nhật, hàm
có thể suy diễn 4 ký tự như là những ký tự điều khiển: carriage return (CR),
linefeed (LF), space, tab và có thể canh phải, canh trái, canh giữa.
- TabbedTextOut(): xuất chuỗi ký tự lên một DC được chỉ định sử dụng
font chữ hiện hành và cho bung những điểm canh cột (tab) theo những cột
được khai báo.
- GrayString(): xuất một hàng văn bản bị làm mờ tại một vị trí chỉ định.
Thường được áp dụng để báo là đối tượng đó bị vô hiệu hóa (disabled).
Trong các hàm trên thì chỉ có 2 hàm TextOut() và ExtTextOut() là thuộc
GDI.EXE còn 3 hàm còn lại đều là thành phần của Windows Manager tức là thuộc
USER.EXE. Trên thực tế là hầu như các dòng văn bản được hiển thị trên màn hình
của Windows 3.X đều được xuất bởi 2 hàm TextOut và ExtTextOut, vì các hàm còn
lại cũng gọi vào 2 hàm này để vẽ ra, và vì vậy trong chương trình chúng tôi cũng
chỉ tiến hành override 2 hàm này và trong phần này chúng tôi xin giới thiệu chi tiết
2 hàm TextOut(), ExtTextOut().
1 - Hàm TextOut:
- Là hàm kết xuất văn bản đơn giản nhất của GDI dùng để xuất một dòng văn
bản đơn tại vị trí (spx,spy) sử dụng font chữ được chọn.
- Cú pháp:
TextOut( HDC hdc,
Int spx,
Int spy,
LPCTSTR lpszString,
Int cbString
);
- Thông số:
hdc handle của DC
spx, spy tọa độ logic cho biết điểm điều khiển (control point) dùng canh vị
trí khởi đi của dòng văn bản. Điểm điều khiển là một vị trí trong hệ
tọa độ được định nghĩa trong DC. Với hệ tọa độ MM_TEXT thì
đơn vị tính là pixels.
lpszString con trỏ chỉ tới chuỗi ký tự không có ký tự kết thúc là ký tự
rỗng.
nString số ký tự (số byte) trong chuỗi văn bản.
- Mặc định GDI canh dòng văn bản về góc trái-trên ở điểm điều khiển (spx,spy).
- Giá trị trả về: hàm trả về khác 0 nếu thành công, ngược lại trả về 0.
2 - Hàm Windows API ExtTextOut:
- Tương tự hàm TextOut hàm này cũng sẽ vẽ một dòng văn bản đơn nhưng
thêm một số chức năng tùy chọn sau: điều khiển chiều rộng ký tự, một vùng chữ
nhật làm việc cắt xén, một vùng chữ nhật tô đục. Tùy theo yêu cầu mà lựa chọn.
- Cú pháp:
ExtTextOut (
HDC hdc,
Int spx,
Int spy,
UINT fuOptions,
CONST RECT* lpRect,
LPCTSTR lpszString,
Int cbString,
CONST INT* lpDxWidths );
- Thông số:
hdc handle của DC
spx,spy tọa độ logic cho biết điểm điều khiển (control point) dùng canh vị
trí khởi đi của dòng văn bản. Điểm điều khiển là một vị trí trong
hệ tọa độ được định nghĩa trong DC. Với hệ tọa độ MM_TEXT thì
đơn vị tính là pixel.
fuOptions cờ hiệu cho biết hàm sẽ sử dụng hình chữ nhật do ứng dụng cung
cấp như thế nào, các giá trị có thể là 0, ETO_CLIPPED,
ETO_OPAQUE hoặc kết hợp.
+ ETO_CLIPPED: dòng văn bản được xén vào hình chữ nhật được
trỏ tới bởi lpRect.
+ ETO_APAQUE: màu nền hiện hành tô đầy hình chữ nhật
lpRect con trỏ chỉ cấu trúc RECT cho biết kích thước của hình chữ nhật
dùng clipping, opaquing hoặc cả hai tùy theo giá trị của nOptions.
lpszString con trỏ chỉ tới chuỗi ký tự không có ký tư kết thúc là ký tự rỗng.
cbString số ký tự trong chuỗi văn bản.
lpDxWidths con trỏ chỉ về bản dãy những trị cho biết khoảng cách các ký
tự, nếu NULL thì dùng các giá trị có sẵn.
- Hàm TextOut sử dụng khoảng cách giữa các ký tự mặc định của các font.
ExtTextOut cho phép điều chỉnh độ rộng của từng ký tự được đặc tả trong mảng số
nguyên .
- Giá trị trả về: hàm trả về khác 0 nếu thành công, ngược lại trả về 0.
3 – Thuộc tính kết xuất văn bản của DC:
Gồm có 6 thuộc tính DC ảnh hưởng đến hình dáng và vị trí của văn bản khi
kết xuất:
- Background Color: màu nền của văn bản
- Background Mode: cho ON/OFF màu nền
- Font: kiểu văn bản và kích thước văn bản
- Intercharacter Spacing: số pixel thêm vào giữa các ký tự để canh văn bản
- Text Alignment: mối quan hệ giữa văn bản với điểm xuất phát
- Text Color: màu chữ văn bản
Trong phạm vi đề tài chúng tôi chỉ quan tâm đến những đặc tính được định
lượng bằng đơn vị pixel chứ không quan tâm đến các thuộc tính về màu sắc.
a) Hàm GetTextMetrics:
- Các thông số trong cấu trúc dữ liệu TEXTMETRIC tức là toàn bộ các giá trị
đo lường một font chữ vật lý. Muốn lấy được các giá trị này sử dụng hàm
GetTextMetrics()
- Cú pháp:
BOOL GetTextMetrics(hdc, lptm)
HDC hdc;
TEXTMETRIC FAR* lptm;
- Lấy các giá trị font chữ vật lý của một DC, đặt vào cấu trúc TEXTMETRIC.
- Thông số:
hdc handle của DC
lptm trỏ tới cấu trúc TEXTMETRIC nhận các giá trị
- Giá trị trả về: hàm trả về khác 0 nếu thành công, ngược lại trả về 0
Trong các giá trị được chứa trong cấu trúc TEXTMETRIC thì chúng tôi chỉ
quan tâm tới thông số tmAveCharWidth có kiểu dữ liệu LONG, thông số này là độ
rộng trung bình tính bằng pixel của một ký tự của font chữ thường được đại diện
bởi độ rộng của ký tự “x”.
Sau đây là cấu trúc TEXTMETRIC là cấu trúc chứa thông tin căn bản về font
vật lý. Tất cả kích thước được đưa ra trong các đơn vị logic tức là chúng phụ thuộc
vào chế độ ánh xạ hiện hành của ngữ cảnh màn hình.
Cú pháp:
typedef struct tagTEXTMETRIC
{
int tmHeight;
int tmAscent;
int tmDescent;
int tmInternalLeading;
int tmExternalLeading;
int tmAveCharWidth;
int tmMaxCharWidth;
int tmWeight;
BYTE tmItalic;
BYTE tmUnderlined;
BYTE tmStruckOut;
BYTE tmFirstChar;
BYTE tmLastChar;
BYTE tmDefaultChar;
BYTE tmBreakChar;
BYTE tmPitchAndFamily;
BYTE tmCharSet;
int tmOverhang;
int tmDigitizedAspectX;
int tmDigitizedAspectY;
} TEXTMETRIC;
- Thông số:
int tmHeight Chiều cao toàn phần của cỡ chữ
(= tmAscent + tmDescentmembers)
int tmAscent Chiều cao phần trên đường cơ sở
int tmDescent Chiều cao phần ở dưới đường cơ sở
int tmInternalLeading Chiều cao phần nhô lên của cỡ chữ, ví dụ như dấu
^ của chữ ô
int tmExternalLeading Khoảng cách giữa các dòng văn bản
int tmAveCharWidth Độ rộng trung bình của các ký tự trong font, với
những font ANSI_CHARSET là độ rộng trung bình của
tất cả các ký tự từ “a” đến “z”, với các tập ký tự khác là giá trị trung bình
không trọng lượng của mọi ký tự ở trong font
int tmMaxCharWidth Độ rộng của ký tự rộng nhất trong font
int tmWeight Độ “nặng” (bão hòa) cỡ chữ, các giá trị có thể là:
FW_DONTCARE 0
FW_THIN 100
FW_EXTRALIGHT 200
FW_ULTRALIGHT 200
FW_LIGHT 300
FW_NORMAL 400
FW_REGULAR 400
FW_MEDIUM 500
FW_SEMIBOLD 600
FW_DEMIBOLD 600
FW_BOLD 700
FW_EXTRAB OLD 800
FW_ULTRABOLD 800
FW_BLACK 900
FW_HEAVY 900
BYTE tmItalic Khác 0 nếu chữ nghiêng
BYTE tmUnderlined Khác 0 nếu chữ có gạch dưới
BYTE tmStruckOut Khác 0 nếu chữ bị gạch giữa thân
BYTE tmFirstChar Ký tự đầu tiên của font
BYTE tmLastChar Ký tự cuối cùng của font
BYTE tmDefaultChar Ký tự mặc định để thay thế
BYTE tmBreakChar Ký tự dùng để ngăn cách giữa các từ
BYTE tmPitchAndFamily Kiểu và họ của font, 4 bit thấp là kiểu font
với các giá trị:
TMPF_FIXED_PITCH
TMPF_VECTOR
TMPF_TRUETYPE
TMPF_DEVICE
FF_DECORATIVE
FF_DONTCARE
FF_MODERN
FF_ROMAN
FF_SCRIPT
FF_SWISS
BYTE tmCharSet Tập ký tự của font, với các giá trị có thể là:
ANSI_CHARSET 0
DEFAULT_CHARSET 1
SYMBOL_CHARSET 2
SHIFTJIS_CHARSET 128
OEM_CHARSET 255
int tmOverhang Độ rộng thêm vào đối với những font đặc biệt
int tmDigitizedAspectX Hướng ngang của thiết bị mà font được thiết kế
int tmDigitizedAspectY Hướng theo chiều đứng của thiết bị mà font được
thiết kế
b) Hàm GetTextExtent:
- Kích thước của dòng văn bản (dimensions): tức là chiều cao và chiều rộng
của dòng văn bản sử dụng font hiện hành. Có nhiều hàm để lấy giá trị này nhưng
chúng tôi dùng hàm GetTextExtent().
- Cú pháp:
DWORD GetTextExtent(hdc, lpszString, cbString)
HDC hdc;
LPCSTR lpszString;
int cbString;
- Tính kích thước của dòng văn bản (dimensions): tức là chiều cao và chiều
rộng của dòng văn bản sử dụng font hiện hành. Khi tính kích thước thì hàm
GetTextExtent() cũng tính luôn những khoảng trắng được thêm vào bởi hàm
SetTextCharacterExtra().
- Thông số:
hdc handle của DC
lpszString Trỏ tới chuỗi văn bản
cbString Số byte của chuỗi
- Giá trị trả về: Hàm trả về giá trị DWORD chứa kích thước cửa một dòng văn
bản trong đó byte thấp chứa bề rộng của chuỗi và byte cao chứa chiều cao của chuỗi
tính bằng đơn vị logic.
* Khung chữ nhật bao dòng text (bounded-rectangle): Là khung chữ nhật nhỏ
nhất bao trọn hình ảnh dòng text bên trong, nó có các cạnh tiếp xúc với các điểm
ảnh xa nhất ở 4 hướng (trên, dưới, trái, phải). Bằng kết quả trả về từ
GetTextExtent, ta có thể tính ra khung chữ nhật này dễ dàng. Khung chữ nhật này
có thể dùng để tính xem một điểm nào đó có nằm trong dòng text không.
c) Hàm GetTextAlign:
- Thuộc tính canh văn bản (Text Alignment): cho phép ta thay đổi mối tương
quan giữa điểm xuất phát tọa độ thường được chuyển cho hàm kết xuất văn bản
(như các hàm TextOut() và ExtTextOut()) và đoạn văn bản phải kết xuất. GDI cho
phép đặt các cờ hiệu canh văn bản bằng hàm SetTextAlign() và hàm
GetTextAlign() để đi tìm trị của các cờ hiệu canh văn bản.
- Như vậy muốn xác định vị trí chính xác của một ký tự so với điểm xuất dòng
văn bản thì ta nhất thiết phải tìm cho được những giá trị cờ hiệu được đặt bởi hàm
SetTextAlign() bởi vì các hàm này quyết định việc canh dòng văn bản được xuất ra
bởi các hàm kết xuất văn bản, để đáp ứng yêu cầu đó ta sử dụng hàm
GetTextAlign():
- Cú pháp:
UINT GetTextAlign(hdc)
HDC hdc;
- Thông số:
hdc handle của DC
- Giá trị trả về: hàm này trả về trạng thái các cờ canh văn bản, có thể có một
hoặc nhiều cờ phối hợp với nhau. Có 9 loại cờ canh văn bản mang các giá trị là:
TA_BASELINE y-coordinate đặt tại đường baseline.
TA_TOP y-coordinate đặt tại cạnh trên khung chữ nhật bao dòng
text (bounded-rectangle) (default)
TA_BOTTOM y-coordinate đặt tại cạnh dưới khung chữ nhật bao dòng
text (bounded-rectangle)
TA_LEFT x-coordinate đặt tại cạnh cạnh trái bounded-rectangle
(default)
TA_CENTER x-coordinate đặt ngay giữa 2 cạnh bounded-rectangle
TA_RIGHT x-coordinate đặt tại cạnh phải bounded-rectangle
TA_NOUPDATECP Dùng x; y-coordinate của TextOut; ExtTextOut để vẽ,
không quang tâm đến CP (default)
TA_UPDATECP Không quan tâm x; y-coordinate, thay thế bởi toạ độ
CP hiện tại, sau khi vẽ xong thì cập nhật CP.
* CP - current position: Mỗi DC định nghĩa một CP để dùng trong các trường
hợp tọa độ không chỉ định rõ hoặc vẽ các đối tượng liên tiếp nhau. Ví dụ dùng CP
và hàm LineTo để vẽ poly-line.
d) Hàm GetTextCharacterExtra:
- Thuộc tính Intercharacter Spacing: cho phép ta cộng thêm một số pixel vào
giữa các ký tự của dòng văn bản, những pixel thêm vào này gọi là Extra pixel. Sử
dụng hàm SetTextCharacter() được cung cấp bởi GDI để đặt khoảng cách giữa các
ký tự. Như vậy muốn lấy khoảng cách này giữa các ký tự của dòng văn bản được
xuất ra thì sử dụng hàm GetTextCharacterExtra().
- Cú pháp:
int GetTextCharacterExtra(hdc)
HDC hdc;
- Giá trị trả về: Hàm trả về giá trị xác định số lượng khoảng trắng thêm vào
giữa các ký tự nếu hàm thành công.
- Giá trị mặc định là 0.
4 - Tọa độ trong kết xuất văn bản:
Trong 5 hàm kết xuất văn bản: TextOut(), ExtTextOut(), TabbedTextOut(),
DrawText() và GrayString() thì tọa độ để xuất dòng văn bản ra được tính bằng đơn
vị logic. Trong khi đó một số hàm để lấy các đặc tính DC của các dòng văn bản
được xuất đó lại được tính bằng nhiều đơn vị khác nhau, lúc thì tính bằng đơn vị
logic, lúc thì lại được tính bằng các loại tọa độ thiết bị khác nhau. Ngoài ra, đơn vị
tính của vị trí cursor mouse lại được tính bằng hệ toạ độ thiết bị toàn màn hình nên
trong quá trình tính toán chúng ta cần lưu ý để chuyển tất cả chúng về cùng một hệ
tọa độ để phần tính toán được chính xác.
a) Hàm GetDCOrg:
- Hàm GetDCOrg() lấy tọa độ origin dịch cuối cùng cho DC, hoặc nói cách
khác là toạ độ (thiết bị) của gốc toạ độ logic của DC. Kết quả trả về dùng làm offset
để chuyển tọa độ client thành tọa độ thiết bị của các điểm trong cửa sổ một ứng
dụng. Origin dịch cuối cùng liên quan với origin vật lý của màn hình.
- Cú pháp:
DWORD GetDCOrg(hdc)
HDC hdc;
- Thông số hdc là handle của DC mà origin của nó được lấy.
- Giá trị trả về: Trả về giá trị trong đó word thấp chứa tọa độ x, word cao chứa
tọa độ y của origin dịch cuối cùng trong tọa độ thiết bị.
b) Hàm PtInRect:
- Hàm PtInRect() xác định điểm có nằm bên trong hình chữ nhật hay không.
Chú ý rằng một điểm được coi là thuộc hình chữ nhật khi nó nằm ở trên cạnh trái,
nằm ở trên cạnh trên hoặc nằm hoàn toàn trong hình chữ nhật, ngược lại một điểm
không thuộc hình chữ nhật khi nó nằm ở bên ngoài, nằm ở trên cạnh phải hoặc nằm
ở trên cạnh dưới của hình chữ nhật.
- Cú pháp:
BOOL PtInRect(lprc, pt)
const RECT FAR* lprc;
POINT pt;
- Thông số:
lprc trỏ tới địa chỉ hình chữ nhật
pt cấu trúc điểm
- Giá trị trả về: trả về khác 0 nếu có điểm thuộc cửa sổ, ngược lại trả về 0.
Chương 5:
PHÂN TÍCH VÀ THIẾT KẾ CHƯƠNG TRÌNH
I - Phân tích vấn đề:
1 - Ý tưởng dẫn đến giải thuật:
- Mục đích yêu cầu của đề tài là: "Nhận dạng từ dưới cursor mouse trên
desktop window". Có nghĩa là tại một vị trí bất kỳ nào đó của cursor mouse trên
màn hình Windows nếu có một tác động chuột quy định trước (chẳng hạn như click
nút phải của chuột) thì phải lấy được từ ở ngay dưới vị trí cursor (nếu có), hoặc xuất
ra thông báo cho biết không có từ nào nằm ngay dưới vị trí cursor đang đứng.
- Có 2 dạng thể hiện văn bản trên màn hình Windows, đó là:
* Thể hiện dưới dạng ảnh, dùng hàm kết xuất và xử lý ảnh
* Thể hiện dưới dạng chuỗi văn bản, dùng hàm kết xuất văn bản
- Đối với dạng thể hiện ảnh, văn bản chỉ là tập các điểm ảnh của bức ảnh,
chẳng có ý nghĩa gì khác đối với Windows, nên nếu muốn trích văn bản ra chỉ có
một cách là xử lý ảnh, điều này thực sự là một vấn đề hay và có nhiều ứng dụng
thực tiễn: như nhận dạng một trang giấy được scan vào máy để tạo ra file text tương
ứng thay cho việc đánh máy lại trang giấy đó. Tuy nhiên nó là vấn đề hết sức phức
tạp có sai số nhất định, và tùy thuộc vào font chữ mà văn bản thể hiện, trong khi đó
có một cách khác để lấy được chính xác các dòng text trên màn hình.
- Đối với dạng thể hiện văn bản bằng các hàm kết xuất văn bản: Ứng dụng sẽ
gởi cho Windows chuỗi văn bản cần thể hiện và các thông số cần thiết, và Windows
dùng các hàm kết xuất văn bản để vẽ chuỗi văn bản đó ra màn hình. Từ cách kết
xuất đó đã nảy sinh một ý tưởng về việc nhận dạng các dòng text trên màn hình: là
nếu ta có thể khống chế các hàm kết xuất văn bản, lấy về các thông tin của các hàm
này, thì vấn đề có thể thực hiện được mà không cần phải xử lý ảnh.
* Từ sự phân tích đó chúng tôi đã chọn giải thuật dựa vào sự khống chế các
hàm xuất văn bản của Windows, và cũng may mắn là hầu như tất cả dòng văn bản
kết xuất ra màn hình đều dùng dạng kết xuất dùng hàm kết xuất văn bản, nên nếu
thực hiện hoàn hảo ý tưởng nói trên thì vấn đề được giải quyết gần như hoàn toàn.
2 - Phân tích vấn đề:
Để thực hiện được các ý tưởng trên, cần phải thực hiện các việc sau:
- Override các hàm kết xuất văn bản của Windows để khống chế việc kết xuất
văn bản ra màn hình.
- Tạo một cái bẫy sự kiện chuột để khi sự kiện chuột quy định xảy ra sẽ dẫn vào
phần xử lý lấy text của chương trình. Chú ý là trong phần xử lý này phải có cách
nào đó để khiến Windows vẽ lại các dòng text, có như vậy thì hàm override kết xuất
văn bản mới vớt được các thông tin, và in kết quả vào cửa sổ ứng dụng của chương
trình chính.
- Có một đoạn chương trình để phân tích dòng văn bản, để tách lấy từ ra.
- Chương trình chính làm điểm bắt đầu / kết thúc chương trình, và enable /
disable việc trích lấy từ (bẫy sự kiện chuột).
II – Thiết kế chương trình:
Từ những phân tích trên chúng tôi thiết kế chương trình như sau:
- Tổ chức làm 2 projects:
GETTEXT.MAK: Là chương trình chính, tạo khung giao diện và xử
lý menu. Khi biên dịch sẽ là GETTEXT.EXE
GTDLL.MAK : Chứa các hàm và biến nhớ thực hiện việc cài đặt / gỡ bỏ
bẫy sự kiện chuột; cài đặt / gỡ bỏ override; hàm
override; hàm trích từ... Nói chung là tất cả phần xử lý
còn lại. Khi biên dịch sẽ là GTDLL.DLL
- Các hàm trong chương trình bao gồm:
+ GETTEXT.WinMain : Chương trình chính
+ GETTEXT.MenuWndProc: Hàm xử lý thông điệp của chương trình
chính.
+ GTDLL.InstallMouseFilter : Hàm cài đặt / gỡ bỏ mouse-hook để bẫy
và xử lý sự kiện chuột.
+ GTDLL.MouseFunc : Hàm xử lý mouse-hook, thay cho MouseProc
+ GTDLL.InstallOverrideAPI : Hàm cài đặt override hàm TextOut;
ExtTextout
+ GTDLL.RemoveOverrideAPI : Hàm gỡ bỏ override 2 hàm xuất text
+ GTDLL.TextOutEx : Hàm override của TextOut
+ GTDLL.ExtTextOutEx : Hàm override của ExtTextOut
+ GTDLL.GetWordUnderPoint : Hàm phân tích và trích từ ra khỏi dòng
văn bản
- Các biến toàn cục chủ yếu bao gồm:
+ GTDLL.hwndMain : Handle cửa sổ chính của application, dùng để in
kết quả vào cửa sổ chính.
+ GTDLL.hMod : Handle toàn cục của instance DLL
+ GTDLL.mousePos : Vị trí chuột cần lấy text.
+ GTDLL.searched : Chiều dài text tìm thấy
+ GTDLL.mWordUnderPoint : Kết quả-từ lấy được
+ GTDLL.MouseHookHandle : Hook handles
- Các hàm chủ yếu được trình bày qua những lưu đồ sau:
Voøng loop baét thoâng ñieäp: Daãn vaøo haøm xöû lyù
thoâng ñieäp cuûa chöông trình: MenuWndProc
Caøi ñaët giao dieän chöông trình töø RESOURCE vaø ñaêng kyù
lôùp cöûa soå öùng duïng môùi cho chöông trình (haøm MenuInit):
- Cöûa soå öùng duïng
- Menu
Thoaùt?
(WM_QUIT)
KEÁT THUÙC
LÖU ÑOÀ CUÛA CHÖÔNG TRÌNH CHÍNH
Taïo cöûa soå chöông trình
Xöû lyù thoâng ñieäp
(haøm MenuWndProc)
Yes
No
Löu handle cöûa soå chöông trình vaøo DLL (haøm InitHookDll),
ñeå caùc haøm trong DLL coù theå caäp nhaät cöûa soå chöông trình
Boû ñaêng kyù lôùp cöûa soå öùng duïng
BAÉT ÑAÀU
BAÉT ÑAÀU
Trích töø ra baèng caùc thoâng tin trong parameter cuûa
TextOut(); ExtTextOut() (goïi haøm GetWordUnderPoint):
- hDC
- Vò trí cursor
- Toaï ñoä chuoãi in ra
- Chuoãi text ñöôïc in
- Ñoä daøi chuoãi text ñöôïc in
- TEXTMETRIC hieän haønh
Ñaõ laáy ñöôïc töø naøo chöa?
(bieán searched)
Goïi RemoveOverrideAPI()
KEÁT THUÙC
LÖU ÑOÀ HAØM OVERRIDE TextOut & ExtTextOut
(GTDLL.DLL : TextOutEx & ExtTextOutEx)
No
Yes
Goïïi haøm TextOut(); ExtTextOut() chuaån
ñeå in ra doøng text nhö bình thöôøng
Goïïi InstallOverrideAPI()
Baét ñaàu
Naïp module thö vieän GDI.EXE
Haøm LoadLibrary()
handle<HINSTANCE_ERROR
-Laáy ñieåm nhaäp haøm API TextOut,ExtTextOut
Haøm GetProcAddress()
-Laáy segment selector vaø ñòa chæ offset cuûa haøm
API. Macro SELECTOROF vaø OFFSETOF
-Giaûi phoùng thö vieän GDI.EXE ñaõ naïp
Teân haøm=("TextOut" | "ExtTextOut)
-Laáy ñòa chæ logic cuûa haøm override TextOutEx(),
ExtTextOutEx. Haøm MakeProcInstance()
-Giaûi phoùng haøm override khoûi segment giôùi haïn noù
Haøm FreeProcInstance()
-Laáy boä choïn phaân ñoïan vaø ñòa chæ offset haøm override
-Ñoåi töø code selector cuûa haøm API sang data selector
Haøm PrestoChangoSelector()
Baùo loãi
Baùo loãi
No
Yes
No
Yes
LÖU ÑOÀ HAØM INSTALL OVERRIDE
( GTDLL.DLL : InstallOverrideAPI )
LÖU ÑOÀ HAØM GÔÕ BOÛ OVERRIDE
(GTDLL.DLL : RemoveOverrideAPI)
Baét ñaàu
Naïp module thö vieän GDI.EXE
(Haøm LoadLibrary)
handle < HINSTANCE_ERROR
- Laáy ñieåm nhaäp haøm API TextOut(),ExtTextOut()
(Haøm GetProcInstance() )
- Laáy segment selector vaø ñòa chæ offset cuûa haøm API
(Macro SELECTOROF(), OFFSETOF() )
- Giaûi phoùng thö vieän GDI.EXE ñaõ naïp
(Haøm FreeLibrabry() )
- Ñoåi töø code selector cuûa haøm API sang data selector
(Haøm PrestoChangoSelector() )
- Ghi leân 5 byte ñaàu cuûa haøm API baèng ñoaïn code assembly
- Ñoåi trôû laïi töø data selector sang code selector haøm API
Keát thuùc
Baùo loãi
Baùo loãi
Yes
No
Yes
NoTeân haøm = ("TextOut" |
"ExtTextOut")?
nCode=1
(caøi ñaët)
KEÁT THUÙC
LÖU ÑOÀ HAØM CAØI ÑAËT / GÔÕ BOÛ MOUSEHOOK
(GTDLL - InstallMouseFilter)
Yes
BAÉT ÑAÀU
MouseHooking=1
(Hook ñaõ caøi roài)
MouseHooking=0
(Hook chöa caøi)
Caøi ñaët hook, duøng haøm
SetWindowsHookEx
Gôõ boû hook, duøng haøm
UnhookWindowsHookEx
Gaùn MouseHooking = 1 Gaùn MouseHooking = 0
No
Yes Yes
No No
nCode >= 0
KẾT THÚC
LƯU ĐỒ HÀM XỬ LÝ MOUSEHOOK
(GTDLL - MouseFunc)
Yes
BẮT ĐẦU
Chuột ngoài cửa sổ ứng dụng và
thông điệp chuột là nhấn nút phải
- Cài đặt override 2 hàm TextOut và ExtTextOut
- Reset biến Searched = 0
No
Yes
No
No
Tùy vị trí chuột trên cửa sổ (xác định bởi HitTestCode) mà
phát lệnh thích hợp để bảo Windows vẽ lại vùng đó của cửa sổ:
+ Nằm trên vùng client: Lệnh RedrawWindow vùng client
+ Nằm trên thanh tiêu đề: Lệnh RedrawWindow vùng
nonclient
+ Nằm trên menubar: Lệnh DrawMenuBar
* Khi cửa sổ vẽ lại các dòng text thì các hàm override sẽ phát
huy tác dụng
Gỡ bỏ override 2 hàm TextOut và ExtTextOut
searched > 0
(tìm thấy từ)
In từ vào cửa sổ ứng dụng Thông báo không tìm thấy
Đặt thông số trả về là 1: Sự
kiện chuột đ ã xử lý hoàn tất
Gọi
CallNexHookEx
Gọi
CallNexHookEx
Yes
Bắt đầu
Chuyển toạ độ xuất text trong TextOut; ExtTextOut
từ logic qua fullscreen: hàm GetViewportOrgEx; GetDCOrg
pt nằm trong khung bao?
(dùng hàm PtInRect)
- Lấy bề rộng ký tự trung bình của font chữ hiện
tại: tmAveCharWidth (hàm GetTextMetrics)
- Tính chỉ số vị trí ký tự trong dòng text tại toạ độ
pt (mIndex) theo công thức:
mIndex=(tđộ.x pt - tđộ.x TextOut)/tmAveCharWidth
Trích từ tại vị trí vừa tính được trong chuỗi
(Xin xem lưu đồ kế tiếp)
Kết thúc
LƯU ĐỒ HÀM TRÍCH TỪ TRONG DÒNG TEXT TẠI
TỌA ĐỘ FullScreen pt (GTDLL - GetWordUnderPoint)
Tính khung bao của dòng text (hàm GetTextExtent)
Hiệu chỉnh lại vị trí khung bao và toạ độ xuất text
tùy theo giá trị của GetTextAlign như sau:
- Cập nhật CP: Gán lại toạ độ TextOut là CP
- Trái/giữa/phải: Chỉnh toạ độ trái/phải
- Đỉnh/đáy/baseline: Chỉnh toạ độ trên/dưới
Tinh chỉnh lại mIndex bằng cách:
- Tính khung bao chuỗi text từ 1 đến mIndex để
suy ra toạ độ của ký tự mIndex trên màn hình
- Xét xem pt nằm bên trái hay bên phải mIndex
- Nếu pt bên phải thì tăng mIndex rồi loop lại
cho đến khi pt qua trái.
- Nếu pt bên trái thì giảm mIndex rồi loop lại
cho đến khi pt qua phải.
Yes
N
Bắt đầu
- Từ vị trí mIndex, đặt vòng loop quét dò qua trái
- Xét xem vị trí đang dò có phải là space hoặc tab
- Vòng loop kết thúc khi dò được vị trí space hoặc
tab, hoặc dò đến vị trí đầu chuỗi (vị trí 1).
* Kết quả đạt được: Vị trí đầu của từ.
Kết thúc
LƯU ĐỒ GIẢI THUẬT TRÍCH TỪ TRONG DÒNG TEXT
TẠI VỊ TRÍ mIndex (mở rộng lưu đồ GetWordUnderPoint)
- Từ vị trí mIndex, đặt vòng loop quét dò qua phải
- Xét xem vị trí đang dò có phải là space hoặc tab
- Vòng loop kết thúc khi dò được vị trí space hoặc
tab, hoặc dò đến vị trí cuối chuỗi (chiều dài chuỗi).
* Kết quả đạt được: Vị trí cuối của từ.
- Từ vị trí đầu và vị trí cuối của từ, dễ dàng
trích từ ra bằng hàm trích chuỗi con: strncpy
III – Giới thiệu một số hàm có liên quan:
1) Hàm InvalidateRect:
Hàm InvalidateRect cộng một hình chữ nhật vào một vùng cập nhật của cửa
sổ. Vùng cập nhật đại diện cho vùng client của cửa sổ phải được vẽ lại.
- Cú pháp:
void InvalidateRect(hwnd, lprc, fErase)
HWND hwnd;
const RECT FAR* lprc;
BOOL fErase;
-Thông số:
hwnd cửa sổ mà vùng cập nhật của nó thay đổi
lprc chỉ tới địa chỉ cấu trúc RECT chứa tọa độ client của hình chữ
nhật được cộng thêm vào vùng cập nhật. Nếu NULL thì toàn
bộ vùng client được cộng vào vùng cập nhật
fErase xác định có hay không có background ở trong vùng cập nhật
bị xóa khi vùng cập nhật được xử lý. Nếu TRUE thì
background bị xóa khi BeginPaint được gọi, nếu NULL thì
background vẫn không thay đổi.
- Giá trị trả về: hàm không trả về giá trị nào cả.
2) Hàm InvalidateRgn:
Hàm InvalidateRgn cộng một vùng vào vùng cập nhật của cửa sổ. Vùng cập
nhật đại diện cho vùng client của cửa sổ phải được vẽ lại.
- Cú pháp:
void InvalidateRgn(hwnd, hrgn, fErase)
HWND hwnd;
HRGN hrgn;
BOOL fErase;
- Thông số:
hwnd cửa sổ mà vùng cập nhật của nó thay đổi
hrgn vùng được cộng vào vùng cập nhật. Vùng phải có tọa độ
client. Nếu NULL thì toàn vùng client được cộng vào vùng
cập nhật.
fErase xác định cof1 hay không background bị xóa khi vùng cập nhật
được xử lý. Nếu TRUE thì background bị xóa khi BeginPaint
được gọi. Nếu FALSE thì background vẫn không đổi.
- Giá trị trả về: hàm không trả về giá trị gì.
3) Hàm UpdateWindow:
Hàm cập nhật vùng client của cửa sổ bằng cách gởi một thông điệp
WM_PAINT trực tiếp tới cửa sổ nếu vùng cập nhật cho cửa sổ là không trống. Hàm
gởi thông điệp WM_PAINT trực tiếp tới thủ tục cửa sổ của cửa sổ bỏ qua hàng ứng
dụng. Nếu vùng cập nhật trống thì không có thông điệp nào được gởi.
- Cú pháp:
void UpdateWindow(hwnd)
HWND hwnd;
- Thông số:
hwnd cửa sổ cần cập nhật
- Giá trị trả về: hàm không trả về giá trị
4 – Hàm đặt hook SetWindowsHookEx:
- Hàm SetWindowsHookEx cài đặt một thủ tục hook định nghĩa ứng dụng vào
một chuỗi hook. Cài đặt thủ tục hook để quản lý hệ thống cho kiểu sự kiện nào đó.
Những sự kiện này được tổ chức với cả thread đặc biệt hay với cả tất cả thread trong
hệ thống.
- Cú pháp:
HHOOK SetWindowsHookEx(
Int idHook, // kiểu hook để cài đặt
HOOKPROC lpfn, // địa chỉ của thủ tục hook
HINSTANCE hMod, // handle chỉ tới thể hiện của ứng dụng
DWORD dwThreadId // nhận dạng của thread để đặt hook
);
- Các thông số:
Idhook kiểu thủ tục hook được đặt, gồm các giá trị sau:
WH_CALLWNDPROC đặt một thủ tục hook quản lý các thông điệp trước lúc
hệ thống gởi chúng tới cửa sổ đích.
WH_CALLWNDPROCRET đặt một thủ tục hook quản lý các thông điệp sau
khi chúng được xử lý bởi thủ tục cửa sổ đích.
WH_CBT đặt một thủ tục hook nhận những thông báo có ích tới ứng dụng
huấn luyện trên cơ sở tính toán (CBT).
WH_DEBUG đặt một thủ tục hook có ích cho việc debug những thủ tục hook
khác.
WH_FOREGROUNDIDLE đặt một thủ tục hook sẽ được gọi khi thread
foreground của ứng dụng sẽ trở thành không dùng đến. Hook này có ích cho hoạt
động những nhiệm vụ (task) độ ưu tiên thấp trong thời gian không được dùng đến.
WH_GETMESSAGE đặt một thủ tục hook quản lý các thông điệp được post
tới hàng thông điệp.
WH_JOURNALPLAYBACK đặt một thủ tục hook post những thông điệp
được ghi trước đó bởi thủ tục hook WH_JOURNALRECORD.
WH_JOURNALRECORD đặt một thủ tục hook ghi những thông điệp đầu vào
được post tới hàng thông điệp hệ thống. Hook này có ích cho việc ghi các macro.
WH_KEYBOARD đặt một thủ tục hook quản lý các thông điệp keystroke.
WH_KEYBOARD_LL Windows NT: đặt một thủ tục hook quản lý những sự
kiện nhập vào từ keyboard mức thấp.
WH_MOUSE đặt một thủ tục hook quản lý các thông điệp chuột.
WH_MOUSE_LL Windows NT: đặt một thủ tục hook quản lý những sự kiện
đầu vào chuột mức thấp.
WH_MSGFILTER đặt một thủ tục hook quản lý các thông điệp được kết sinh
như là một kết quả cuả sự kiện đầu vào ở trong dialog box, message box, menu hay
scroll bar.
WH_SHELL đặt một thủ tục hook quản lý các thông điệp nhận thông báo hữu
ích để shell các ứng dụng.
WH_SYSMSGFILTER đặt một ứng dụng các thông điệp được kết sinh như là
kết quả của một sự kiện đầu vào ở trong dialog box, message box, menu hay scroll
bar. Thủ tục hook quản lý những thông điệp này cho tất cả các ứng dụng trong hệ
thống.
lpfn trỏ tới thủ tục hook. Nếu dwThreadId bằng 0 hay đặc tả danh hiệu một
thread được tạo ra bởi một quá trình khác, lpfn phải chỉ tới một thủ tục hook trong
một DLL. Còn không, lpfn có thể trỏ tới một thủ tục hook trong code đươc tổ chức
với quá trình hiện thời.
hMode handle chỉ tới DLL chứa thủ tục hook được trỏ tới bởi lpfn. hMode
phải được đặt NULL nếu dwThread đặc tả một thread được tạo bởi quá trình hiện
hành và nếu thủ tục hook ở trong code được tổ chức với quá trình hiện hành.
dwThreadId đặc tả danh hiệu của thread với thủ tục hook đã được tổ chức, nếu
là 0 thì thủ tục hook được tổ chức với tất cả các thread đang tồn tại.
Giá trị trả về: là handle chỉ tới thủ tục hook nếu thành công và NULL nếu thất
bại.
- Ghi chú: lỗi có thể xảy ra nếu thông số hMode là NULL và dwThreadId = 0
hay đặc tả danh hiệu của một thread được tạo ra bởi một quá trình khác.
Tầm vực của hook phụ thuộc vào kiểu hook. Một vài hook có thể được đặt chỉ
với tầm vực hệ thống, những hook khác cũng được đặt chỉ cho một thread đặc biệt,
đây là danh sách:
Hook Tầm vực
WH_CALLWNDPROC thread hay system
WH_CALLWNDPROCRET thread hay system
WH_CBT thread hay system
WH_DEBUG thread hay system
WH_FOREGROUNDIDLE thread hay system
WH_GETMESSAGE thread hay system
WH_JOURNALPLAYBACK chỉ system
WH_JOURNALRECORD chỉ system
WH_KEYBOARD thread hay system
WH_KEYBOARD_LL thread hay system
WH_MOUSE thread hay system
WH_MOUSE_LL thread hay system
WH_MSGFILTER thread hay system
WH_SYSMSGFILTER thread hay system
WH_SHELL chỉ system
Với một loại hook đã đặc tả thì hook thread được gọi trước rồi mới đến hook
hệ thống. Hook hệ thống là những tài nguyên được chia sẻ và khi đặt một cái sẽ ảnh
hưởng lên tất cả các ứng dụng. Tất cả các hàm hook hệ thống phải ở trong các thư
viện. Hook hệ thống nên được xử lý cho những ứng dụng có mục đích đặc biệt hay
để sử dụng như là một trợ giúp (aid) đặc biệt trong khi debug ứng dụng. Các thư
viện không cần hook thì nên gở bỏ thủ tục hook.
5 - Hàm WindowFromPoint:
- Hàm này lấy handle của cửa sổ chứa điểm đã được xác định.
- Cú pháp:
HWND WindowFromPoint (
POINT Point // cấu trúc điểm
);
- Thông số:
Point : điểm được kiểm tra
- Giá trị trả về: Là một handle của cửa sổ chứa điểm. Nếu không có cửa sổ nào
chứa điểm đó thì giá trị trả về là NULL. Nếu điểm nằm trong điều khiển text tĩnh
(static text control) thì giá trị trả về là handle của cửa sổ nằm bên dưới điều khiển
text tĩnh.
- Ghi chú: Hàm WindowFromPoint không lấy một handle của một cửa sổ bị
che hay không hoạt dộng được, ngay cả nếu điểm ở trong cửa sổ. Một ứng dụng sẽ
sử dụng hàm ChildWindowFromPoint cho việc tìm kiếm không có giới hạn. Hàm
này yêu cầu tối thiểu là Windows 95, Header được khai báo trong winuser.h, sử
dụng thư viện user32.lib
6 – Hàm ChildWindowFromPoint:
- Hàm ChildWindowFromPoint xác định rõ những cửa sổ con nào thuộc về
một cửa sổ cha mẹ chứa điểm đã cho.
- Cú pháp:
HWND ChildWindowFromPoint (
HWND hWndParent, // handle của cửa sổ cha mẹ
POINT Point // cấu trúc tọa độ điểm
);
- Thông số:
hWndParent Handle của cửa sổ cha mẹ.
Point Cấu trúc POINT định nghĩa tọa độ client của điểm được
kiểm tra.
- Giá trị trả về: Là handle của cửa sổ con chứa điểm contains the point ngay cả
trong trường hợp cửa sổ con bị che hay không thể hoạt động hidden or disabled.
Nếu điểm nằm ngoài cửa sổ cha mẹ thì giá trị trả về là NULL. Nếu điểm ở trong
cửa sổ cha mẹ nhưng không ở trong bất kỳ cửa sổ con nào thì trả về handle của cửa
sổ cha mẹ.
- Ghi chú: Hệ thống duy trì danh sách nội, chứa handle các cửa sổ con được tổ
chức bằng một cửa sổ cha mẹ. Thứ tư các handle trong danh sách phụ thuộc vào trật
tự Z của những cửa sổ con. Nếu có nhiều hơn một cửa sổ con chứa điểm thì hệ
thống trả về handle của cửa sổ đầu tiên trong danh sách mà có chứa điểm. Hàm này
đòi hỏi tối thiểu Windows 95, Header: được khai báo trong winuser.h, sử dụng
Import Library user32.lib.
7 – Hàm ChildWindowFromPointEx:
- Hàm ChildWindowFromPointEx xác định rõ những cửa sổ con thuộc về cửa
sổ cha mẹ chứa điểm. Hàm có thể phớt lờ cửa sổ con không nhìn thấy, không thể
hoạt động được và trong suốt.
- Cú pháp:
HWND ChildWindowFromPointEx(
HWND hwndParent, // handle của cửa sổ cha mẹ
POINT pt, // cấu trúc tọa độ điểm
UINT uFlags // những cờ bỏ quãng
);
- Thông số:
hwndParent Handle của cửa sổ cha mẹ.
pt cấu trúc POINT định nghĩa tọa độ client của điểm được
kiểm tra.
uFlags cho biết những cửa sổ con bị bỏ, có thể kết hợp các giá
trị sau:
Giá trị Ý nghĩa
CWP_ALL Không bỏ bất kỳ cửa sổ con nào
CWP_SKIPINVISIBLE Bỏ những cửa sổ con không nhìn thấy
CWP_SKIPDISABLED Bỏ những cửa sổ con không thể hoạt động
CWP_SKIPTRANSPARENT Bỏ những cửa sổ con trong suốt
- Giá trị trả về: Là handle của cửa sổ con đầu tiên chứa điểm và bắt gặp tiêu
chuẩn (critia) được đặc tả bởi uFlags. Nếu điểm ở trong cửa sổ cha mẹ nhưng
không ở trong bất kỳ cửa sổ con nào bắt gặp tiêu chuẩn thì giá trị trả về là handle
của cửa sổ cha mẹ. Nếu điểm nằm ngoài cửa sổ cha mẹ hay nếu hàm thất bại thì giá
trị trả về là NULL.
- Ghi chú: Hệ thống duy trì một danh sách nội chứa handle của những cửa sổ
con được tổ chức bằng cửa sổ cha mẹ. Thứ tự của các handle trong danh sách phụ
thuộc vào trật tự Z của những cửa sổ con. Nếu có nhiều hơn một cửa sổ con chứa
điểm thì hệ thống trả về handle của cửa sổ đầu tiên trong danh sách chứa điểm và
bắt gặp tiêu chuẩn trong uFlags. Hàm này đòi hỏi tối thiểu Windows 95, Header:
được khai báo trong winuser.h, sử dụng Import Library user32.lib.
8 - Hàm GetWindowText:
- Hàm GetWindowText sao chép text thanh tiêu đề của cửa sổ đã được đặc tả
(nếu nó có một) vào một vùng đệm. Nếu cửa sổ được đặc tả là một điều khiển thì
text của điều khiển được sao chép. Tuy nhiên, GetWindowText không thể lấy text
của điều khiển trong một ứng dụng khác.
- Cú pháp:
int GetWindowText(
HWND hWnd, // handle của cửa sổ hay điều khiển có chứa text
LPTSTR lpString, // địa chỉ của vùng đệm cho text
int nMaxCount // số cực đại những ký tự để sao chép
);
- Thông số:
hWnd Handle của cửa sổ hay điều khiển có chứa text.
lpString Pointer chỉ tới vùng đệm sẽ nhận text.
nMaxCount số lượng cực đại các ký tự chép tới vùng đệm tính luôn
cả ký tự, NULL. Nếu đoạn text vượt quá giới hạn này
thì nó sẽ bị cắt bớt.
- Giá trị trả về: Nếu thành công thì trả về độ dài các ký tự trong chuỗi được
chép không tính ký tự rỗng cuối chuỗi. Nếu cửa sổ không có thanh tiêu đề hay đoạn
text, hay nếu thanh tiêu đề rỗng hay nếu handle của cửa sổ hoặc thanh tiêu đề không
hợp lệ thì giá trị trả về là zero. Hàm này không thể lấy đoạn text của một edit
control trong ứng dụng khác.
- Ghi chú: Nếu cửa sổ đích thuộc sở hữu bởi quá trình hiện hành, hàm
GetWindowText tạo nên thông điệp WM_GETTEXT để gởi tới điều khiển hay cửa
sổ được đặc tả. Nếu cửa sổ đích được sở hữu bởi một quá trình khác và có một đầu
đề (caption) thì hàm GetWindowText lấy phần text caption của cửa sổ. Nếu cửa sổ
không có caption thì giá trị trả về là một chuỗi rỗng. Hàm này đòi hỏi tối thiểu
Windows 95, Header: được khai báo trong winuser.h, sử dụng Import Library
user32.lib.
9 - Hàm MouseProc:
Thủ tục hook MouseProc là một hàm callback định nghĩa thư viện hay định
nghĩa ứng dụng sử dụng hàm SetWindowsHookEx. Hệ thống gọi hàm này bất cứ
khi nào một ứng dụng gọi hàm GetMessage hay PeekMessage và có một thông điệp
chuột được xử lý.
Kiểu HOOKPROC định nghĩa một pointer trỏ tới hàm callback. MouseProc là
một placeholder cho tên hàm định nghĩa ứng dụng hay tên hàm định nghĩa thư viện.
- Cú pháp:
LRESULT CALLBACK MouseProc (
Int nCode, // hook code
WPARAM wParam, // danh hiệu thông điệp
LPARAM lParam // tọa độ chuột
);
- Thông số:
nCode một code thủ tục hook sử dụng để quyết định làm thế nào để
xử lý thông điệp, có thể có giá trị:
Giá trị Ý nghĩa
HC_ACTION wParam và lParam chứa thông tin một thông điệp
chuột
HC_NOREMOVE wParam và lParam chứa thông tin một thông
điệp chuột, và thông điệp chuột không bị xóa khỏi
hàng message.
- Nếu nCode nhỏ hơn 0 thì thủ tục hook phải chuyển thông điệp tới hàm
CallNextHookEx không cần xử lý thêm và nên trả về giá trị được trả về bởi
CallNextHookEx.
wParam chứa danh hiệu của thông điệp chuột
lParam là pointer trỏ tới cấu trúc MOUSEHOOKSTRUCT
- Giá trị trả về: Nếu nCode < 0 thì trả về giá trị do CallNextHookEx trả về còn
nếu nCode >= 0 và thủ tục hook không xử lý thông điệp nó đề nghị bạn gọi
CallNextHookEx và trả về giá trị nó trả về ngược lại những ừng dụng khác đã đặt
hook WM_MOUSE sẽ không nhận thông báo hook và có thể đối xử chính xác như
là một kết quả. Nếu thủ tục hook đã xử lý thông điệp thì nó trả về một giá trị khác 0
để ngăn chặn hệ thống chuyển thông điệp tới thủ tục cửa sổ đích.
- Ghi chú: Một ứng dụng đặt thủ tục hook bằng cách đặc tả kiểu hook
WH_MOUSE và địa chỉ của thủ tục hook trong một gọi tới hàm
SetWindowsHookEx. Thủ tục hook phải không đặt hàm callback
JournalPlayBackProc.
10 - Hàm RedrawWindow:
Hàm RedrawWindow cập nhật hình chữ nhật hay vùng đưa ra vào trong vùng
client của cửa sổ.
- Cú pháp:
BOOL RedrawWindow( hwnd, lprcUpdate,
hrgnUpdate, fuRedraw)
HWND hwnd;
const RECT FAR* lprcUpdate;
HRGN hrgnUpdate;
UINT fuRedraw;
- Thông số:
hwnd Cửa sổ cần được vẽ lại. Nếu NULL thì cửa sổ desktop
được cập nhật.
lprcUpdate chỉ tới cấu trúc RECT chứa tọa độ của hình chữ nhật cập
nhật. Thông số này bị phớt lờ nếu hrgnUpdate chứa
handle vùng hợp lệ.
hrgnUpdate vùng cập nhật. Nếu cả hrgnUpdate và lprcUpdate đều
NULL thì toàn bộ vùng client của cửa sổ được cập nhật.
fuRedraw một hay nhiều cờ vẽ lại, có thể kết hợp nhiều cờ.
Các cờ sau được sử dụng để làm mất hiệu lực vùng cửa sổ:
RDW_ERASE làm cho cửa sổ nhận thông điệp WM_ERASEBKGND
khi cửa sổ được vẽ lại. Cờ RDW_INVALIDATE cũng
phải được xác định nếu không cờ RDW_ERASE không
có tác dụng.
RDW_FRAME làm cho bất kỳ vùng nào của vùng non-client của cửa sổ
mà giao với vùng cập nhật nhận thông điệp
WM_NCPAINT. Cờ RDW_INVALIDATE cũng phải
được xác định nếu không RDW_FRAME không ảnh
hưởng. Thông điệp thường không gởi trong suốt sự thực
thi của hàm RedrawWindow trừ khi
RDW_UPDATENOW hay RDW_ERASENOW được
xác định.
RDW_INTERNALPAINT làm cho WM_PAINT được gởi (send)
tới cửa sổ mà không quan tâm cửa sổ chứa vùng hợp lệ
hay không.
RDW_INVALIDATE làm mất hiệu lực lprcUpdate hay hrgnUpdate
(chỉ một trong chúng có lẽ không NULL). Nếu cả hai
NULL, thì toàn bộ cửa sổ bị mất hiệu lực.
Những cờ sau làm có hiệu lực vùng cửa sổ:
RDW_NOERASE chặn bất kỳ thông điệp WM_ERASEBKGND nào
sắp xảy ra.
RDW_NOFRAME chặn bất kỳ thông điệp WM_NCPAINT nào sắp
xảy ra. Cờ này phải được sử dụng với
RDW_VALIDATE và được sử dụng điển hình với
RDW_NOCHILDREN. Sự chọn lựa để sử dụng này
phải cẩn thận khi nó có thể làm cho các phần của cửa sổ
vẽ đúng.
RDW_NOINTERNALPAINT chặn bất kỳ thông điệp nội
WM_PAINT nào. Cờ này không ảnh hưởng
WM_PAINT gây kết quả từ vùng hợp lệ.
RDW_VALIDATE làm hợp lệ lprcUpdate hay hrgnUpdate (chỉ một có
lẻ không NULL). Nếu cả hai đều NULL, thì toàn bộ cửa
sổ được hợp lệ. Cờ này không ảnh hưởng tới thông điệp
nội WM_PAINT.
Những cờ dưới đây điều khiển khi việc vẽ xảy ra. Không có sự vẽ nào được
thực hiện bởi hàm RedrawWindow trừ khi một trong các mẫu này được xác định.
RDW_ERASENOW làm cho các cửa sổ bị tác dụng (như là được xác
định bởi cờ RDW_ALLCHILDREN và
RDW_NOCHILDREN) nhận thông điệp
WM_NCPAINT và WM_ERASEBKGND ,Nếu cần
thiết trước lúc hàm trả về thì WM_PAINT bị trì hoãn.
RDW_UPDATENOW làm cho các cửa sổ bị tác dụng (như là được xác
định bởi cờ RDW_ALLCHILDREN và RDW_NOCHILDREN) nhận
thông điệp WM_NCPAINT, WM_ERASEBKGND và WM_PAINT.
Nếu cần thiết trước lúc hàm trả về.
- Mặc định, các cửa sổ bị tác dụng bởi hàm RedrawWindow phụ thuộc việc
cửa sổ có kiểu WS_CLIPCHILDREN hay không. Những cửa sổ con của các cửa sổ
WS_CLIPCHILDREN không bị ảnh hưởng; Tuy nhiên các cửa sổ không
WS_CLIPCHILDREN được làm có hiệu lực một các đệ quy hay được làm mất hiệu
lực cho đến khi một cửa sổ WS_CLIPCHILDREN được bắt gặp. Các cờ sau điều
khiển những cửa sổ bị ảnh hưởng bởi hàm RedrawWindow:
RDW_ALLCHILDREN gồm các cửa sổ con (nếu co) trong hoạt động
vẽ
RDW_NOCHILDREN loại trừ các cửa sổ con (nếu có) ra khỏi hoạt
động vẽ
- Giá trị trả về: khác 0 nếu thành công, ngược lại là 0.
- Chú ý: Khi hàm RedrawWindow được dùng để làm mất hiệu lực vùng cửa sổ
desktop thì cửa sổ desktop không nhận thông điệp WM_PAINT. Để vẽ lại desktop
một ứng dụng sẽ sử dụng cờ RDW_ERASE để sinh ra thông điệp
WM_ERASEBKGND.
11 - Hàm GetViewportOrgEx:
Hàm GetViewportOrgEx lấy tọa độ x, y của origin của viewport được tổ chức
với một DC.
- Cú pháp:
BOOL GetViewportOrgEx(hdc, lpPoint)
HDC hdc;
POINT FAR* lpPoint;
- Thông số:
hdc xác định device context.
lpPoint Points chỉ tới địa chỉ một cấu trúc POINT. Origin của
viewport (trong tọa độ thiết bị) được đặt trong cấu trúc
này.
- Giá trị trả về: khác 0 nếu thành công, ngược lại là 0.
12 - Hàm GetDCOrg:
Hàm GetDCOrg lấy tọa độ của origin dịch cuối cùng cho DC. Origin này xác
định offset được sử dụng bởi Windows để dịch tọa độ thiết bị sang tọa độ client cho
các điểm trong một cửa sổ ứng dụng. Origin dịch cuối cùng liên quan với origin vật
lý của màn hình.
- Cú pháp:
DWORD GetDCOrg(hdc)
HDC hdc; // handle of device context
- Thông số:
hdc device context mà origin của nó được lấy
- Giá trị trả về: word thấp của giá trị trả về chứa tọa độ x và word cao chứa toạ
độ y của origin dịch cuối cùng trong hệ toạ độ thiết bị nếu hàm thành công.
13 - Hàm GetClientRect:
Hàm GetClientRect tọa độ client của vùng client của cửa sổ. Tọa độ client xác
định góc trái-trên và phải-dưới của vùng client. Bởi vì tọa độ client liên quan đến
góc trái-trên của vùng client của cửa sổ nên tọa độ của góc trái-trên là (0,0).
- Cú pháp:
void GetClientRect(hwnd, lprc)
HWND hwnd; // handle of window
RECT FAR* lprc; // address of structure for rectangle
- Thông số:
hwnd Cửa sổ mà tọa độ client của nó được lấy
lprc chỉ tới cấu trúc RECT nhận tọa độ client. Giá trị left và top sẽ
là 0, right và bottom sẽ chứa chiều rộng và chiều cao của cửa
sổ.
- Giá trị trả về: không trả về giá trị.
14 – Các thông điệp để vẽ lại màn hình:
Các thông điệp này được gởi đến cửa sổ được cho bằng hàm SendMessage và
khiến cho ứng dụng quản lý cửa sổ đó vẽ lại cửa sổ.
a) Thông điệp WM_PAINT:
Mặt bằng cửa sổ bị thay đổi liên tục (bởi các lệnh resize, đóng mở các dialog
box…) vì thế nếu không cập nhật thì sẽ bị biến dạng nên Windows dùng thông điệp
WM_PAINT để tô vẽ lại màn hình.
Có nhiều tình huống làm cho Windows phát ra thông điệp WM_PAINT:
- Trước hết là khi người sử dụng chạy chương trình
- Sau khi cửa sổ co giản hay hoàn nguyên sau khi cửa sổ bị che phủ (một phần
hay toàn phần) bởi một cửa sổ khác tức là một phần cửa sổ bị che không thấy bây
giờ được vẽ lại cho thấy
- Gởi đi một thông điệp WM_PAINT bằng cách làm mất hiệu lực vùng client
(invalidating) của nó như gọi hàm InValidateRect().
WM_PAINT:
Hdc = (HDC) wParam ; // DC để vẽ trong đó
Hdc chỉ tới DC để vẽ, nếu là NULL thì dùng DC có sẵn, hdc được sử dụng bởi
một vài điều khiển chung để có thể vẽ trong một DC khác hơn là DC có sẵn. Các
cửa sổ khác có thể phớt lờ thông số này.
Trị trả về: một ứng dụng trả về 0 nếu nó xử lý thông điệp này.
b) Thông điệp WM_NCPAINT:
Một ứng dụng gởi thông điệp này tới một cửa sổ khi khung (frame) của nó
phải được vẽ lại.
Khung cửa sổ là vùng không phải client area.
WM_NCPAINT:
Hrgn = (HRGN) wParam ; // handle của update region
Tham số:
Hrgn là giá trị của wParam chỉ tới update region được xén tới frame cửa sổ,
khi wParam = 1 thì toàn bộ frame cửa sổ cần được cập nhật.
Giá trị trả về: một ứng dụng trả về giá trị 0 nếu nó xử lý thông điệp này.
Ghi chú: clipping region của cửa sổ luôn luôn là hình chữ nhật ngay cả khi
hình dạng của frame thay đổi.
IV – Giới thiệu một số cấu trúc dữ liệu có liên quan:
Các cấu trúc dữ liệu này là cấu trúc chuẩn của Windows 3.1, được định nghĩa
trong file WINDOWS.H
1 - Cấu trúc TEXTMETRIC:
Cấu trúc TEXTMETRIC chứa thông tin căn bản về font vật lý. Tất cả các
kích thước được đưa ra trong các đơn vị luận lý tức là chúng phụ thuộc vào chế độ
ánh xạ hiện hành ngữ cảnh màn hình.
Nội dung ý nghĩa của các dữ liệu trong cấu trúc này đã trình bày trong chương
4: Kết xuất văn bản.
2 – Cấu trúc POINT:
- Dùng để định nghĩa tọa độ x, y của một điểm.
- Cú pháp:
typedef struct tagPOINT
{
LONG x;
LONG y;
}
3 – Cấu trúc STRUCT:
- Định nghĩa tọa độ các góc upper-left và lower-right của một hình chữ nhật
- Cú pháp:
typedef struct tagRECT
{
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT;
4 – Cấu trúc PAINTSTRUCT:
- Dùng chứa thông tin dùng để tô vẽ một client area thuộc cửa sổ.
- Cú pháp:
typedef struct tagPAINTSTRUCT
{
HDC hdc;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
BYTE fIncUpdate;
BYTE rgbReserved[16];
} PAINTSTRUCT;
- Tham số:
hdc handle của DC cần vẽ
fErase cho biết background có vẽ lại hay không, nếu khác 0 thì
tô vẽ còn nếu ngược lại thì không vẽ.
rcPaint góc upper-left và lower-right của hình chữ nhật được vẽ
fRestore dành riêng cho sử dụng nội tại của Windows.
fIncUpdate dành riêng cho sử dụng nội tại của Windows.
RgbResersed[16] khối ký ức dành riêng cho sử dụng nội tại của
Windows.
5 – Cấu trúc EVENTMSG:
- Chứa thông tin từ hàng ứng dụng của Windows, được sử dụng để lưu trữ
thông tin thông điệp cho hàm callback JornalPlaybackProc.
- Cú pháp:
typedef struct tagEVENTMSG
{
UINT message;
UINT paramL;
UINT paramH;
DWORD time;
} EVENTMSG;
- Thông số:
message thông điệp
paramL thông tin thêm vào về thông điệp. Nghĩa chính xác phụ
thuộc vào giá trị thông điệp.
paramH thông tin thêm vào về thông điệp. Nghĩa chính xác phụ
thuộc vào giá trị thông điệp.
time thời điểm mà thông điệp được post.
6 – Cấu trúc MSG:
- Chứa thông tin từ hàng ứng dụng cửa sổ.
- Cú pháp:
typedef struct tagMSG
{
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG;
- Thông số:
hwnd cửa sổ nhận thông điệp
message ố thông điệp
wParam thông tin thêm vào về thông điệp. Nghĩa chính xác phụ thuộc
vào giá trị thông điệp.
lParam thông tin thêm vào về thông điệp. Nghĩa chính xác phụ thuộc
vào giá trị thông điệp.
time thời điểm thông điệp được post.
pt vị trí cursor ở tọa độ màn hình khi thông điệp được post.
7 - Cấu trúc SIZE:
- Chứa viewport extents, window extents, text extents, bitmap dimensions, và
aspect-ratio filter cho một vài hàm mở rộng
- Cú pháp:
typedef struct tagSIZE
{
int cx;
int cy;
} SIZE;
- Thông số:
cx x-extent khi hàm trả về
cy y-extent khi hàm trả về
8 - Cấu trúc MOUSEHOOKSTRUCT:
- Cấu trúc MOUSEHOOKSTRUCT chứa thông tin về một sự kiện chuột
- Cú pháp:
typedef struct tagMOUSEHOOKSTRUCT
{
POINT pt;
HWND hwnd;
UINT wHitTestCode;
DWORD dwExtraInfo;
} MOUSEHOOKSTRUCT;
- Thông số:
pt một điểm có cấu trúc POINT chứa tọa độ x,y của mouse
cursor trong hệ tọa độ màn hình
hwnd cửa sổ sẽ nhận thông điệp chuột tương ứng với sự kiện
mouse
wHitTestCode mã hit-test trả về
dwExtraInfo thông tin thêm vào được tổ chức với sự kiện mouse. Một
ứng dụng có thể thiết lập thông tin thêm vào này bằng
cách gọi hàm sự kiện phần cứng và lấy nó bằng cách
gọi hàm GetMessageExtraInfo .
Kết quả và hướng phát triển
Chương trình GETTEXT đã bước đầu đáp ứng được yêu cầu của đề tài đặt ra:
Nhận dạng được các từ hiển thị trên màn hình.
Tuy nhiên, do kỹ thuật override chỉ mới thực hiện được trong môi trường
Windows 16 bits, nên chương trình này chỉ chạy được trên môi trường Windows
16bits. Trong môi trường Windows 9x, là môi trường lai tạp giữa 16bits và 32bits,
nên chương trình chỉ nhận dạng được khi dòng văn bản được xuất bởi các hàm kết
xuất văn bản của môi trường 16bits (như TextOut, ExtTextOut), còn đối với văn
bản được kết xuất bởi các hàm của môi trường 32bits (như TextOutA, ExtTextOutA
- được dùng để kết xuất văn bản trong các phầm mềm 32bits như Microsoft Office
97) thì chương trình không thể nhận dạng được. Dù vậy điều mà đề tài đã đạt được
là đưa ra được một giải thuật khung sườn mang tính khả thi, có thể phát triển hoàn
chỉnh trong tương lai.
Do vậy, để nhận dạng được tất cả các từ xuất hiện trên màn hình Windows thì
phải override được các hàm của Windows 32bits. Việc này thực sự là một vấn đề
lớn, và cần phải hiểu sâu sắc về Windows, vì Windows có chế độ bảo vệ bộ nhớ rất
chặt chẽ, nên không thể ghi xoá vào hàm API như cách mà chương trình đã làm, do
đó cần phải có giải thuật khác.
Ngoài ra việc lấy dữ liệu bằng cách override chỉ là một hướng để giải quyết
vấn đề, ta cũng có thể thực hiện bằng cách khác như dùng các hàm lấy text mà
Windows có hỗ trợ, nhưng có thể vấn đề sẽ phức tạp hơn.
Các file đính kèm theo tài liệu này:
- Đồ án tốt nghiệp - Phân tích thiết kế hệ thống - Nghiên cứu các phương pháp nhận dạng từ dưới cursor mouse trên Desktop Windows.pdf