lôøi caûm taï,i.vietnamdoc.net/data/file/2015/thang06/17/nghien-cuu... · web view5 - vấn...

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

Upload: others

Post on 29-Dec-2019

1 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

MỤC LỤC

LỜI MỞ ĐẦU 3CHƯƠNG 1: TÌM HIỂU VỀ LẬP TRÌNH WINDOWS 4

I. Khái quát về lập trình trong Windows 5II. Thông điệp và xử lý thông điệp 7III. Giao diện thiết bị đồ họa GDI 11IV. Cửa sổ trong Windows 15V. Chương trình Windows tiếp nhận thông điệp chuột 22

CHƯƠNG 2: TÌM HIỂU VỀ HOOK 261 - Chuỗi hook 272 - Thủ tục hook 273 - Các loại hook 284 - Sử dụng hook 305 - Hook trong Windows 3.x 316 - Giới thiệu một số hàm liên quan đến hook 33

CHƯƠNG 3: KỸ THUẬT OVERRIDE HÀM API 36I. Khái quát về kỹ thuật override 37II. Lý do sử dụng kỹ thuật override trong lập trình Windows 37III. Cơ chế hoạt động và quản lý bộ nhớ trên Windows 16bits 38IV. Cơ chế hoạt động và quản lý bộ nhớ trên Windows 32bits 41V. Hiện thực kỹ thuật override trên Windows 16bits 45VI. Một số hàm được sử dụng trong kỹ thuật override 50

CHƯƠNG 4: KẾT XUẤT VĂN BẢN TRONG WINDOWS 54I. Kết xuất văn bản trong Windows 55II. Các hàm căn bản để kết xuất văn bản 55

CHƯƠNG 5: PHÂN TÍCH VÀ THIẾT KẾ CHƯƠNG TRÌNH 66I. Phân tích vấn đề 67II. Thiết kế chương trình 68III. Giới thiệu một số hàm có liên quan 78IV. Giới thiệu một số cấu trúc dữ liệu có liên quan 92

KẾT QUẢ VÀ HƯỚNG PHÁT TRIỂN 97

Page 2: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

Đề 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.

Page 3: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

Lời Mở Đầugày nay, hầu như mọi công việc hàng ngày liên quan đến cuộc sống của chúng ta đều diễn ra trên máy tính. Từ việc soạn thảo văn bản, gởi nhận thông tin đến việc tra

cứu, truy cập thông tin từ hệ thống mạng máy tính toàn cầu Internet đối với người sử dụng là công việc thường ngày và rất phổ biến.

Từ đó, sẽ phát sinh vấn đề là người sử dụng sẽ cần tìm hiểu ý nghĩa của một từ, một câu hoặc cần phải dịch một đoạn văn bản, một file dữ liệu nào đó ra tiếng Việt và ngược lại. Đây là một nhu cầu cần thiết và hầu như xảy ra thường xuyên đối với nhiều người, do đó nhận dạng từ đặc biệt là nhận dạng từ trên màn hình trong môi trường Windows là việc làm cần thiết và có ý nghĩa thực tế.

Kết quả của việc nhận dạng từ sẽ được dùng để xây dựng nên các ứng dụng khác chẳng hạn như các từ điển được tra cứu theo kiểu tương tác trực tiếp sẽ rất thuận tiện cho người sử dụng bởi vì theo cách này thì cho dù đang ở trong bất kỳ ứng dụng nào khi cần tra cứu thì thao tác trực tiếp ngay trên ứng dụng đang dùng tức là chỉ cần click chuột vào đó chứ không cần phải mở từ điển rồi tra cứu từ đó theo kiểu cổ điển.

Vì thế, trong thời gian làm Luận Án Tốt nghiệp được sự hướng dẫn của thầy Lê Tấn Hùng nhóm sinh viên chúng tôi thực hiện đề tài: “Nhận dạng từ dưới cursor mouse trên deskop Windows. Viết chương trình nhận dạng từ này”. Trong giai đoạn đầu của luận án tốt nghiệp chúng tôi đã nghiên cứu được một số vấn đề quan trọng và căn bản có ý nghĩa trong việc thực hiện yêu cầu đã đặt ra của đề tài. Đề tài này chỉ tập trung nhận dạng từ ở dạng text trên desktop của môi trường Windows rồi xuất kết quả ra.

Trong thời gian làm luận án tốt nghiệp nhóm sinh viên chúng tôi đã tiến hành nghiên cứu cơ chế hoạt động và quản lý của hệ điều hành Windows. Nghiên cứu về phương thức lập trình trong môi trường Windows và các phương tiện mà Windows hỗ trợ khi lập trình. Tham khảo và nghiên cứu kỹ thuật override các hàm giao tiếp của Windows ở chế độ 16 bit và 32 bit. Nghiên cứu cách xử lý các thông điệp trong Windows và tìm hiểu về cách kết xuất văn bản, về chế độ ánh xạ, vấn đề tọa độ . . . và cách xử lý văn bản. Trên cơ sở đó bước đầu chúng tôi đã xây dựng xong một ứng dụng có khả năng nhận dạng được từ trên nền Windows 16 bit được viết bằng ngôn ngữ Visual C++ version 1.5 và hướng phát triển trong thời gian tới là hiện thực nó trên nền Win32.

Báo cáo của chúng tôi sẽ lần lượt điểm qua những nội dung mà chúng tôi đã nghiên cứu và tìm hiểu được trong thời gian qua. Sau đó là phần giới thiệu chi tiết về chương trình từ khâu phân tích-thiết kế cho đến phần chương trình nguồn và cuối cùng sẽ là nêu những vấn đề còn tồn tại và hướng phát triển trong tương lai.

Page 4: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

Chương 1:

TÌM HIỂU VỀTÌM HIỂU VỀLẬP TRÌNH WINDOWSLẬP TRÌNH WINDOWS

Page 5: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

I - KHÁI QUÁT VỀ LẬP TRÌNH TRONG WINDOWS:

1 - Khái quát về lập trình trong Windows:

Môi trường lập trình Windows về cơ bản là dựa trên bộ hàm API (Application Programmer Interface), nó có chức năng như các ngắt trong bảng vector ngắt của DOS, nhưng nó thân thiện hơn ở chỗ cách gọi hàm API giống hệt cách gọi hàm của ngôn ngữ cấp cao, mỗi hàm có một tên gọi hẳn hoi, và tên gọi thường được đặt rất phù hợp với công dụng của hàm (mặc dù có hơi dài dòng) từ đó tạo khả năng gợi nhớ cao. Với Windows, người lập trình không còn phải lập trình theo kiểu assembly nữa mà lập trình theo kiểu ngôn ngữ cấp cao, mọi hoạt động trong máy ở mức thấp từ hàm API trở xuống thuộc phạm vi của Windows và Windows không khuyến khích việc các ứng dụng can thiệp vào lĩnh vực này. Bù lại, bằng các hàm API, nó hỗ trợ rất hiệu quả cho người lập trình, giúp khai thác khả năng của thiết bị triệt để, dễ dàng và tiện lợi hơn bao giờ hết. Có thể nói Windows đã mở ra cho người lập trình không gian rộng lớn để phát triển ứng dụng, và hạn chế không gian phát triển hệ thống. Điều này dẫn đến hệ quả là các ứng dụng được tạo ra hết sức dễ dàng, và quan trọng là hệ thống chạy ổn định hơn, không bị treo do lỗi của ứng dụng, không thể xâm nhập, nhưng sẽ rất khó khăn nếu người lập trình muốn trực tiếp điều khiển hoạt động trong máy và phát triển về lập trình hệ thống.

- Tìm hiểu hàm Windows API: Windows là một hệ điều hành đa nhiệm (multitasking) mà qua đó các ứng dụng ở trong môi trường Windows sẽ giao tiếp với user thông qua một hay nhiều giao diện. Để truy cập các giao diện này thì các ứng dụng được xây dựng trên môi trường Windows sẽ sử dụng tập các hàm được gọi là giao diện chương trình ứng dụng API (Application Program Interface). Chương trình của người sử dụng có thể gọi tới các hàm API để truy cập tới mọi tài nguyên của Windows. GDI là một bộ phận của API, giao diện thiết bị đồ họa GDI (Graphic Device Interface) có nhiệm vụ duy trì sự độc lập của Windows đối với các thiết bị đồ họa hay còn gọi là khả năng độc lập thiết bị (device independent) tức là cho phép Windows làm việc với nhiều kiểu thiết bị đồ họa khác nhau.

2 - Thư viện liên kết động DLL (Dynamic Link Library):

Thư viện liên kết động là các tập tin được Windows lưu dưới dạng nhị phân chứa các hàm mà mọi ứng dụng trên Windows đều có thể sử dụng. Nét đặc trưng của DLL là nó có thể được sử dụng bởi nhiều ứng dụng tại cùng một thời điểm hay nói cách khác thư viện liên kết động có thể cùng một lúc được gọi bởi nhiều chương trình. DLL là một dữ liệu chia sẻ được (shared data).

Có 3 loại DLL khác nhau:

Page 6: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

- Thư viện liên kết động API: thuộc hệ thống Windows, khi cài hệ điều hành thì nó đã có sẵn. Chúng được nạp khi Windows khởi động.

- Thư viện liên kết động third party: do các công ty khác tạo ra trên môi trường Windows, hỗ trợ thêm công tác lập trình trong Windows.

- Thư viện liên kết động do chúng ta tạo ra.

Windows sử dụng cấu trúc thư viện liên kết động DLL (Dynamic Link Library) nhằm mục đích không sao chép một khối lượng lớn các mã vào trong chương trình như ở các thư viện thông thường. Nhờ cấu trúc động của DLL nên mọi chương trình đều có thể truy cập thư viện trong thời gian thực thi. Các hàm API được Windows giữ dưới dạng hỗn hợp trong một số DLL. Trong quá trình dịch khi gặp lệnh gọi hàm API từ chương trình ứng dụng thì chương trình dịch không thêm mã này vào module thực hiện mà chỉ thêm các lệnh liên kết (chứa tên của DLL bên trong có hàm cần nạp) và tên hàm đó. Khi thực thi chương trình thì hàm API thực sự mới được nạp vào bộ nhớ để thực hiện.

Cùng với sự phát triển của Windows là sự phát triển của lập trình hướng đối tượng, và để hỗ trợ cho việc lập trình hướng đối tượng, Microsoft đã cung cấp cho người lập trình một bộ thư viện các lớp cơ bản để phát triển các ứng dụng hướng đối tượng gọi là MFC (Microsoft Foundation Classes), nội dung của nó bao gồm thông tin về các lớp cơ bản được chuẩn hóa như lớp application; document; view; OLE; cửa sổ; nút bấm; text; v.v… trong các lớp này mọi thứ liên quan đến nó (bao gồm dữ liệu và các chương trình xử lý của nó) đều được làm hoàn chỉnh, người lập trình chỉ việc lấy ra sử dụng, hoặc có thể thêm bớt một ít tính năng đặc trưng cho đối tượng của mình. Mục tiêu chính của MFC là hệ thống hóa các hàm API, cung cấp một thể thức gọi gọn các hàm API, cung cấp một “khung làm việc” (framework) cực mạnh để người lập trình không cần phải quan tâm đến những đoạn chương trình thuộc về “thủ tục” mà chỉ cần quan tâm đến phần cốt lõi để đạt được mục đích.

II - THÔNG ĐIỆP VÀ XỬ LÝ THÔNG ĐIỆP:

1 - Khái niệm:

Lập trình trên môi trường Windows khác với lập trình ở các môi trường khác ở điểm là lập trình trên Windows luôn luôn gắn liền với những thông điệp. Mọi hoạt động xảy ra trên một chương trình Windows đều thông qua các thông điệp. Thông điệp sẽ được hệ thống báo cho các ứng dụng biết các tác động từ bên ngoài vào hệ thống Windows. Một cửa sổ có thể gởi đi một thông điệp cho một cửa sổ khác và các cửa sổ đáp ứng lại thông điệp bằng cách gởi đi một thông điệp khác cho một cửa sổ khác.

Page 7: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

Trong Windows có 3 loại thông điệp cơ bản:

- Những thông điệp tổng quát: có mã nhận diện mang tiền tố WM_ được coi là phần lớn trong ứng dụng và Windows đã cung cấp các hàm để giải quyết.

- Những control notification: đây là những thông điệp WM_COMMAND được chuyển từ cửa sổ con tới cửa sổ bố mẹ.

- Những nút lệnh: là thông điệp WM_COMMAND phát đi từ trình đơn, từ các nút điều khiển. Đây là loại thông điệp yêu cầu ứng dụng phải thực hiện một công việc gì đó.

2 - Gởi đi các thông điệp:

Windows cho phép ứng dụng gởi đi những thông điệp cho mình, cho các ứng dụng khác hoặc cho hệ thống.

Có 3 hàm Windows API để gởi thông điệp đi:

a) Hàm SendMessage:

Cú pháp:

LRESULT SendMessage(hwnd, uMsg, wParam, lParam)HWND hwnd; // handle của cửa sổ nhận (đích)UINT uMsg; // thông điệp để gởiWPARAM wParam; // thông số thông điệp đầu tiênLPARAM lParam; // thông số thông điệp thứ hai

- Hàm SendMessage gởi thông điệp tới một hay nhiều cửa sổ. Hàm gọi thủ tục cửa sổ cho cửa sổ và không trở về cho đến lúc thủ tục cửa sổ đã xử lý thông điệp.

- Giá trị trả về: cho biết kết quả xử lý thông điệp và phụ thuộc vào thông điệp được gởi.

b) Hàm PostMessage:

- Cú pháp:

BOOL PostMessage(hwnd, uMsg, wParam, lParam)HWND hwnd; // handle của của sổ đíchUINT uMsg; // thông điệp gởiWPARAM wParam; // thông số thông điệp đầu tiênLPARAM lParam; // thông số thông điệp thứ hai

