Đề tài Phân tích và thiết kế chương trình

MỤC LỤC LỜI MỞ ĐẦU CHƯƠNG 1: TÌM HIỂU VỀ LẬP TRÌNH WINDOWS I. Khái quát về lập trình trong Windows II. Thông điệp và xử lý thông điệp III. Giao diện thiết bị đồ họa GDI IV. Cửa sổ trong Windows V. Chương trình Windows tiếp nhận thông điệp chuột CHƯƠNG 2: TÌM HIỂU VỀ HOOK 1 - Chuỗi hook 2 - Thủ tục hook 3 - Các loại hook 4 - Sử dụng hook 5 - Hook trong Windows 6 - Giới thiệu một số hàm liên quan đến hook CHƯƠNG 3: KỸ THUẬT OVERRIDE HÀM API I. Khái quát về kỹ thuật override II. Lý do sử dụng kỹ thuật override trong lập trình Windows III. Cơ chế hoạt động và quản lý bộ nhớ trên Windows 32bits IV. Cơ chế hoạt động và quản lý bộ nhớ trên Windows 64bits V. Hiện thực kỹ thuật override trên Windows 16bits VI. Một số hàm được sử dụng trong kỹ thuật override CHƯƠNG 4: KẾT XUẤT VĂN BẢN TRONG WINDOWS I. Kết xuất văn bản trong Windows II. Các hàm căn bản để kết xuất văn bản CHƯƠNG 5: PHÂN TÍCH VÀ THIẾT KẾ CHƯƠNG TRÌNH I. Phân tích vấn đề II. Thiết kế chương trình III. Giới thiệu một số hàm có liên quan IV. Giới thiệu một số cấu trúc dữ liệu có liên quan KẾT QUẢ VÀ HƯỚNG PHÁT TRIỂN

docx92 trang | Chia sẻ: lvcdongnoi | Lượt xem: 2578 | Lượt tải: 1download
Bạn đang xem trước 20 trang tài liệu Đề tài Phân tích và thiết kế chương trình, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
terminated chứa tên hàm hay số thứ tự của hàm. Nếu là số thứ tự thì giá trị phải ở trong word thấp và word cao phải là 0. Giá trị trả về: là giá trị điểm nhập của hàm module nếu hàm thành công,ngược lại trả về NULL. Thông số lpszProcName là một giá trị số thứ tự và hàm được xác định bởi số thứ tự đó không tồn tại trong module thì hàm vẫn có thể trả về giá trị non-NULL. Xác định hàm bằng tên tốt hơn. 4 – Hàm MakeProcInstance: - Cú pháp: FARPROC MakeProcInstance(lpProc, hinst) FARPROC lpProc; HINSTANCE hinst; - MakeProcInstance trả về địa chỉ của prolog code một hàm exported. Prolog code buộc một instance data segment với một hàm exported. Khi hàm được gọi nó truy xuất tới các biến và dữ liệu trong instance data segment đó. - Thông số: lpProc địa chỉ của hàm exported. hinst instance được tổ chức với data segment yêu cầu. - Giá trị trả về: chỉ tới prolog code cho hàm exported nếu thành công, ngược lại là NULL. 5 – Hàm FreeProcInstance: - Cú pháp: void FreeProcInstance(lpProc) FARPROC lpProc; - Hàm FreeProcInstance giải phóng hàm ra khỏi data segment buộc lấy nó bởi hàm MakeProcInstance. - Thông số: lpProc: chỉ tới địa chỉ procedure-instance address của hàm được giải phóng. Nó phải được tạo bởi hàm MakeProcInstance. - Hàm không trả về giá trị gì. 6 – Hàm AllocSelector: - Cú pháp: UINT AllocSelector(uSelector) UINT uSelector; - Hàm AllocSelector cấp phát một selector mới. Windows không khuyến khích sử dụng hàm này, chỉ sử dụng khi thực sự cần thiết, trong Windows 32bit không support. - Thông số: uSelector là selector để trả về. Nếu là selector không hợp lệ thì trả về một một selector mới là một bản sao chính xác của cái đã xác định ở đây. Nếu là 0 thì trả về một selector mới không được khởi tạo. - Giá trị trả về: là một selector bản sao của selector đã tồn tại hoặc là một selector mới chưa được khởi tạo, ngược lại là 0. 7 – Hàm PrestoChangoSelector: - Cú pháp: UINT PrestoChangoSelector( uSourceSelector, uDestSelector) UINT uSourceSelector; UINT uDestSelector; - Hàm PrestoChangoSelector tạo ra một code selector tương ứng với data selector đã cho hoặc tạo ra một data selector tương ứng với một code selector đã cho. Windows không khuyến khích sử dụng hàm này, chỉ sử dụng khi thực sự cần thiết, trong Windows 32bit không support. - Thông số: uSourceSelector selector cần đổi uDestSelector selector được cấp trước đó bởi hàm AllocSelector. Selector được cấp trước này nhận selector được chuyển đổi. - Giá trị trả về: là selector đã được đổi nếu thành công, ngược lại là 0. Chương 4: KẾT XUẤT VĂN BẢN TRONG WINDOWS I - Kết xuất văn bản trong Windows: Trong phần lớn các ứng dụng thì văn bản là phần kết xuất chính. Do Windows là một hệ điều hành độc lập thiết bị (device independent) nên việc kết xuất văn bản cũng tương đối dễ chịu. Cũng như các thành phần đồ họa khác trong Windows, việc xuất văn bản lên màn hình phải thông qua trung gian là DC (device context). Như thế, đặc tính độc lập thiết bị của hệ điều hành Windows bắt buộc developer phải làm việc gián tiếp để hiển thị văn bản nhưng Windows đảm bảo là chương trình của ta sẽ chạy được trên bất kỳ thiết bị nào. Trong đa số trường hợp Windows sẽ giải quyết hoạt động của thiết bị thông qua các driver thiết bị mà người sử dụng đã cho cài đặt trên hệ thống. Các driver thiết bị sẽ chận hứng dữ kiện mà ứng dụng muốn cho hiển thị rồi cho dịch các dữ liệu này ra dạng thích hợp của thiết bị mà nó sẽ hiển thị lên như màn hình, máy in… Mỗi thiết bị đều có một driver do nhà sản xuất tạo ra. Device Context (DC) chẳng qua là một cấu trúc dữ liệu làm gạch nối giữa chương trình ứng dụng và driver của thiết bị. Kết xuất văn bản theo GDI hoàn toàn khác với kết xuất trên môi trường lập trình cổ điển DOS, vì GDI coi văn bản như là một loại đối tượng đồ họa. Cách tiếp cận để kết xuất văn bản của GDI có thể được gọi là kết xuất thiên về pixel (pixel oriented output), GDI sử dụng khung lưới pixel để cho ta xuất văn bản và ta có thể xuất văn bản ở bất kỳ vị trí nào trên cửa sổ. Và do coi văn bản như là một đối tượng đồ họa nên ta có thể dễ dàng trộn văn bản với các đối tượng đồ họa khác. Nhưng khác với các đối tượng đồ họa khác ta phả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: 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 No 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 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:

  • docxBaoCao.docx
  • rarSource.rar