- Hàm PostMessage gởi (đặt) một thông điệp vào trong hàng thông điệp cửa sổ và rồi trở về mà không đợi cửa sổ tương ứng xử lý thông điệp. Những thông điệp trong một hàng thông điệp được lấy bằng cách gọi hàm SetMessage hay PeekMessage.

Page 8: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

- Giá trị trả về: trả về khác 0 nếu thành công, ngược lại 0.

c) Hàm SendDlgItemMessage:

- Cú pháp:

LRESULT SendDlgItemMessage(hwndDlg,idDlgItem,uMsg,wParam,lParam)HWND hwndDlg; // handle của hộp hội thoạiint idDlgItem; // mã nhận diện ô điều khiển sẽ nhận thông điệpUINT uMsg; // thông điệp gởi điWPARAM wParam; // thông số thông điệp đầu tiên LPARAM lParam; // thông số thông điệp thứ hai

- Hàm SendDlgItemMessage gởi một thông điệp tới một điều khiển trong hộp hội thoại.

- Giá trị trả về: cho biết kết quả xử lý thông điệp và phụ thuộc vào thông điệp được gởi.

3 - Vòng lặp thông điệp:

Một thread hoặc một process đẩy một thông điệp ra khỏi hàng đợi bằng cách dùng vòng lặp thông điệp. Vòng loop chính của một ứng dụng đặt tại cuối hàm WinMain() của ứng dụng đó. Vòng lặp thông điệp có dạng như sau:

while GetMessage(&msg,NULL,0,0) { TranslateMessage(&msg);

DispatchMessage(&msg);}

Sau đây là Sơ đồ dòng thông điệp:

Thread1 Message Queue Thread2 Message Queue Thread3 Message Queue

System Dispatcher

Hardware Event Occur

System Message Queue

GetMessage()TranslateMessage()Dispatch Message()

GetMessage()TranslateMessage()Dispatch Message()

GetMessage()TranslateMessage()Dispatch Message()

WndProc() WndProc() WndProc()

DefWndProc() DefWndProc() DefWndProc()

Thread1 Hook Thread2 Hook Thread3 Hook

System Dispatcher

Page 9: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

Nó mô tả đơn giản hóa quá trình xử lý thông điệp. Thông điệp có thể bắt nguồn từ nhiều cách khác nhau, sơ đồ sau đây sẽ giải thích chi tiết hơn về vòng lặp thông điệp và chỉ ra cách thông điệp được đặt vào hàng đợi như thế nào:

Thông điệp không chỉ phát xuất từ sự kiện phần cứng, cũng có thể có thông điệp của chương trình phát xuất từ một chương trình đang chạy. Các threads có thể gởi dữ liệu trở về sau và về trước bằng cách gởi thông điệp. Thông điệp có thể gởi vào hàng đợi bằng hàm PostMessage(), hoặc chúng có thể được gởi trực tiếp cho vòng lặp thông điệp để xử lý ngay lập tức bằng hàm SendMessage().

Hardware Events

Message SentFrom Other Threads

System Dispatcher

System Message Queue

Thread Message Queue

WndProc()

Message Loop

PostMessage()

TranslateMessage()

SentMessage()

SentMessage()(To Another Thread)

Other threadsPostMessage()

Other threadsPostMessage()

Page 10: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

4 - Xử lý thông điệp:

Việc xử lý thông điệp là yếu tố chính làm cho các ứng dụng Windows vận hành được. Hệ thống và các ứng dụng khác sinh ra các thông điệp cho mọi sự kiện xuất hiện trong hệ thống thông điệp của Windows sẽ cho phép Windows chạy đa nhiệm trong một thời điểm. Windows 95 và Windows NT mở rộng khả năng của version Windows trước bằng việc cấp phát cho mỗi dòng xử lý (thread) hay mỗi tiến trình (proccess) một hàng đợi thông điệp riêng. Trong version Windows cũ thì tất cả ứng dụng đều dùng chung một hàng đợi thông điệp, vì thế để các ứng dụng khác xử lý thông điệp, ứng dụng phải trả quyền điều khiển về cho Windows mỗi khi nó có thể. Với Windows 95 và Windows NT, điều này không còn nữa.

Windows sinh ra thông điệp cho mọi sự kiện phần cứng, ví dụ như người dùng nhấn một phím hoặc di chuyển chuột. Nó gởi thông điệp đến hàng đợi thông điệp của thread thích hợp, nếu thông điệp được dành cho nhiều thread thì nó cũng được đưa vào các hàng đợi của các thread đó.

Một thông điệp trên thực tế là một cấu trúc dữ liệu như sau:

typedef struct tagMSG {HWND hwd; // handle cửa sổ UINT message; //số chỉ định loại message WPARAM wParam; //được chuyển cho WndProc() LPARAM wParam; //được chuyển cho WndProc() DWORD time; //số mili giây từ lúc bắt đầuPOINT pt; //cấu trúc điểm POINT

}

III - GIAO DIỆN THIẾT BỊ ĐỒ HỌA GDI(GRAPHIC DEVICE INTERFACE):

1 - Khái niệm:

Windows là một hệ điều hành đa nhiệm (multitasking) trong đó các ứng dụng giao tiếp với user thông qua một hay nhiều giao diện. Để truy xuất các giao diện thì chương trình ứng dụng phải sử dụng các hàm Giao diện chương trình ứng dụng. API là tập các lệnh mà một ứng dụng sử dụng để yêu cầu và tiến hành các dịch vụ cấp thấp được thi hành bởi Windows.

Giao diện thiết bị đồ họa GDI (Graphic Device Interface) là một phần của API có nhiệm vụ duy trì sự độc lập của Windows đối với các thiết bị đồ họa (cho phép Windows làm việc với nhiều thiết bị đồ họa khác nhau). Windows GDI là một thư viện bao gồm một số hàm giúp kết xuất đồ họa (graphic output) lên màn hình, máy

Page 11: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

in…GDI sẽ tạo ra: điểm, đường kẻ, hình dạng (shape: chữ nhật, tròn…), chữ văn bản.

2 - Device Context:

Ngữ cảnh thiết bị DC (Device Context) là một phần quan trọng của GDI Windows. Một DC là một cấu trúc dữ liệu dài khoảng 800 bytes được Windows duy trì có nhiệm vụ lo lưu giữ những thông tin cần thiết mà ứng dụng sẽ cần đến khi phải hiển thị kết xuất lên một thiết bị vật lý. GDI không bao giờ cho phép chương trình làm việc trực tiếp với một DC mà GDI phân phối cho chương trình một handle để nhận dạng một DC cụ thể. Tất cả các hàm API; GDI đều nhận thông số đầu tiên là một handle – hdc.

DC là một công cụ chứa các thuộc tính vẽ, DC cho phép kết nối logic một chương trình về một thiết bị cụ thể nào đó. Ngoài ra do Windows là một hệ điều hành đa nhiệm nên các chương trình không thể truy xuất trực tiếp các thiết bị vật lý để tránh xung đột. Thay vào đó, chương trình Windows phải sử dụng kết nối logic do DC đại diện. Nghĩa là tất cả các chương trình cách tiếp cận này để GDI có thể giải quyết tranh chấp khi 2 chương trình yêu cầu dùng cùng một thiết bị nên DC còn có vai trò làm permission slip. DC lưu trữ thông tin liên quan đến mặt bằng vẽ và những khả năng của nó. Trước khi sử dụng bất kỳ hàm vẽ GDI nào thì điều phải tạo một DC cho thiết bị, và khi sử dụng xong thì phải trả nó về cho Windows nhằm đảm bảo cho hoạt động của hệ thống được thông suốt bởi vì số lượng DC mà Windows quản lý là có giới hạn.

DC ở Win16: Ngữ cảnh thiết bị (DC) là một nối kết giữa một ứng dụng Windows, một driver thiết bị và một thiết bị đầu ra (output device). Windows duy trì một cache gồm 5 DC đặc biệt cho hoạt động hệ thống. Ứng dụng phải giải phóng các DC này sau khi sử dụng.

Luồng thông tin từ ứng dụng Windows qua DC và device driver tới thiết bị đầu ra:

Truy xuất thiết bị đầu ra (Accessing Output Devices): Bất kỳ ứng dụng Windows nào cũng có thể sử dụng hàm GDI để truy xuất một thiết bị đầu ra. GDI chuyển các gọi độc lập thiết bị từ ứng dụng tới driver thiết bị. Rồi driver thiết bị thông dịch các gọi đó vào trong sự hoạt động độc lập thiết bị.

Những đặc tính của DC mô tả các đối tượng vẽ được chọn (pens và brushes), font được chọn và màu của nó, cách thức mà đối tượng được vẽ (hay ánh xạ) tới thiết bị, vùng trên thiết bị có sẵn cho output (vùng xén) và những thông tin quan trọng khác. Cấu trúc chứa những đặc tính DC được gọi là khối dữ liệu DC.

Page 12: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

3 - Chế dộ ánh xạ (mapping mode):

Để duy trì sự độc lập thiết bị, GDI tạo ra output ở không gian luận lý và ánh xạ nó lên màn hình. Chế độ ánh xạ cho biết mối quan hệ giữa không gian luận lý và những pixel trên thiết bị.

Có tới 8 chế độ ánh xạ khác nhau nhưng chúng tôi chỉ quan tâm tới chế độ ánh xạ MM_TEXT vì đây là chế độ ánh xạ mặc định. Trong chế độ này một đơn vị luận lý được ánh xạ tới một pixel trên thiết bị hay màn hình. Như vậy đơn vị tính luận lý là pixel và các tọa độ x, y cũng được tính theo pixel, trị x tăng khi qua phải và giảm khi qua trái, trị y tăng khi đi xuống và giảm khi đi lên. Origin của hệ thống tọa độ là góc trái-trên (upper-left) của màn hình.

4 - Hệ thống tọa độ windows:

Windows sử dụng các hệ thống tọa độ khác nhau tùy theo hoàn cảnh như:

Hệ toạ độ thiết bị (Device coordinate system)

- Hệ toạ độ toàn màn hình (Full screen coordinate system)

- Hệ toạ độ vùng client (Client area coordinate system)

- Hệ toạ độ toàn cửa sổ (Whole window coordinate system)

- Hệ toạ độ logic (Logical coordinate system)

Trong phạm vi ứng dụng của đề tài chúng tôi chỉ quan tâm đến các hệ toạ độ:

a) Full screen coordinate system:

Là hệ thống tọa độ thiết bị liên quan tới trọn màn hình. Tọa độ màn hình được tính theo pixel và chọn tọa độ (0,0) làm góc upper-left của màn hình. Hệ thống này sử dụng khi liên quan đến trọn màn hình trên tọa độ màn hình. Thường vị trí của

WindowsApplicatio

n

GDIDevice Context

DeviceDriver

OutputDevice

WindowsApplicatio

n

WindowsApplication

DeviceDriver

DeviceDriver

OutputDevice

OutputDevice

Page 13: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

một đối tượng như con nháy hoặc con trỏ hoặc cửa sổ so với góc upper-left của màn hình thì dùng hệ tọa độ này.

b) Client area coordinate system:

Cũng là hệ tọa độ thiết bị, nó khác với hệ tọa độ trọn màn hình ở origin của hệ tọa độ. Tọa độ trọn màn hình là tương đối so với upper-left của màn hình còn tọa độ vùng client là tương đối so với upper-left của vùng client. Tọa độ này cũng tính theo device unit (pixel) giống như tọa độ màn hình.

Hàm ClientToScreen để chuyển tọa độ vùng client qua tọa độ trọn màn hình.

Hàm ScreenToClient chuyển tọa độ trọn màn hình qua tọa độ vùng client.

c) Whole window coordinate system:

Gần giống hệ tọa độ vùng client, là tương đối so với góc upper-left của cửa sổ, được sử dụng khi vẽ vùng nonclient của cửa sổ.

d) Logical coordinate:

Hầu hết các hàm GDI sử dụng hệ tọa độ này. Hệ thống tọa độ logic không phải là hệ thống tọa độ thiết bị, hệ thống tọa độ logic bao giờ cũng được ánh xạ lên một hệ thống tọa độ thiết bị. Hệ tọa độ logic có thể được ánh xạ lên hệ tọa độ toàn màn hình, hệ tọa độ vùng client hoặc hệ tọa độ toàn cửa sổ.

Dùng hàm DPtoLP để chuyển tọa độ thiết bị sang hệ tọa độ logic.

Dùng hàm LPtoDP để chuyển tọa độ logic sang hệ tọa độ thiết bị.

Như vậy điều quan trọng trong việc tính toán sử dụng hệ tọa độ là phải kiểm soát được việc sử dụng các hệ tọa độ một cách đồng bộ bởi vì việc chuyển đổi giữa các hệ tọa độ đã được cung cấp bởi các hàm nêu trên.

5 - Viewport và window:

Mapping mode cho biết ánh xạ tọa độ logic và những kích thước được cung cấp khi gọi các hàm GDI qua hệ thống tọa độ thiết bị gắn liền với DC. Tức là mapping mode quyết định GDI ánh xạ việc ánh xạ một window (tọa độ logic) qua một viewport (tọa độ thiết bị). Viewport nghĩa là một vùng hình chữ nhật của hệ thống tọa độ thiết bị được định nghĩa bởi một DC còn window khi sử dụng để qui chiếu GDI mapping mode là một hình chữ nhật của hệ thống tọa độ logic được định nghĩa bởi một DC.

Công thức để chuyển đổi một hệ tọa độ window (logic) qua một hệ tọa độ viewport (thiết bị):

xviewport = (xwindow - xwindowOrg)(xviewportExt / xwindowExt) + xviewportOrg

Page 14: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

yviewport = (ywindow - ywindowOrg)(yviewportExt / ywindowExt) + yviewportOrg

Trong đó:

(xwindow,ywindow) là điểm trên tọa độ logic được chuyển đổi thành điểm (xviewport,yviewport)

(xwindowOrg,ywindowOrg) và (xviewportOrg,yviewportOrg) là origin của vùng hình chữ nhật window và viewport theo mặc nhiên các điểm này được cho về (0,0) trên DC mặc nhiên.

Công thức sử dụng 2 điểm cho biết extent của một vùng theo tọa độ logic (xwindowExt,ywindowExt) và của một vùng theo hệ tọa độ thiết bị (xviewportExt,yviewportExt).

Tỉ lệ của (viewpot extent/window extent) là hệ số scaling dùng để dịch đơn vị logic qua đơn vị thiết bị.

Việc chuyển đổi ngược lại tương tự bằng các biến đổi công thức trên.

IV - CỬA SỔ TRONG WINDOWS:

Cửa sổ là khái niệm cơ bản trong giao diện GDI của Windows, nó là một kiến trúc chuẩn mực để từ đó xây dựng nên các đối tượng khác như: cửa sổ chính của ứng dụng (main frame); text box; edit control; button; combo box; menu; scroll bar;... nói chung là toàn bộ những công cụ tạo nên giao diện GDI đều có thể gọi là cửa sổ. Cũng có thể xem cửa sổ như vùng chữ nhật màn hình mà nơi đó ứng dụng in ra các kết xuất và nhận các dữ liệu từ người dùng.

Windows quản lý tất cả cửa sổ hiện có trong hệ thống bằng cách gán cho mỗi cửa sổ một handle (trên thực tế nó là một số nguyên), ta chỉ cần có được handle cửa sổ thì có thể thao tác mọi thứ trên cửa sổ đó.

Một cửa sổ chia sẻ màn hình với các cửa sổ khác, kể cả các cửa sổ của ứng dụng khác. Chỉ có một cửa sổ trong một thời điểm có thể nhận dữ liệu nhập từ người dùng. Người dùng có thể dùng chuột, bàn phím, hay các thiết bị nhập khác để tương tác với cửa sổ này và ứng dụng sở hữu nó.

1 - Các loại cửa sổ:

Windows cung cấp nhiều kiểu cửa sổ khác nhau để có thể kết hợp hình thành nên các hình thức cửa sổ khác nhau. Các kiểu được sử dụng trong hàm CreateWindow khi cửa sổ được tạo.

Một số kiểu cửa sổ sau:

Page 15: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

- Cửa sổ chồng lên nhau (Overlapped windows hay top-level window): là cửa sổ không bao giờ có cửa sổ cha mẹ.

- Cửa sổ bị sở hữu (Owned windows): là kiểu đặc biệt, được sở hữu bởi một cửa sổ bị chồng

- Cửa sổ pop-up: là kiểu đặc biệt của cửa sổ overlapped nhưng có thể có hoặc không title bar.

- Cửa sổ con: là cửa sổ xác định vùng client của cửa sổ cha mẹ, được sử dụng để chia vùng client của cửa sổ cha mẹ ra thành các vùng chức năng khác nhau. Một ứng dụng dùng hàm ShowWindow để cho thấy hay che dấu một cửa sổ con. Mỗi cửa sổ con phải có một cửa sổ cha mẹ. Cửa sổ cha mẹ nhường một phần trong vùng của nó cho cửa sổ con và cửa sổ con sẽ nhận tất cả các tác động từ bên ngoài vào vùng này. Một cửa sổ con có thể có nhiều cửa sổ con khác và mỗi cửa sổ con đều có cho riêng nó một handle riêng để giao dịch khi gởi thông điệp cho cửa sổ cha mẹ. Mỗi cửa sổ con là một cửa sổ độc lập, nó nhận tác động bên ngoài của riêng nó và các thông điệp khác. Những input gởi cho cửa sổ con được đi trực tiếp tới cửa sổ con và không chuyển qua cửa sổ cha mẹ ngoại trừ trường hợp cửa sổ con bị hàm EnabledWindow cho disabled. Trong trường hợp này thì Windows chuyển bất kỳ input nào tới cửa sổ con đó cho cửa sổ cha mẹ của nó. Điều này cho phép cửa sổ cha mẹ kiểm tra được input và làm cho cửa sổ con ở trạng thái enabled nếu nó thấy điều đó là cần thiết.

Những hoạt động của cửa sổ cha mẹ cũng ảnh hưởng đến cửa sổ con như sau:

- Shown: Cửa sổ cha mẹ sẽ được hiển thị trước cửa sổ con.

- Hidden: Cửa sổ cha mẹ sẽ bị che sau cửa sổ con. Cửa sổ con sẽ được nhìn thấy (hết bị che) (visible) chỉ khi cửa sổ cha mẹ được nhìn thấy.

- Destroyed: Cửa sổ cha mẹ bị huỷ sau cửa sổ con.

- Moved: Cửa sổ con bị di chuyển cùng với vùng client của cửa sổ cha mẹ. Cửa sổ con đáp ứng cho việc tô vẽ sau khi di chuyển.

- Gia tăng kích thước hay ở trạng thái kích thước cực đại: tô vẽ bất kỳ phần nào của cửa sổ cha mẹ mà đã được phơi bày ra như là kết quả của kích thước tăng lên của vùng client.

Windows không tự động xén (clip) một cửa sổ con ra khỏi vùng client của cửa sổ cha mẹ. Điều này nghĩa là cửa sổ cha mẹ vẽ lên trên cửa sổ con nếu nếu nó tiến hành bất kỳ sự tô vẽ nào trong cùng vị trí với vị trí của cửa sổ con. Windows chỉ xén cửa sổ con ra khỏi vùng client của cửa sổ cha mẹ nếu cửa sổ cha mẹ có kiểu WS_CLIPCHILDREN. Nếu cửa sổ con bị xén thì cửa sổ cha mẹ không thể tô vẽ lên nó. Một cửa sổ con có thể chồng lên các cửa sổ con khác trong cùng vùng client. Cửa sổ anh em (cùng cha mẹ) có thể tô vẽ trong mỗi vùng client của các cửa sổ

Page 16: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

khác trừ khi một cửa sổ con có kiểu WS_CLIPSIBLINGS. Nếu ứng dụng xác định kiểu này cho một cửa sổ con thì bất kỳ phần nào của cửa sổ anh em của cửa sổ con đó nằm trong cửa sổ này đều bị xén. Nếu một cửa sổ có kiểu WS_CLIPCHILDREN hoặc WS_CLIPSIBLINGS thì một mất mát nhỏ trong sự thực hiện (performance) xảy ra. Mỗi cửa sổ chiếm tài nguyên hệ thống bởi vậy ứng dụng sẽ không sử dụng các cửa sổ con một cách bừa bãi. Để hoạt động tối ưu một ứng dụng cần chia luận lý cửa sổ chính của nó trong thủ tục cửa sổ của cửa sổ chính còn hơn là dùng các cửa sổ con.

2 - Thủ tục cửa sổ (Window Procedures):

Một thủ tục cửa sổ xử lý tất cả những thông điệp được gởi tới tất cả các cửa sổ trong lớp được đưa ra. Windows gởi các thông điệp tới thủ tục cửa sổ khi nó nhận input từ user có ý định chuyển cho cửa sổ được đưa ra hay khi nó cần thủ tục để thực hiện một vài hành động trên cửa sổ của nó như việc tô vẽ lại bên trong vùng client.

Thủ tục cửa sổ nhận các kiểu thông điệp như: nhập vào từ bàn phím, chuột; yêu cầu tiêu đề cửa sổ; tường thuật sự thay đổi gây ra bởi cửa sổ khác (như thay đổi file WIN.INI); cơ hội sửa đổi đáp ứng hệ thống tiêu chuẩn đến những hoạt động chắc chắn (như điều chỉnh menu trước lúc hiển thị); yêu cầu thực hiện một vài hành động trên cửa sổ hay vùng client của nó (cập nhật vùng client); thông tin về tình trạng của nó trong mối quan hệ với các cửa sổ khác (truy xuấ nhất định thất bại của nó tới bàn phím hay trở thành cửa sổ hoạt động).

Một thủ tục cửa sổ nhận hầu hết các thông điệp là từ Windows nhưng nó cũng có thể nhận thông điệp từ các cửa sổ khác gồm cả những cửa sổ nó sở hữu. Những thông điệp này có thể là những yêu cầu về thông tin hay thông báo mà một sư kiện được đưa ra đã xảy ra trong một cửa sổ khác. Một thủ tục cửa sổ tiếp tục nhận thông điệp fừ hệ thống và có thể chấp nhận những cửa sổ khác trong hệ thống cho đến khi thủ tục cửa sổ, thủ tục cửa sổ của một cửa sổ cha mẹ hay hệ thống hủy cửa sổ. Ngay cả khi cửa sổ ở trong quá trình đang bị hủy, thủ tục cửa sổ nhận những thông điệp thêm vào đưa tới nó cơ hội để tiến hành bất kỳ nhiệm vụ làm sạch (cleanup) nào trước lúc kết thúc. Những thông điệp này gồm WM, WM_DESTROY, WM_QUERYENDSESSION và WM_ENDSESSION. Nhưng khi cửa sổ bị hủy thì không có thêm thông điệp nào được đưa tới thủ tục cho cửa sổ cụ thể đó. Nếu có nhiều hơn một cửa sổ của lớp, tuy nhiên, thủ tục cửa sổ tiếp tục nhận thông điệp cho những cửa sổ khác cho đến khi cũng chính chúng bị hủy. Một thủ tục cửa sổ chỉ rõ làm thế nào tất cả cửa sổ của một cửa sổ đưa ra thực sự có hành vi bằng cách đáp ứng những gì các cửa sổ tạo ra những lệnh từ user hay hệ thống. Thủ tục cửa sổ phải kiểm tra những thông điệp mà nó nhận từ hệ thống và quyết định bất kỳ hành động gì sẽ diễn ra. Thủ tục cửa sổ cũng có thể chọn không đáp ứng một thông điệp được

Page 17: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

đưa ra. Nếu không đáp ứng thủ tục phải chuyển thông điệp tới hàm DefWindowProc để đưa cho hệ thống cơ hội để đáp ứng. Hàm này thực hiện hành động có sẵn trên cơ sở thông điệp được đưa ra và những thông số của nó. Nhiều thông điệp (đặc biệt là thông điệp vùng non-client) phải được xử lý vì thế DefWindowProc được yêu cầu trong tất cả các thủ tục cửa sổ.

Thủ tục cửa sổ cũng nhận các thông điệp mà thực sự đã dự định được xử lý bởi hệ thống. Những thông điệp vùng-nonclient thông báo cho thủ tục biết user thực hiện một vài hành động trong vùng client của cửa sổ hoặc một vài thông tin về cửa sổ được yêu cầu bởi hệ thống để thực hiện một hành động. Mặc dù Windows chuyển những thông điệp này tới thủ tục cửa sổ thì thủ tục sẽ chuyển chúng cho hàm DefWindowProc và không cố gắng xử lý chúng. Ở trường hợp này thủ tục cửa sổ phải phớt lờ thông điệp hay trả về không chuyển nó tới DefWindowProc.

3) Thông điệp cửa sổ:

Một thông điệp cửa sổ là một tập những giá trị mà Windows gởi tới thủ tục cửa sổ để cung cấp input cho cửa sổ hay yêu cầu cửa sổ thực hiện một vài hành động. Windows tính đến một sự thay đổi rộng khắp những thông điệp mà nó hay ứng dụng của nó có thể gởi tới thủ tục cửa sổ. Hầu hết những thông điệp được gởi tới cửa sổ như là kết quả của hàm đưa ra đang được thực thi hay như là kết quả của input từ user. Mỗi thông điệp gồm 4 giá trị: một handle xác định cửa sổ, một danh hiệu thông điệp, một giá trị thông điệp-đặc biệt 16-bit và một giá trị thông điệp-đặc biệt 32-bit. Những giá trị này được chuyển tới thủ tục cửa sổ như là những thông số riêng lẻ. Rồi thủ tục cửa sổ kiểm tra danh hiệu thông điệp để quyết định những đáp ứng gì phải làm và làm thế nào để thông dịch giá trị 16-bit và 32-bit.

Cú pháp thủ tục cửa sổ:

- LONG FAR PASCAL WndProc(hwnd, wMsg, wParam, lParam) HWND hwnd; WORD wMsg; WORD wParam; DWORD lParam;

Các thông số:

hwnd cho biết cửa sổ nhận thông điệpwMsg loại thông điệpwParam thông tin thông điệp-đặc biệt thêm vào 16-bitlParam thông tin thông điệp-đặc biệt thêm vào 32-bit

Hàm trả về giá trị 32-bit cho biết kết quả xử lý thông điệp

Page 18: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

4 - Default window procedure:

Hàm DefWindowProc là phần xử lý thông điệp có sẵn cho những thủ tục cửa sổ không hay không thể truy xuất một vài thông điệp được gởi tới cho chúng. Hầu hết các thủ tục cửa sổ thì hàm DefWindowProc thực hiện hầu hết, nếu không muốn nói là tất cả, việc xử lý thông điệp vùng client. Đây là các thông điệp biểu hiện những hành động được thực hiện trên các phần khác của cửa sổ hơn là vùng client.

5 - Vấn đề tô vẽ màn hình:

Khi một cửa sổ bị di chuyển thì Windows tự động sao chép nội dung của vùng client tới vị trí mới. Điều này tiết kiệm thời gian bởi vì một cửa sổ không phải tính toán lại và vẽ lại nội dung của vùng client như là phần của sự di chuyển. Nếu cửa sổ di chuyển hay thay đổi kích thước thì Windows chỉ sao chép phần lớn vùng client trước đó khi nó cần điền vị trí mới. Nếu cửa sổ gia tăng kích thước thì Windows sao chép toàn bộ vùng client và gởi thông báo WM_PAINT tới cửa sổ để điền vào trong vùng được phơi bày mới hơn. Khi cửa sổ bị di chuyển thì Windows cho rằng nội dung của vùng client vẫn hợp lệ và có thể được sao chép không cần thay dổi tới vị trí mới. Tuy nhiên với một vài cửa sổ thì nội dung của vùng client không còn hợp lệ sau khi di chuyển đặc biệt là nếu di chuyển luôn sự thay đổi kích thước. Để tô vẽ lại toàn bộ vùng client thay cho sao chép nội dung trước đó mỗi lần một cửa sổ thay đổi kích thước thì một cửa sổ sẽ xác định kiểu CS_VREDRAW và trong lớp cửa sổ.

Để quản lý hiển thị màn hình, Windows tiến hành nhiều hoạt động ảnh hưởng tới nội dung của vùng client. Nếu Windows di chuyển, định kích thước hay thay đổi bề mặt màn hình, sự thay đổi có thể ảnh hưởng cửa sổ được đưa ra. Nếu vậy, Windows đánh dấu vùng bị thay đổi bằng hoạt động sẵn sàng cho việc cập nhật và ở cơ hội tiếp theo nó gởi thông điệp WM_PAINT tới cửa sổ vì thế nó có thể cập nhật cửa sổ trong vùng cần cập nhật. Nếu một cửa sổ vẽ trong vùng client của nó thì nó phải gọi BeginPaint để lấy handle của ngữ cảnh màn hình, phải cập nhật vùng bị thay đổi như đã định nghĩa bởi vùng cập nhật và cuối cùng nó phải gọi EndPaint để hoàn tất công việc. Một cửa sổ có thể vẽ trong vùng client của nó bất kỳ lúc nào tức là ngoài thời điểm mà nó đáp ứng thông điệp WM_PAINT chỉ cần nó lấy ngữ cảnh màn hình cho vùng client trước lúc nó tiến hành vẽ.

Thông điệp WM_PAINT: là một yêu cầu của Windows tới một cửa sổ để cập nhật màn hình cửa nó. Windows gởi WM_PAINT bất cứ khi nào cần vẽ một phần lại cửa sổ. Khi cửa sổ nhận thông điệp WM_PAINT thì nó sẽ lấy vùng cập nhật bằng hàm BeginPaint và nó sẽ tiến hành bất kỳ hoạt động gì cần thiết để cập nhật phần đó của vùng client.

InvalidateRect và InvalidateRgn thực sự không sinh ra thông điệp WM_PAINT. Windows tích luỹ những thay đổi được tạo ra bởi các hàm này và những thay đổi của riêng nó trong lúc một cửa sổ xử lý những thông điệp khác trong

Page 19: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

hàng thông điệp của nó. Làm trễ WM_PAINT làm cho cửa sổ xử lý tất cả những thay đổi cùng một lúc thay vì cập nhật những những mẫu nhỏ trong những bước riêng lẻ làm lãng phí thời gian.

Để chỉ thị Windows gởi thông điệp WM_PAINT một ứng dụng có thể sử dụng UpdateWindow, hàm này gởi thông điệp trực tiếp tới cửa sổ, bất chấp những thông điệp khác trong hàng thông điệp của ứng dụng. UpdateWindow được sử dụng khi một cửa sổ cần cập nhật vùng client của nó ngay lập tức (chẳng hạn chỉ ngay sau cửa sổ được tạo). Khi một cửa sổ nhận WM_PAINT nó phải gọi BeginPaint để lấy ngữ cảnh màn hình cho vùng client và lấy thông tin khác như vùng cập nhật và background bị xóa hay không. Windows tự động chọn vùng cập nhật như là vùng xén của ngữ cảnh màn hình. GDI huỷ bỏ (xén) những gì được vẽ bên ngoài vùng xén chỉ những gì ở bên trong vùng cập nhật là thực sự nhìn thấy được. BeginPaint xóa vùng cập nhật để ngăn chặn vùng giống nhau từ việc sinh ra các thông điệp WM_PAINT đến sau. Sau khi vẽ xong Windows phải gọi hàm EndPaint để giải phóng DC.

Vùng cập nhật: Một vùng cập nhật xác định phần của vùng client được đánh dấu cho việc vẽ cho thông điệp WM_PAINT kế tiếp. Mục đích của vùng cập nhật là để lưu các ứng dụng thời điểm nó đưa ra để vẽ toàn bộ nội dung của vùng client. Nếu chỉ có phần mà cần vẽ được cộng vào vùng cập nhật thì chỉ có phần đó được vẽ.

Hàm InvalidateRect và InvalidateRgn cộng một hình chữ nhật hay một vùng vào vùng cập nhật. Hình chữ nhật hay vùng phải được đưa ra ở trong tọa độ client. Vùng cập nhật bản thân nó được định nghĩa trong tọa độ client. Windows cộng những vùng và hình chữ nhật của chính nó vào một vùng cập nhật của cửa sổ sau khi những hoạt động như di chuyển, định kích thước và cuộn cửa sổ.

Hàm ValidateRect và ValidateRgn xóa một hình chữ nhật hay một vùng ra khỏi vùng cập nhật. Những hàm này được sử dụng điển hình khi cửa sổ đã cập nhật một phần đặc biệt của màn hình trong vùng cập nhật trước khi nhận thông điệp WM_PAINT.

Hàm GetUpdateRect lấy hình chữ nhật nhỏ nhất bao lấy toàn bộ vùng cập nhật. Hàm GetUpdateRgn lấy vùng cập nhật chính nó. Những hàm này có thể được sử dụng để tính toán kích thước hiện hành của vùng cập nhật để quyết định những công việc vẽ nào được yêu cầu.

V – CHƯƠNG TRÌNH WINDOWS TIẾP NHẬN THÔNG ĐIỆP CHUỘT:

Giới thiệu dòng chảy dữ liệu thông điệp nhập từ con chuột:

Page 20: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

1 - Mouse:

Khi mouse báo vị trí của mình (vị trí cursor) và có tác động lên mouse thì một tín hiệu được phát đi từ mouse gây ra một ngắt quãng, mouse driver giải quyết ngắt quãng này.

2 - Mouse device driver:

Khi Windows khởi động thì mouse driver tự động nạp vào và kiểm tra xem có chuột hay không. Nếu có thì Windows gọi driver cung cấp một thủ tục để báo cáo các biến cố xảy ra trên chuột. Khi có một mouse event thì driver thông báo cho Windows biết. Nếu event là di chuyển mouse thì ưu tiên đáp ứng vị trí con trỏ di chuyển ngay lúc ngắt. Còn lại tất cả các event khác đều được đưa vào hardware event queue.

3 - Hardware event queue:

Các mouse event được đưa vào hardware event queue chờ giao cho message loop của chương trình giải quyết. Queu này là một vùng đệm có thể chứa tối đa 120 event. Những event trong queue chưa thuộc một chương trình cụ thể nào cho tới khi nó được tiếp nhận bởi hàm GetMessage(). Điều này đảm bảo cho hệ thống hoạt động đúng đắn. Sau đó là vòng lặp GetMessage().

4 - GetMessage() loop:

GetMessage() loop đưa các thông điệp vào xử lý. GetMessage() sẽ quyết định chương trình nào sẽ tiếp nhận thông điệp bằng cách xem chương trình nào sở hữu cửa sổ mà con trỏ chuột nằm trên đó. Tùy theo vị trí của con trỏ mà phát sinh hai

Hardware event queue

Device driverMouse GetMessage() DispatchMessage()

WindowProc()

DefWindowProc()

Hook chainVirtual &

Scan code

Page 21: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

loại thông điệp: thông điệp vùng client và thông điệp vùng non-client. Muốn biết cursor ở vùng nào thì GetMessage() chuyển đi một thông điệp WM_NCHITTEST cho thủ tục cửa sổ. Hàm GetMessage() dựa vào cơ chế pull-model để đọc thông tin tình huống trong queue và lại dựa vào push-model để biết vị trí của cursor. Tức là GetMessage() sẽ gọi thủ tục cửa sổ như là một chương trình thường trú vậy. GetMessage() sử dụng hàm SendMessage() để gọi thủ tục cửa sổ. Trị trả về nằm trong phạm vi của thông điệp WM_NCHITTEST mà GetMessage() gởi cho thủ tục cửa sổ của ta. WM_NCHITTEST là thông điệp đến đầu tiên trong hàng loạt thông điệp mà mouse phát ra. Nó yêu cầu thủ tục cửa sổ nhận diện vị trí cursor. Đa số chương trình chuyển thông điệp này cho DefWindowProc() lo tìm vị trí cursor và cung cấp một hit-test code như là trị trả về.

Khi DefWindowProc() trả về kết quả khác HTCLIENT, HTERROR, HTNOWHERE, HTTRANSPARENT thì cursor nằm trên vùng non-client thì Windows sẽ phát đi thông điệp non-client.

Còn khi DefWindows trả về kết quả HTCLIENT thì cursor nằm trên vùng client và những thông điệp do Windows phát đi lúc này thì sẽ được trình ứng dụng xử lý.

Hàm SendMessage() sẽ sử dụng mã hit-test code để quyết định xem loại thông điệp chuột nào mà cho phát sinh. Khi hit-test code bằng HTCLIENT thì một thông điệp vùng client sẽ được phát sinh còn tất cả các hit-test code khác sẽ phát sinh ra những thông điệp chuột vùng non-client.

Trước khi SendMessage() trả về một thông điệp chuột cho chương trình của ta thì có một việc mà hàm này phải thi hành: nó phải bảo đảm là hình dáng cursor phù hợp vị trí hiện thời của mouse. Muốn thế nó phải gởi đi một thông điệp khác cho thủ tục cửa sổ WM_GETCURSOR. Tương tự như thông điệp WM_NCHITTEST đa số chương trình phớt lờ thông điệp này và giao cho DefWindowProc() thực hiện. Mã hit-test code được cho ở trong byte thấp của thông số lParam để cho DefWindowProc() biết mà thiết đặt hình dáng của con trỏ.

Hai thông điệp WM_NCHITTEST và WM_SETCURSOR bao giờ cũng đi trước một thông điệp chuột. Vì Windows phải tìm ra xem vị trí cursor hiện ở trong vùng client hay vùng non-client để phát ra thông điệp vùng client hay thông điệp vùng non-client một cách thích hợp. Một khi đã được nhận diện thì Windows phải đảm bảo là người sử dụng nhận được hình dáng cursor thích hợp.

Windows cho phép đặt message hook để thay đổi dòng chảy các thông điệp. Một WH_GETMESSAGE hook có thể thay đổi dòng chảy của bất cứ thông điệp chuột của vùng client hoặc vùng non-client. Khi GetMessage() sẵn sàng đem một thông điệp vào chương trình của ta thì nó sẽ gọi hook xem có thay đổi gì không trước khi thông điệp được chuyển cho chương trình.

Page 22: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

Khi GetMessage() đã đưa thông điệp vào chương trình rồi thì thông điệp sẽ được trao trực tiếp cho thủ tục cửa sổ thích hợp bởi hàm DispatchMessage(). Bây giờ thông điệp đã nằm trong thủ tục cửa sổ.

5 - Thủ tục cửa sổ:

Hơn 20 thông điệp của Windows về chuột (trừ WM_NCHITTEST) thì có 10 thông điệp thuộc vùng non-client do DefWindowProc() giải quyết. Hai thông số wParam, lParam của thủ tục cửa sổ sẽ cho biết thông tin về thông điệp. Trị của hai thông số lParam và wParam đều tương tự nhau cho các thông điệp chuột trên vùng client.

Trị của thông số lParam chứa vị trí cursor theo tọa độ của vùng client. Tọa độ này cho origin về góc upper-left của vùng client với đơn vị tính là pixel. Trị x nằm ở word thấp còn y nằm ở word cao của lParam.

Trị của wParam là một lô cờ hiệu mô tả trạng thái của các nút chuột cũng như trạng thái các nút <Ctrl>, <Shift>

6 – DefWindowProc():

Đối với chuột thì DefWindowProc() không quan tâm đến những thông điệp thuộc vùng client mà chỉ quan tâm đến những thông điệp thuộc vùng non-client.

DefWindowProc() có nhiệm vụ cung cấp một giao diện chung cho bàn phím và con chuột bằng cách dịch phần nhập liệu từ bàn phím hoặc con chuột thành các lệnh hệ thống (system command) và cho hiện lên như các thông điệp WM_SYSCOMMAND. Cuối cùng DefWindowProc() giải quyết các thông điệp WM_NCHITTEST và WM_SETCURSOR cung cấp trước cho các thông điệp chuột khác.

Page 23: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

Chương 2:

TÌM HIỂU VỀ HOOKSTÌM HIỂU VỀ HOOKS

Page 24: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

Hook là một cơ chế cực mạnh cho phép ta cài đặt một thủ tục để điều khiển hoặc chận hứng các thông điệp trước khi các thông điệp này tới được nơi tiếp nhận.

Hay nói một cách khác hook là một điểm trong kỹ thuật message-handling hệ thống, nơi mà một ứng dụng có thể đặt một thủ tục để quản lý sự lưu thông của các thông điệp trong hệ thống và xử lý một kiểu thông báo nào đó trước khi chúng tới được thủ tục cửa sổ đích.

Do có khả năng can thiệp mạnh nên hook có xu hướng làm chậm lại hệ thống vì chúng làm tăng số lượng các hoạt động của hệ thống đối với mỗi thông điệp. Chỉ đặt hook khi thực sự cần thiết và dỡ bỏ chúng khi không cần đến.

1 - Chuỗi hook:

Hệ thống cho phép nhiều kiểu hook khác nhau: mỗi kiểu cung cấp việc truy xuất tới một khía cạnh khác nhau của kỹ thuật message-handling. Chẳng hạn, một ứng dụng có thể sử dụng hook WM_MOUSE để quản lý những thông điệp chuột trong luồng thông điệp.

Hệ thống duy trì một chuỗi hook riêng lẻ đối với mỗi kiểu hook. Một chuỗi hook là một danh sách các pointer chỉ tới các hàm callback application-defined đặc biệt mà những hàm này gọi các thủ tục hook. Khi một thông điệp xảy ra là nó đã được tổ chức với một kiểu hook cụ thể, hệ thống chuyển thông điệp tới mỗi thủ tục hook có mặt trong chuỗi hook, theo trật tự cái nọ sau cái kia. Hoạt động của một thủ tục hook có thể phụ thuộc vào kiểu hook mà nó liên quan. Các thủ tục hook cho một vài kiểu hook có thể chỉ quản lý những thông điệp; những cái khác có thể thay đổi những thông điệp hay dừng sự phát triển của nó trong chuỗi, ngăn chặn chúng tìm tới thủ tục hook kế tiếp hay cửa sổ cuối cùng (đích).

2 – Thủ tục hook:

Để có được sự tiện lợi của một loại hook chi tiết, người lập trình cung cấp một thủ tục hook và sử dụng hàm SetWindowsHookEx để đặt nó vào trong chuỗi hook. Một thủ tục hook có cú pháp:

- LRESULT CALLBACK HookProc (Int nCode,WPARAM wParam,LPARAM lParam

);

HookProc là một placeholder cho một ứng dụng đã được định nghĩa trước.

Thông số nCode là một mã hook phụ thuộc vào kiểu hook; mỗi kiểu có một tập các đặc tính các mã hook. Những giá trị của thông số wParam và lParam phụ thuộc vào mã hook, nhưng điển hình thì chúng chứa thông tin về một thông điệp

Page 25: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

được send hay được post. Hàm SetWindowsHookEx luôn luôn đặt một thủ tục hook ở đầu một chuỗi hook. Khi một sự kiện xảy ra mà sự kiện này được quản lý bởi một kiểu hook cụ thể thì hệ thống gọi thủ tục ở đầu chuỗi hook đã được tổ chức. Mỗi thủ tục hook trong chuỗi quyết định nên chuyển hay không chuyển sự kiện tới thủ tục tiếp theo. Một thủ tục hook chuyển một sự kiện tới thủ tục tiếp theo bằng cách gọi hàm CallNextHookEx. Chú ý rằng những thủ tục hook dành cho các kiểu hook chỉ có thể quản lý các thông điệp, hệ thống chuyển thông điệp tới mỗi thủ tục hook, chứ không dính dáng gì đến có hay không một thủ tục cụ thể gọi CallNextHookEx. Một thủ tục hook có thể toàn cục, quản lý những thông điệp đối với tất cả các thread trong hệ thống hay nó có thể là thread cụ thể, quản lý các thông điệp cho chỉ một thread riêng biệt. Một thủ tục hook toàn cục có thể được gọi trong ngữ cảnh của bất kỳ ứng dụng nào, bởi thế thủ tục phải ở trong một module DLL riêng lẻ. Một thủ tục hook loại thread cụ thể chỉ được gọi trong ngữ cảnh của thread đã được tổ chức. Nếu một ứng dụng đặt một thủ tục hook cho một trong các thread của riêng nó thì thủ tục hook có thể ở trong cả module giống nhau như quãng nghĩ giữa các mã ứng dụng hoặc trong một DLL. Nếu ứng dụng đặt một thủ tục hook cho một thread của một ứng dụng khác thì thủ tục phải ở trong một DLL. Chú ý chỉ sử dụng hook toàn cục cho mục đích debug còn không thì nên tránh không sử dụng. Hook toàn cục có thể gây tổn hại cho hoạt động của hệ thống và gây nên xung đột với những ứng dụng khác có cùng kiểu hook toàn cục.

3 – Các loại hook:

Một loại hook làm cho một ứng dụng có thể quản lý một mặt khác nhau của kỹ thuật message-handling hệ thống.

Bao gồm các loại hook sau đây:

- WH_CALLWNDPROC 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 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 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 hook có ích cho việc debug những thủ tục hook khác.

- WH_FOREGROUNDIDLE 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 hook quản lý các thông điệp được post tới hàng thông điệp.

Page 26: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

- WH_JOURNALPLAYBACK hook post những thông điệp được ghi trước đó bởi thủ tục hook WH_JOURNALRECORD.

- WH_JOURNALRECORD 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 hook quản lý các thông điệp keystroke.

- WH_KEYBOARD_LL Windows NT: hook quản lý những sự kiện nhập vào từ keyboard mức thấp.

- WH_MOUSE hook quản lý các thông điệp chuột.

- WH_MOUSE_LL Windows NT: hook quản lý những sự kiện đầu vào chuột mức thấp.

- WH_MSGFILTER 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 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.

4 – Sử dụng hook:

a) Cài đặt hook:

Đặt một thủ tục hook bằng cách gọi hàm SetWindowsHookEx đặc tả kiểu hook gọi thủ tục, thủ tục có phải được tổ chức với tất cả các thread hay chỉ được tổ chức với một thread cụ thể và một pointer chỉ tới một điểm vào thủ tục. Phải đặt một thủ tục hook toàn cục vào một DLL riêng biệt từ ứng dụng cài đặt thủ tục hook. Ứng dụng cài đặt phải có handle chỉ tới module DLL trước khi nó có thể đặt thủ tục hook. Hàm LoadLibrary khi được đưa tên của DLL sẽ trả handle cho module DLL. Sau khi có handle, có thể gọi hàm GetProcAddress để lấy lại địa chỉ của thủ tục hook. Cuối cùng sử dụng hàm SetWindowsHookEx để đặt địa chỉ hook vào trong chuỗi hook dành riêng. SetWindowsHookEx chuyển handle module, một pointer chỉ tới điểm vào thủ tục hook và cho danh hiệu thread, chỉ ra rằng thủ tục hook phải được tổ chức với tất cả các thread trong hệ thống.

Ví dụ minh họa:

HOOKPROC hkprcSysMsg;

Page 27: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

static HINSTANCE hinstDLL;static HHOOK hhookSysMsg;

hinstDLL = LoadLibrary("c:\windows\sysmsg.dll");hkprcSysMsg = (HOOKPROC)GetProcAddress(hinstDLL,

SysMessageProc);hhookSysMsg = SetWindowsHookEx (WH_SYSMSGFILTER,

hkprcSysMsg, hinstDLL, 0 );

b) Giải phóng hook:

Có thể giải phóng một procedure loại thread cụ thể tức xóa địa chỉ của nó khỏi chuỗi hook bằng cách gọi hàm UnhookWindowsHookEx nhưng hàm này không trả tự do cho DLL chứa thủ tục hook. Đây là lý do mà thủ tục hook toàn cục được gọi trong ngữ cảnh quá trình của mỗi ứng dụng trong hệ thống, gây nên một gọi tuyệt đối tới hàm LoadLibrary cho tất cả các quá trình đó. Bởi vì một gọi tới hàm FreeLibrary không thể được tạo ra cho một quá trình khác, rồi thì không có cách nào để giải phóng cho DLL. Hệ thống cuối cùng giải phóng DLL sau khi tất cả các quá trình nối hoàn toàn với DLL đã kết thúc hay gọi FreeLibrary và tất cả các quá trình đã gọi thủ tục hook lại tiếp tục quá trình xử lý bên ngoài DLL. Một phương pháp lựa chọn cho việc đặt thủ tục toàn cục là cung cấp một hàm cài đặt trong DLL, cùng với thủ tục hook. Với phương pháp này, ứng dụng cài đặt không cần handle chỉ tới module DLL. Bằng cách nối với DLL, ứng dụng gia tăng việc truy xuất tới hàm cài đặt. Hàm cài đặt có thể cung cấp handle module DLL và những chi tiết khác ở trong cái gọi tới SetWindowsHookEx. DLL cũng có thể chứa một hàm giải phóng thủ tục hook toàn cục; ứng dụng có thể gọi hàm giải phóng hook này khi kết thúc.

5 – Hook trong Windows 3.x:

Hook là một điểm trong kỹ thuật message-handling của Windows mà một ứng dụng có thể sử dụng để làm tăng khả năng truy xuất tới dòng thông điệp. Windows cung cấp nhiều kiểu hook khác nhau, mỗi kiểu cho phép truy xuất tới một kiểu thông điệp cụ thể hay một vùng các thông điệp. Để có được một hook cụ thể thì một ứng dụng có thể cài đặt một hàm lọc (filter function) để xử lý những thông điệp được tổ chức với hook. Một hàm lọc xử lý những thông điệp trước khi chúng đến thủ tục cửa sổ đích.

Chuỗi hàm lọc (Filter-Function Chain):

Một chuỗi hàm lọc là một loạt những hàm lọc họ hàng cho một hook hệ thống cụ thể. Một ứng dụng chuyển một hàm lọc cho một hook hệ thống bằng cách gọi hàm SetWindowsHook. Mỗi lần gọi thì cộng thêm một hàm lọc mới vào đầu của

Page 28: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

chuỗi. Bất cứ khi nào một ứng dụng chyển địa chỉ một hàm lọc cho hook hệ thống nó phải giữ vùng nhớ cho địa chỉ hàm lọc kế tiếp trong chuỗi. SetWindowsHook cài một hàm hook vào chuỗi hook và trả về handle của hook. Khi mỗi hàm lọc hoàn thành nhiệm vụ nó phải gọi hàm DefHookProc, hàm này sử dụng địa chỉ được lưu trong vị trí được giữ bởi ứng dụng để truy xuất hàm lọc kế tiếp trong chuỗi. Để xóa một hàm lọc trong chuỗi lọc một ứng dụng phải gọi hàm UnhookWindowsHook với thông số là kiểu hook và một con trỏ chỉ tới hàm.

Sau đây là các hook cửa sổ tiêu chuẩn:Kiểu Chức năngWH_CALLWNDPROC Cài đặt lọc cửa sổ WH_CBT Cài đặt lọc computer-based training (CBT)WH_DEBUG Cài đặt lọc debugWH_GETMESSAGE Cài đặt lọc thông điệp (chỉ trên những

version debug)WH_HARDWARE Cài đặt lọc thông điệp-phần cứng không tiêu

chuẩnWH_JOURNALPLAYBACK Cài đặt lọc journaling playbackWH_JOURNALRECORD Cài đặt lọc journaling record WH_KEYBOARD Cài đặt lọc bàn phímWH_MOUSE Cài đặt lọc thông điệp chuộtWH_MSGFILTER Cài đặt lọc thông điệpWH_SYSMSGFILTER Cài đặt lọc thông điệp trên toàn hệ thống

Trong đó hook WH_CALLWNDPROC và WH_GETMESSAGE ảnh hưởng hoạt động của hệ thống, chỉ sử dụng để debug.

Để cài đặt một hàm lọc thì ứng dụng phải trải qua 4 bước:

1 - Export hàm trong file .DEF2 - Lấy địa chỉ hàm bằng cách dùng hàm GetProcAddress (MakeProcInstance

chỉ được sử dụng khi hàm lọc không ở trong một DLL)3 - Gọi SetWindowsHook , xác định kiểu hàm hook và địa chỉ của hàm (được

trả về bởi GetProcAddress) 4 - Lưu giá trị trả về từ SetWindowsHook trong vị trí được giữ. Giá trị này là

handle của hàm lọc trước.

Những hàm cho hook toàn hệ thống phải được cho vào trong một DLL.

Như vậy qua những lý thuyết về hook trong môi trường Win32 hay trong môi trường Win16 cho chúng ta có nhận xét: dùng kỹ thuật hook cho phép ta đặt một thủ tục để theo dõi, điều khiển và xử lý các thông điệp của hệ thống Windows theo ý của ta trước lúc thông điệp đó đến được cửa sổ đích. Tuy nhiên kỹ thuật hook ở

Page 29: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

trong môi trường Win32 mạnh hơn, nó có thể cho phép ta thực hiện được các công việc có vai trò tương tự như kỹ thuật override trong Win16.

6 - Giới thiệu một số hàm có liên quan đến hook:

a) CallMsgFilter:

- Cú pháp:

BOOL CallMsgFilter(lpmsg, nCode)MSG FAR* lpmsg;int nCode;

- CallMsgFilter chuyển thông điệp đưa ra và mã tới hàm lọc thông điệp hiện hành. Hàm lọc thông điệp là một hàm đặc tả ứng dụng kiểm tra và sửa đổi tất cả các thông điệp. Một ứng dụng xác định hàm bằng cách sử dụng hàm SetWindowsHook.

- Thông số:

lpmsg trỏ tới cấu trúc MSG chứa thông điệp được lọc.

nCode xác định một mã được sử dụng bởi hàm lọc để quyết định làm thế nào để truy xuất thông điệp.

- Giá trị trả về: chỉ ra trạng thái của quá trình xử lý thông điệp. Trả về 0 nếu thông điệp được xử lý và khác 0 nếu thông điệp không được xử lý.

- Chú ý: hàm CallMsgFilter thường được gọi bởi Windows để cho các ứng dụng kiểm tra và điều khiển luồng thông điệp trong suốt quá trình xử lý nội ở trong menu, scroll bar hay khi di chuyển hoặc làm thay đổi kích thước một cửa sổ.

b) SetWindowsHookEx:

- Cú pháp:

HHOOK SetWindowsHookEx(idHook, hkprc, hinst, htask)int idHook;HOOKPROC hkprc;HINSTANCE hinst;HTASK htask;

- Hàm SetWindowsHookEx cài đặt một hàm hook application-defined vào trong một chuỗi hook. Hàm này là version mở rộng của hàm SetWindowsHook.

- Thông số:

Page 30: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

idHook Kiểu của hook được cài đặt. Thông số này gồm các kiểu hook như đã trình bày ở phần lý thuyết nêu trên.

hkprc Địa chỉ procedure-instance của thủ tục hook application-defined được cài đặt.

hinst Instance của module chứa hàm hook.

htask Nhiệm vụ cho hook được cài đặt. Nếu NULL thì hàm hook được cài đặt có tầm vực hệ thống và có thể được gọi ở trong ngữ cảnh của bất kỳ quá trình nào hay nhiệm vụ nào ở trong hệ thống.

- Giá trị trả về: giá trị trả về là handle của hook được cài đặt nếu hàm thành công. Ứng dụng hay thư viện phải sử dụng handle này để xác định hook khi nó gọi hàm CallNextHookeEx và UnhookWindowsHookEx. Giá trị trả về là NULL nếu có lỗi.

c) Hàm gỡ bỏ một hàm hook UnhookWindowsHookEx:

- Cú pháp:

BOOL UnhookWindowsHookEx(hhook)HHOOK hhook;

- Hàm UnhookWindowsHookEx bỏ đi một hàm hook application ra khỏi một chuỗi hàm hook. Một hàm hook xử lý các sự kiện trước khi chúng được gởi tới vòng lặp thông điệp ứng dụng trong hàm WinMain.

- Thông số:

hhook Chỉ ra hàm hook được dỡ bỏ. Đây là giá trị được trả về bởi hàm SetWindowsHookExIdentifies khi hàm hook được cài đặt.

- Chú ý: Hàm UnhookWindowsHookEx phải được sử dụng trong sự kiết hợp với hàm SetWindowsHookEx.

d) Hàm gọi hook kế tiếp trong hook-chain CallNextHookEx:

- Cú pháp:LRESULT CallNextHookEx(hHook, nCode, wParam, lParam)

HHOOK hHook;int nCode;WPARAM wParam;LPARAM lParam;

- Hàm CallNextHookEx function chuyển các thông tin hook đến hàm xử lý hook kế tiếp trong hook chain.

- Thông số

Page 31: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

hHook Chỉ định hook handle nCode Chỉ định hook code để gởi đến hook kế tiếp. Hàm xử lý hook dùng

giá trị này để chỉ định xử lý thông điệp được gởi từ hook thế nào. wParam Chỉ định 16 bits thông tin mở rộng của thông điệplParam Chỉ định 32 bits thông tin mở rộng của thông điệp

- Giá trị trả về: Giá trị trả về là kết quả của quá trình xử lý và tùy thuộc vào thông số nCode.

Page 32: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

Chương 3:

KỸ THUẬT OVERRIDEKỸ THUẬT OVERRIDEHÀM APIHÀM API

Page 33: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

I - Khái quát về kỹ thuật override:

Override có nghĩa là: Thay thế một giá trị lúc run-time cho một giá trị đã có trong tập tin hoặc trong chương trình. Hoặc tạo ra một đáp ứng lúc run-time thay cho tình huống dự kiến trong chương trình.

Đối với các hàm giao tiếp trong môi trường Windows thì khi Windows gọi đến các DLL (Dynamic Link Library – Thư viện liên kết động) tại các điểm nhập của các hàm Kernel, User, GDI… để xử lý các hàm được gọi trong ứng dụng thì chính ở thời điểm này ta có thể chen vào để có thể thực hiện việc hoàn tất bất kỳ thao tác xử lý gì. Việc chen vào ở thời điểm đó sẽ có 2 cách như sau dựa vào thời điểm để chen vào:

- Cách 1: chen vào trước khi hàm API bị gọi được thi hành (front-end processing)

- Cách 2: sau khi hàm API đã kết thúc việc thực thi thì ta cho chen vào dẫn đến việc thực thi một thao tác gì hoặc một công việc theo yêu cầu của ta (back-end processing).

Như vậy override các hàm thuộc giao tiếp Windows là một kỹ thuật cho phép developer can thiệp vào tiến trình gọi hàm API nhằm thực hiện một thao tác, một công việc gì đó theo mục đích của developer trước khi quá trình thực thi hàm API bắt đầu (theo cách 1) hoặc là ngay sau khi đã kết thúc việc thực thi hàm API (theo cách 2).

II - Lý do để sử dụng kỹ thuật override trong lập trình trên môi trường Windows:

Như vậy nếu sử dụng kỹ thuật override thì developer có thể lập trình để chen vào tiến trình thực thi các hành vi, thao tác xử lý riêng của mình bằng cách đón đợi thông báo gọi hàm API tương ứng từ chương trình ứng dụng và chuyển hướng điều khiển cho thực thi đoạn chương trình riêng đó mà không cần sửa đổi, biên dịch lại chương trình ứng dụng. Khi không cần thiết thì cơ chế override có thể được tắt đi và chương trình ứng dụng có thể trở về thực thi bình thường đúng chức năng của mình . Ngoài ra, override các hàm Windows API là một quá trình can thiệp động vào hệ thống nên kỹ thuật override là rất cần thiết trong trường hợp developer muốn bổ xung thêm hoặc sửa đổi một số tính năng hoạt động của tất cả hay chỉ một số ứng dụng đang chạy trong hệ thống mà không cần phải sửa chữa hay biên dịch lại các chương trình nguồn của ứng dụng. Mà dù có muốn thì developer cũng không thể làm được điều này bởi vì Windows không cho phép thâm nhập cũng như công bố bản mã nguồn của các ứng dụng đó. Từ đó ta thấy override xử lý các tình huống

Page 34: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

này hoàn toàn một cách tự động. Như vậy, trong Windows thì kỹ thuật override là một trong những kỹ thuật có thể được dùng như là phương tiện nâng cao tính năng của chương trình ứng dụng mà vẫn được sự chấp thuận của hệ thống Windows.

Một vài chương trình xử lý ngắt trong hệ điều hành DOS có thể được override bởi đoạn chương trình xử lý ngắt riêng của user bằng cách gán địa chỉ bộ nhớ nơi mà chương trình xử lý ngắt mới vào bảng vector ngắt tương ứng với số hiệu ngắt đồng thời lưu giữ địa chỉ của chương trình xử lý ngắt để trở về hoặc phục hồi bảng vector ngắt khi cần thiết. Mỗi khi có ngắt xảy ra hệ thống sẽ tham khảo bảng vector ngắt để xác định địa chỉ của chương trình phục vụ cần thi hành và chuyển điều khiển đến đó, lúc này đoạn chương trình của user có địa chỉ đặt trong bảng vector ngắt mới sẽ thực thi. Điểm trở về của chương trình sẽ do user quyết định: chuyển điều khiển đến lệnh kế tiếp sau lệnh đã xảy ra ngắt hoặc tiếp tục thi hành lệnh ngắt cũ rồi mới trở về. Từ đó trong Windows chúng ta sẽ tìm cách trỏ tới địa chỉ đoạn chương trình sẽ override hàm API thay vì hệ thống phải chuyển điều khiển tới địa chỉ đoạn mã thực sự của hàm API mỗi khi hàm được gọi.

Tuy nhiên do cơ chế quản lý bộ nhớ của Windows khác với DOS nên chúng ta phải tìm hiểu thật kỹ về cơ chế quản lý bộ nhớ của Windows để có thể tìm ra được giải pháp kỹ thuật thật tốt cho vấn đề override. Đặc biệt chúng ta cũng cần tìm hiểu sự khác nhau giữa Windows 16-bit và Windows 32-bit.

III - Cơ chế hoạt động và quản lý bộ nhớ trên Windows 16bits:

Windows 16bits tự động chạy ở chế độ “386 enhanced mode” ở các máy 386, bộ nhớ tối thiểu 2MB. Đó thực chất là chế độ standard với 2 đặc tính bổ sung:

Windows dùng các thanh ghi trang của 386 để hiện thực bộ nhớ ảo

Windows sử dụng chế độ ảo 8086 của 386 để đáp ứng chế độ đa nhiệm MS-DOS.

Chế độ 386 enhanced và chế độ standard đem lại cho Windows những lợi ích từ cơ chế bảo vệ (protected mode) của các bộ vi xử lý 286, 386.

Bộ nhớ mở rộng (extended memory) được bổ sung trực tiếp vào bộ nhớ conventional (conventional memory) và được sử dụng như một khối nhớ liên tục. Cơ chế bảo vệ còn cung cấp các hỗ trợ đặc biệt về quản lý bộ nhớ mà ở chế độ thực không có như việc áp buộc các truy xuất bộ nhớ phải tuân thủ một số quy luật nhằm trợ giúp đảm bảo tính toàn vẹn của mỗi chương trình, của mỗi dữ liệu của chương trình và của chính bản thân hệ thống.

Các ứng dụng Windows trong chế độ này có thể truy xuất đến một vùng nào đó trên đĩa cứng và sử dụng nó như một phần của bộ nhớ. Để truy xuất đúng phần địa chỉ ảo này Windows có bộ quản lý bộ nhớ ảo VMM (Virtual Memory Manager),

Page 35: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

nó làm việc cùng với phần cứng phân trang được thiết kế sẵn trong con 386. Trong chế độ này, không gian địa chỉ có thể lên gấp 4 lần kích thước bộ nhớ vật lý khả dụng.

Chế độ bảo vệ (protected mode): là trạng thái của bộ vi xử lý quy định một số quy luật khi bộ nhớ được đánh địa chỉ nhằm làm giảm những rủi ro mà chương trình có thể ghi đè phần bộ nhớ không thuộc về nó. Trong chế độ bảo vệ một chương trình sẽ dùng một segment gồm 2 phần: segment identifier và offset để đánh địa chỉ bộ nhớ. Sự chuyển đổi từ địa chỉ luận lý sang địa chỉ vật lý như sau: bộ vi xử lý sẽ tham khảo các bảng miêu tả (descriptor table) (bảng chứa dữ liệu đặc biệt) được hệ điều hành khởi tạo và quản lý. Có 2 loại: bảng miêu tả toàn cục GDT (Global Descriptor Tables) và bảng miêu tả cục bộ LDT (Local Descriptor Table). Một bảng miêu tả gồm một mảng các mẫu tin về thông tin của segment được gọi là bộ miêu tả phân đoạn (segment selector). Phần địa chỉ bộ nhớ mà chúng ta gọi là segment identifier được tham khảo đến như là một bộ chọn phân đoạn (segment selector). Một segment selector là một chỉ số vào mảng các bộ miêu tả tạo nên bảng miêu tả, nó xác định segment descriptor cung cấp chi tiết cần thiết để truy xuất phân đoạn dữ liệu.

Khi chương trình tham chiếu đến một vị trí nhớ, CPU sẽ nạp segment descriptor vào các thanh ghi đặc biệt để xác định địa chỉ vật lý của segment sau đó offset được cộng vào địa chỉ nền (base address) để truy xuất đến các byte bộ nhớ mong muốn.

Cấu trúc của bộ chọn chế độ bảo vệ (protected mode selector): chỉ có 13 trong số 16 bit giá trị segment được dùng như chỉ số của bảng miêu tả, 3 bit còn lại chia thành 2 phần quan trọng trong sơ đồ địa chỉ hóa và cơ chế bảo vệ. Bit 2 là cờ báo bảng miêu tả nào đang được dùng cho phép hệ điều hành thiết lập không gian địa chỉ của chương trình bằng cách dùng 2 bảng miêu tả: GDT bao hàm toàn bộ bộ nhớ được chia sẻ cho toàn hệ thống còn LDT là không gian địa chỉ riêng của chương trình. Bit 0 và bit 1 mô tả mức đặc quyền yêu cầu của phân đoạn RPL (requested privilege level), chúng được phần mềm hệ điều hành thiết lập để khởi tạo và ép buộc sơ đồ bảo vệ bộ nhớ với 4 mức đặc quyền (0,1,2,3): mức 0 là cao nhất dành riêng cho hầu hết phần mềm hệ điều hành tin cậy. Các chương trình và thư viện Windows được đặc thường trú ở mức đặc quyền thấp nhất – vành 3 để giải phóng và trao các mức đặc quyền cao hơn cho các thành phần khác của hệ điều hành.

Trong chế độ hỗ trợ bộ nhớ ảo của Windows: chỉ có trong chế độ 386 enhanced và cùng làm việc bên cạnh cơ chế bảo vệ. Các byte dữ liệu cần làm việc được xác định giống như ở chế độ bảo vệ bình thường nhưng khác ở chỗ cách dịch địa chỉ base+offset. Trong chế độ bảo vệ bình thường địa chỉ bộ nhớ dịch ra là địa chỉ vật lý. Nhưng trong chế độ 386 enhanced phần cứng phân trang được thiết kế sẵn trong bộ vi xử lý Intel 80386 sẽ được kích hoạt cho phép địa chỉ được xem như

Page 36: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

là một địa chỉ ảo. Các giá trị segment và offset sẽ được giải mã để thành không gian địa chỉ ảo. Không gian địa chỉ ảo này được phân thành các trang nhớ 4K, mỗi trang này có thể hoặc nằm trên bộ nhớ vật lý hoặc nằm trong tập tin hoán chuyển trên đĩa. Khi một tham khảo được thiết lập đến một vị trí thường trú trên đĩa, một lỗi trang sẽ được bật, là một ngắt nội tới CPU. Ngay lúc này, trình quản lý bộ nhớ ảo sẽ đọc trang nhớ mong muốn từ đĩa vào để truy xuất được dữ liệu. Chỉ thị bật lỗi trang sẽ được khởi động lại và cơ chế phân trang hoàn toàn trong suốt với phần mềm.

Sử dụng bộ nhớ:

Sử dụng các khối bộ nhớ: trong Windows bộ nhớ được quản lý theo khối, có thể di chuyển và huỷ bỏ (discardable) được. Mỗi khối nhớ di chuyển được sẽ không có địa chỉ cố định nên Windows có thể di chuyển nó đến vị trí mới và cũng có thể tận dụng tối đa phần bộ nhớ còn lại. Đối với khối nhớ hủy bỏ được Windows có thể hủy nó để cấp cho nhu cầu khác và ứng dụng có thể nạp trở lại dữ liệu khi cần thiết. Khi xin cấp một khối nhớ thì user sẽ nhận từ windows một handle bộ nhớ , dùng handle để lấy địa chỉ khối nhớ khi cần truy xuất, trong khi đang cập nhật khối nhớ thì handle phải được khóa lại để khối nhớ không di chuyển được, khi cập nhật xong thì mở khóa cho handle để Windows có thể di chuyển được.

Sử dụng bộ nhớ toàn cục (Global Memory): Bộ nhớ toàn cục gồm bộ nhớ của máy tính được sử dụng cho các ứng dụng và thư viện của Windows. Ứng dụng có thể xin cấp bộ nhớ lớn tuỳ ý phụ thuộc vào bộ nhớ toàn cục còn lại.

Sử dụng bộ nhớ cục bộ (Local Memory): nhằm đáp ứng nhu cầu cấp phát những đối tượng kích thước nhỏ, nhưng không được vượt quá 64 KB.

IV – Cơ chế hoạt động và quản lý bộ nhớ trong Windows 32bits:

Windows 32bits sử dụng mô hình bộ nhớ phẳng 4GB đã loại trừ được nhiều vấn đề nảy sinh trong hệ điều hành DOS bởi việc thay thế kiến trúc bộ nhớ phân trang thay cho kiến trúc bộ nhớ phân đoạn vốn chậm chạp.

Mỗi ứng dụng DOS chạy trong máy ảo VM (Virtual Machine) của nó. Điều này tạo cho mỗi quá trình DOS một mức bảo vệ khỏi các quá trình khác và gia tăng lượng vùng nhớ thấp khả dụng.

Việc sử dụng bộ nhớ được điều khiển bởi các quá trình VxD 32 bit làm gia tăng tốc độ xử lý. Cả hai trình VCACHE và VMM là các quá trình 32 bit làm giảm thiểu tổng phí và gia tăng tốc độ cho việc đánh địa chỉ và việc hoán đổi thông tin giữa bộ nhớ và đĩa.

Windows 32bits chỉ có thể hoạt động trên hệ thống 386 trở lên do yêu cầu phải có phần cứng hỗ trợ sơ đồ địa chỉ hóa 32 bit và cơ chế phân trang bộ nhớ.

Page 37: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

Kiến trúc bộ nhớ:

Kiến trúc bộ nhớ của Windows 32bits được định nghĩa là hệ thống bộ nhớ ảo đòi hỏi phân trang dựa trên nền mô hình bộ nhớ phẳng 4GB bằng cách sử dụng sơ đồ địa chỉ hóa 32 bit.

Hệ thống yêu cầu phân trang (demand-paged) điều khiển việc truy xuất vào bộ nhớ chính và việc thực thi quá trình , dựa trên các phần mềm yêu cầu cho hệ điều hành mà phần mềm đang xử lý đặt ra. Hệ điều hành cũng giám sát các tài nguyên hệ thống, xác định quá trình nào đang yêu cầu bộ nhớ và cung cấp một vài cơ chế để đáp ứng các yêu cầu đó.

Bộ nhớ ảo là không gian bao gồm cả bộ nhớ vật lý liên kết với hệ thống lưu trữ trên đĩa cứng nhằm làm cho việc thi hành của các quá trình có đủ vùng nhớ để thực thi các chỉ thị phầm mềm.

Mô hình bộ nhớ phẳng tuyến tính cho phép đánh địa chỉ bắt đầu tại một vài vị trí nào đó, 0 hay 0000h và tiếp tục cho đến giới hạn lớn nhất, 4G hay FFFF:FFFFh bằng cách dùng sơ đồ đánh địa chỉ tăng dần. Sơ đồ địa chỉ hóa này chỉ được hỗ trợ bởi phần cứng của hệ thống 386 hoặc cao hơn.

Mô hình lập trình 386:

Các thanh ghi và đường dẫn dữ liệu 32 bit của hệ thống 386 (và cao hơn) cho phép 4GB không gian địa chỉ vật lý. Không gian bộ nhớ ảo của chế độ bảo vệ 30386 gồm có 16383 tuyến tính cho mỗi bộ nhớ 4GB. Việc biểu hiện bộ nhớ tuyến tính 4GB được gọi là mô hình bộ nhớ phẳng (flat memory model). Mỗi thanh ghi đơn có thể được coi như một con trỏ chỉ vào không gian địa chỉ 4GB này. Các thanh ghi trong 80386 có giá trị 32 bit, gồm 5 nhóm chính:

Nhóm thanh ghi đa dụng (general purpose register): dùng di chuyển dữ liệu ra vài bộ vi xử lý, kiểm tra và lập các cờ trạng thái.

Nhóm các thanh ghi gỡ rối (debuging register): cho phép người lập trình thiết lập một vài địa chỉ ngắt (breakpoint address) trong quá trình để theo dõi, gỡ lỗi cho chương trình.

Nhóm các thanh ghi trạng thái và điều khiển (status and control register): cung cấp các cờ trạng thái chỉ ra kết quả của các phép toán và được dùng để thay đổi các bước thực thi của chương trình dựa vào kết quả kiểm tra cờ. Các thanh ghi cờ trạng thái được bộ quản lý bộ nhớ ảo VMM sử dụng rộng rãi để quản lý bộ nhớ.

EIP là thanh ghi lệnh mở rộng (extended instruction register): chỉ ra địa chỉ của lệnh tiếp theo sẽ được thi hành.

Page 38: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

Nhóm các thanh ghi điều khiển (control register): được hệ điều hành dùng điều khiển việc thực thi chương trình và được dùng bởi VMM để đánh địa chỉ cho bộ nhớ ảo, hỗ trợ đặc điểm tổ chức bộ nhớ theo trang của 386.

Các thanh ghi phân đoạn (segment register): duy trì sự tương thích với hệ thống 80286 và cung cấp địa chỉ phân đoạn khi 386 chạy trong chế độ thực hoặc chế độ chuẩn.

Địa chỉ hóa bộ nhớ ảo: Windows 32bits dùng sơ đồ địa chỉ phân trang làm cho bộ nhớ vật lý dường như rộng thêm hơn.

Thư mục trang (page directory): là một bảng chứa đựng địa chỉ của 1024 bảng trang (page table), mỗi địa chỉ rộng 32 bit nên kích thước của thư mục trang là 4096 bytes.

Bảng trang (page table): bao gồm là các điểm nhập, mỗi điểm nhập là sự kết hợp của địa chỉ vật lý và các cờ trạng thái của bộ nhớ vật lý. Sự kết hợp giữa thư mục trang và một bảng trang đơn độc sẽ đánh địa chỉ cho 4MB bộ nhớ. Vì vậy nếu RAM được thêm vào thì đòi hỏi cũng phải thêm bảng trang cho mỗi 4MB. Các địa chỉ bảng trang tuần tự được lưu giữ trong thư mục trang cho đến tối đa 1024 địa chỉ. Cách đánh địa chỉ trang như trên là lý do giải thích tại sao bộ nhớ tối thiểu cho Windows 32bits là 4MB. Mỗi quá trình trong Windows 32bits có một tập các địa chỉ bảng trang được gán cho nó. Mỗi địa chỉ này bao gồm phần 20 bit cao là một địa chỉ vật lý và phần 12 bit thấp là các cờ trạng thái. Các cờ này cung cấp thông tin cần thiết cho thành phần Kernel của Windows và chương trình người sử dụng.

Khung trang (page frame): mỗi khung trang được đánh địa chỉ duy nhất bởi một điểm nhập trong bảng trang. Phần 12 bit thấp của địa chỉ ảo 32 bit này đặc tả cho 1 byte duy nhất của bộ nhớ. Việc sử dụng 12 bit này sẽ đánh địa chỉ toàn bộ 4096 byte của khung trang và như vậy khung trang sẽ chỉ vào các địa chỉ RAM vật lý.

Như vậy một địa chỉ ảo 32 bit được chia làm 3 phần:

10 bit cao (22 - 31) chỉ ra bảng trang được chọn trong thư mục trang

10 bit tiếp theo (12 - 21) chỉ ra địa chỉ của khung trang thuộc bảng trang

12 bit thấp (0 - 11) đặc tả cho địa chỉ byte vật lý bên trong ranh giới 4K của trang

Không gian bộ nhớ ảo của trình ứng dụng:

Trong Windows 32bits, mỗi quá trình có một không gian địa chỉ 4GB riêng của nó. Các nhánh (thread) thuộc quá trình chỉ có thể truy xuất đến không gian nhớ thuộc về quá trình đó mà thôi. Không gian địa chỉ của tất cả các quá trình khác đều không thể truy xuất đối với nhánh đang chạy. Tuy nhiên riêng trong Windows

Page 39: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

32bits thì không hoàn toàn trọn vẹn như vậy, vùng nhớ thuộc về hệ điều hành không được che giấu đối với nhánh đang chạy do vậy rất có khả năng nhánh đang chạy vì một sự cố nào đó sẽ truy xuất vào vùng dữ liệu của hệ điều hành và làm hỏng hệ thống.

Không gian địa chỉ của mỗi quá trình được phân thành các vùng như sau:

Vùng địa chỉ từ 0x00000000 đến 0x003FFFFF:

Đây là vùng nhớ kích thước 4MB ở phần đáy của không gian địa chỉ, Windows 32bits dùng để đảm bảo tính tương thích với MS-DOS và Windows 16 bit. Các ứng dụng 32 bit không nên đọc ghi vào vùng này. Về mặt lý thuyết thì CPU sẽ tạo ra lỗi truy xuất (access violation) nếu một nhánh nào đó của quá trình chạm vào vùng nhớ này, tuy nhiên vì lý do kỹ thuậ thì thực tế Microsoft không thể bảo vệ toàn bộ vùng nhớ này mà chỉ có thể bảo vệ vùng 4KB thấp nhất. Vì thế nếu một nhánh nào đó của quá trình cố gắng đọc ghi vào vùng nhớ có địa chỉ từ 0x00000000 đến 0x00000FFF thì CPU sẽ phát hiện và báo lỗi truy xuất. Việc bảo vệ vùng 4KB này đặc biệt hữu ích cho việc phát hiện các phép gán con trỏ rỗng.

Vùng địa chỉ từ 0x00040000 đến 0x7FFFFFFF:

Phần không gian 2.143.289.344 (= 2GB – 4KB) là nơi thường trú của không gian địa chỉ riêng (không chia sẻ) của quá trình. Một quá trình Win32 không thể đọc/ghi hoặc bằng bất kỳ cách nào truy xuất truy xuất dữ liệu của quá trình khác đang thường trú trên vùng này. Đối với tất cả các ứng dụng Win32, vùng này là nơi mà phần chính yếu của dữ liệu quá trình đang cất giữ.

Vùng địa chỉ từ 0x80000000 đến 0xBFFFFFFF:

Vùng 1GB này là nơi hệ thống cất giữ dữ liệu dùng chia sẽ giữa tất cả các quá trình Win32 chẳng hạn như các thư viện liên kết động hệ thống, kernel32.dll, user32.dll, gdi32.dll, advapi32.dll đều được nạp vào vùng không gian địa chỉ này. Chính điều này làm cho 4 thư viện hệ thống trở nên dễ dàng khả dụng đối với toàn bộ các quá trình Win32 một cách đồng thời. Hệ thống cũng ánh xạ toàn bộ các tập tin ánh xạ bộ nhớ (memory-mapped file) vào vùng này.

Vùng địa chỉ từ 0xC0000000 đến 0xFFFFFFFF:

Vùng 1GB này là nơi mã lệnh của hệ điều hành được định vị, bao gồm các trình điều khiển thiết bị ảo của hệ thống (VxD), mã lệnh quản lý bộ nhớ ở mức thấp, mã lệnh tập tin hệ thống. Cũng giống như vùng nhớ trước, toàn bộ mã lệnh trong vùng này được chia sẽ cho tất cả quá trình Win32. Tuy nhiên dữ liệu trong vùng này lại không được bảo vệ, bất kỳ một ứng dụng Win32 nào cũng có thể đọc/ghi vào vùng này và làm hỏng hệ thống.

Page 40: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

Như vậy thì ý tưởng cơ bản cho việc thực hiện kỹ thuật override trong Windows 32 là cũng nhảy tới địa chỉ của hàm override tương ứng mỗi khi hàm API nào đó được gọi. Tuy nhiên, đối với Windows 32bits thì mỗi quá trình trong hệ thống đều được thực thi trong một không gian địa chỉ riêng rẽ. Nên muốn can thiệp vào quá trình gọi hàm của ứng dụng thì chúng ta phải bằng mọi cách thâm nhập vào không gian địa chỉ của ứng dụng, thì lúc đó chúng ta mới có thể điều khiển được quá trình gọi hàm API. Nhưng ở Windows 16 bit thì các hàm dùng để thay đổi thuộc tính các trang nhớ chứa mã hàm API thì nay ở trong Windows 32 bit không còn được hỗ trợ nữa. Như vậy làm theo cách như ở Windows 16 bit là không khả thi, vấn đề đặt ra là phải tìm cách thay đổi thuộc tính các trang nhớ đang chứa mã hàm API nguyên thủy.

Chúng tôi đã cố gắng nghiên cứu công việc này bằng các phương pháp được giới thiệu trong chương 16: Breaking Through Process Boundary Walls của cuốn Advance Windows – The Developer’s Guide to the Win32 API for Windows NT 3.5 and Windows 95 và tìm cách thực hiện nhưng chưa đạt được kết quả khả quan.

Do hạn chế về thời gian cũng như tài liệu tham khảo về các kỹ thuật này rất ít nên việc nghiên cứu để tìm ra cách giải quyết vấn đề sử dụng kỹ thuật override trong Windows 32bits chưa đi đến kết quả nên chúng tôi buộc phải chọn kỹ thuật override trong Windows 16bits để overrride các hàm xuất văn bản có sẵn để áp dụng vào chương trình của mình.

V – Hiện thực kỹ thuật override trên Windows 16bits:

Phương pháp mà chúng tôi chọn để áp dụng vào chương trình là ở dạng front-end processing tức là 5 bytes lệnh đầu tiên của đoạn mã lệnh hàm API sẽ được ghi đè bằng 5 bytes của lệnh JMP address trong đó byte thứ nhất là mã hợp ngữ của lệnh CALL, 4 byte kế tiếp là offset và segment tương ứng của đoạn mã lệnh hàm override.

Trình tự hiện thực bao gồm các bước sau:

1 - Xác định địa chỉ bộ nhớ nơi đoạn mã lệnh override thường trú:

Thường chúng được tập hợp dưới dạng các tập tin .DLL, .EXE của developer. Có 2 hàm để lấy địa chỉ logic trong bộ nhớ của bất kỳ hàm API nào: GetProcAddress và MakeProcInstance.

2 - Xác định địa chỉ bộ nhớ nơi bắt đầu đoạn mã tương ứng của hàm API cần override:

Đây cũng chính là điểm nhập của các hàm trong thư viện liên kết động đã được nạp vào bộ nhớ. Các thư viện này là thành phần cơ bản của Windows và được

Page 41: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

nạp vào bộ nhớ khi Windows khởi động. Tại địa chỉ bộ nhớ của hàm API có được ta có thể tạo một lệnh nhảy từ đây đến địa chỉ đoạn mã lệnh override. Nhưng Windows chỉ cho phép ghi lên data segment chứ không cho phép ghi lên code segment. Vì vậy ta phải có bước trung gian:

3 - Thay đổi thuộc tính của segment chứa mã hàm API trong Windows:

Bằng cách dùng hàm PrestoChangoSelector để có thể thay đổi thuộc tính segment theo 2 chiều: từ code sang data hoặc từ data sang code.

4 - Ghi mã lệnh nhảy vào địa chỉ bắt đầu đoạn mã hàm API:

Dùng lệnh nhảy không điều kiện JMP thì lúc đó stack của ứng dụng sẽ không đổi, đỉnh stack vẫn là địa chỉ trở về ứng dụng sau lệnh gọi hàm API, do vậy khi gặp lệnh return trong thân hàm override thì địa chỉ trở về là địa chỉ lệnh kế tiếp sau lệnh gọi hàm API trong ứng dụng. Như vậy để làm điều này thì chúng ta ghi đè 5 bytes đầu tiên tại địa chỉ bắt hàm API với dội dung là mã hợp ngữ của lệnh JMP address trong đó byte đầu tiên là mã lệnh JMP, có giá trị là 0EAh, 4 byte kế tiếp là địa chỉ logic dạng kiến trúc đoạn offset (2 byte)-segment (2 byte) nơi bắt đầu đoạn mã lệnh override của developer.

5 - Phục hồi 5 bytes nguyên thủy mã lệnh đầu tiên của hàm API:

- Để gỡ bỏ override, trả lại hàm API như cũ.

- Giải thuật thực hiện nói chung giống hệt như việc cài đặt override, chỉ khác là thay vì ghi mã lệnh nhảy và địa chỉ thì bây giờ ghi 5 bytes nguyên thủy của hàm API.

- Năm bytes nguyên thủy của hàm API là hằng số, nên có thể dùng một trong hai cách sau:

* Ghi thẳng các mã lệnh này vào trong chương trình. Cách này đơn giản dễ làm nên việc hiện thực chương trình nhanh, và không phụ thuộc vào nhân tố bên ngoài (phần bộ nhớ lưu trữ 5 bytes nguyên thủy) nên tránh được việc chương trình chạy sai lệch nếu vô ý thay đổi 5 bytes này, nhưng không tổng quát.

* Khi cài đặt override thì đọc 5 bytes nguyên thủy, lưu vào trong DLL, đến khi gỡ bỏ thì lấy 5 bytes đó ghi trở lại. Cách này tổng quát hơn, nhưng chương trình sẽ phức tạp hơn và phải làm nhiều việc hơn một cách không cần thiết.

6 - Thiết kế hàm override API:

Điều trước nhất cần nhớ khi thiết kế hàm override API là việc đặt các parameters của nó: phải giống hệt như hàm API nguyên thủy, và từ các parameters này ta sẽ chứa các thông tin cần thiết. Đồng thời thông tin trả về cũng phải cùng kiểu dữ liệu với hàm API nguyên thủy.

Page 42: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

Việc xử lý bên trong hàm override thì tùy ý đồ của ứng dụng, nói chung là có thể làm bất cứ việc gì. Chỉ có một việc đặc biệt và cần thiết là gọi lại hàm nguyên thủy, nói chung việc này cũng đơn giản, bao gồm 3 bước như sau:

- Gỡ bỏ override: Hàm API trở lại bình thường

- Gọi lại hàm API

- Cài đặt override lại như cũ.

7 – Cách lấy nội dung 5 bytes đầu tiên của một hàm API:

Chúng tôi chọn phương pháp thứ nhất để phục hồi nội dung 5 bytes đầu của hàm API khi gỡ bỏ override. Muốn vậy phải xác định trước giá trị 5 bytes này.

Các bước hiện thực để lấy nội dung 5 bytes đầu tiên của một hàm API như sau:

- Lấy địa chỉ của hàm API thường trú trong bộ nhớ

- Lấy địa chỉ offset và segment của hàm

- Sau đó dùng đoạn chương trình viết bằng hợp ngữ để chuyển nội dung từng byte một vào trong 1 biến có cấu trúc chỉ gồm 1 trường là một mảng 5 byte.

- Từ đó cho hiển thị để biết nội dung.

Như vậy ta có thể đọc nội dung của bất kỳ hàm API nào.

Sau đây là chương trình thực hiện:

// kieu du lieustruct First5 { BYTE memb[5]; };typedef struct First5 ARRAY5BYTE;

// doan chuong trinhARRAY5BYTE FAR PASCAL Get5ByteOrgFunction(

LPCSTR APIFunctionName){HINSTANCE hinstDll;FARPROC fpFunction; UINT fpFunctionOff, fpFunctionSeg;BYTE Byte5temp[5];ARRAY5BYTE Array5temp;

hinstDll= LoadLibrary("USER.EXE");if (hinstDll < HINSTANCE_ERROR)

Page 43: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

{MessageBox(NULL,"Can not load library",NULL,MB_ICONEXCLAMATION);

return(NULL);}fpFunction= GetProcAddress(hinstDll,APIFunctionName);fpFunctionSeg=SELECTOROF(fpFunction);fpFunctionOff=OFFSETOF(fpFunction);FreeLibrary(hinstDll);

// lay noi dung cua 5 bytes dau cho vao cau truc Byte5temp// bang ngon ngu Assembly_asm{

push dsmov ds,fpFunctionSegmov bx,fpFunctionOffinc fpFunctionOffinc fpFunctionOffmov ax,[bx]mov Byte5temp[0],almov Byte5temp[1],ahmov bx,fpFunctionOffinc fpFunctionOffinc fpFunctionOffmov ax,[bx]mov Byte5temp[2],almov Byte5temp[3],ahmov bx,fpFunctionOffmov ax,[bx]mov Byte5temp[4],alpop ds

}

Array5temp.memb[0]=Byte5temp[0];Array5temp.memb[1]=Byte5temp[1];Array5temp.memb[2]=Byte5temp[2];Array5temp.memb[3]=Byte5temp[3];Array5temp.memb[4]=Byte5temp[4];return(Array5temp);

Page 44: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

}

Nội dung 5 bytes đầu tiên của 5 hàm xuất văn bản của Windows 3.x:

Hàm Nội dungTextOutExtTextOutTabbedTextOutDrawTextGrayString

55 8B EC 68 DD h B8 8F 05 45 55 h 55 8B EC 68 66 h C8 10 00 00 1E h 66 58 6A 19 66 h

VI – Một số hàm được sử dụng trong kỹ thuật override:

1 – Hàm LoadLibrary:

- Cú pháp:

HINSTANCE LoadLibrary(lpszLibFileName)LPCSTR lpszLibFileName;

- Hàm LoadLibrary nạp library module.

- Thông số lpszLibFileName: Trỏ tới một chuỗi kết thúc bằng ký tự null là tên của file thư viện được nạp. Nếu chuỗi không chứa đường dẫn thì Windows sẽ tìm kiếm thư viện theo trình tự sau:

- Thư mục hiện hành

- Thư mục Windows (chứa trong WIN.COM), hàm GetWindowsDirectory lấy đường dẫn của thư mục này.

- Thư mục hệ thống Windows (chứa trong file hệ thống như GDI.EXE), hàm GetSystemDirectory lấy đường dẫn của thư mục này.

- Thư mục chứa file thực thi cho task hiện hành, hàm GetModuleFileName lấy đường dẫn của thư mục này.

- Thư mục đã liệt kê trong biến môi trường PATH.

- Danh sách thư mục đã ánh xạ trong mạng.

Giá trị trả về: là handle của module thư viện được nạp nếu hàm thành công, ngược lại là lỗi nếu giá trị nhỏ hơn HINSTANCE_ERROR.

Page 45: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

2 – Hàm FreeLibrary:

- Cú pháp:

void FreeLibrary(hinst)HINSTANCE hinst;

- Hàm FreeLibrary giảm số lần tham chiếu của module library được nạp. Khi số lần tham chiếu là 0 thì bộ nhớ sẽ chiếm lại.

- Thông số:

hinst Library module được nạp.

- Giá trị trả về: hàm không trả về giá trị gì.

3 – Hàm GetProcAddress:

- Cú pháp:

FARPROC GetProcAddress(hinst, lpszProcName)HINSTANCE hinst;LPCSTR lpszProcName;

- Hàm GetProcAddress lấy địa chỉ của hàm module

- Thông số:

hinst module chứa hàm

lpszProcName Con trỏ tới địa chỉ chuỗi null-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;

Page 46: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

- 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.

Page 47: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

- 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.

Page 48: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

Chương 4:

KẾT XUẤT VĂN BẢNKẾT XUẤT VĂN BẢN TRONG WINDOWSTRONG WINDOWS

Page 49: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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.

Page 50: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

- 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,LPCTSTRlpszString,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.

Page 51: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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.

Page 52: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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

Page 53: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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 tmDescentChiề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

Page 54: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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 fontint tmMaxCharWidth Độ rộng của ký tự rộng nhất trong fontint 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 OLD800 FW_ULTRABOLD 800 FW_BLACK 900 FW_HEAVY 900

BYTE tmItalic Khác 0 nếu chữ nghiêngBYTE tmUnderlined Khác 0 nếu chữ có gạch dướiBYTE tmStruckOut Khác 0 nếu chữ bị gạch giữa thânBYTE tmFirstChar Ký tự đầu tiên của fontBYTE tmLastChar Ký tự cuối cùng của fontBYTE 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_PITCHTMPF_VECTORTMPF_TRUETYPETMPF_DEVICEFF_DECORATIVEFF_DONTCAREFF_MODERNFF_ROMANFF_SCRIPTFF_SWISS

Page 55: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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ệtint 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 DClpszString Trỏ tới chuỗi văn bảncbString 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ừ

Page 56: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows 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-rectangleTA_RIGHT x-coordinate đặt tại cạnh phải bounded-rectangleTA_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.

Page 57: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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ị.

Page 58: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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)constRECT FAR* lprc;POINT pt;

- Thông số:

lprc trỏ tới địa chỉ hình chữ nhậtpt 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.

Page 59: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

Chương 5:

PHÂN TÍCH VÀ THIẾTPHÂN TÍCH VÀ THIẾT KẾ CHƯƠNG TRÌNHKẾ CHƯƠNG TRÌNH

Page 60: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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

Page 61: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows 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

Page 62: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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

+ 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:

Page 63: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự
Page 64: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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

Page 65: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự
Page 66: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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

Page 67: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

Bắt đầu

Chuyển toạ độ xuất text trong TextOut; ExtTextOuttừ 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ẠITỌ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

Page 68: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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 TEXTTẠ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àngtrích từ ra bằng hàm trích chuỗi con: strncpy

Page 69: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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

Page 70: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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 đặtHOOKPROC lpfn, // địa chỉ của thủ tục hookHINSTANCE hMod, // handle chỉ tới thể hiện của ứng dụngDWORD 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:

Page 71: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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

Page 72: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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ư

Page 73: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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.

Page 74: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

- 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:

Error: Reference source notfoundGiá 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

Page 75: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows 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

Page 76: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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

Page 77: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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.

Page 78: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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

Page 79: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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.

Page 80: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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ổ.

Page 81: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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

Page 82: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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;

Page 83: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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:

Page 84: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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:

Page 85: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

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 .

Page 86: Lôøi Caûm Taï,i.vietnamdoc.net/data/file/2015/Thang06/17/nghien-cuu... · Web view5 - Vấn đề tô vẽ màn hình: Khi một cửa sổ bị di chuyển thì Windows tự

Kết quả và hướng phát triểnKế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.