Tải bản đầy đủ (.pdf) (9 trang)

Tìm hiểu về MessageBox

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (255.03 KB, 9 trang )

Iczelion’s Tutorial Win32 ASM Tutorial 2 : MessageBox
Tìm hiểu về MessageBox

Trong bài viết này, chúng ta sẽ tạo ra một MessageBox với nội dung
“Win32 assembly is great”

Tổng quan về lập trình trên Windows

Hệ điều hà
nh (HĐH) cung cấp cho các lập trình viên nguồn tài nguyên phong phú
để họ lập trình các ứng dụng chạy trên nền tảng Wins. Đáng kể nhất là phải nói đến là
Windows API (Application Programming Interface). Nó được xem như là tập hợp hầu hết
các hàm đặc trưng thường dùng, và được các ứng dụng Win32 sử dụng. Những hàm này
được chứa trong các thư viện liên kết động (DLLs) như: kernel32.dll, user32.dll và
gdi32.dll.
Kernel32.dll chứa các hàm và thủ tục mà một hệ điều hành truyền thống quản lý
như: quản l
ý bộ nhớ, xuất nhập tập tin và quản lý tiến trình (là quá trình thực hiện một
chương trình từ khi khởi động đến khi kế thúc).
User32.
dll quản lý giao diện người dùng (the user interface aspects) , cài đặt tất
cả khung cửa sổ ở mức luận lý chương trình của bạn.
Gdi32.dll cung cấp toàn bộ giao diện thiết bị đồ họa (Graphics Device Interface)
cho phép chương trình ứng dụng hiển thị văn bản và đồ họa trên các thiết bị xuất phần
cứng như m
àn hình và máy in.
Ngoài 3 thư viện chính trên, HĐH còn cung cấp những thư viện khác mà chương
trình của bạn có thể dùng, miễn là bạn có đầy đủ các thông tin về các “yêu cầu” cho hàm
API.
Trong một chương trình Windows, có sự khác biệt khi ta gọi một hàm của thư viện
ngôn ngữ (chẳng hạn


C, ASM, …) và một hàm của HĐH Windows (các hàm API) hay

thư viện liên kết động cung cấp. Đó là khi biên dịch thành mã máy (machine code), các
hàm thư viện ngôn ngữ sẽ được liên kết thành mã chương trình (source code). Trong khi
các hàm Windows sẽ được gọi khi chương trình cần dùng đến chứ không liên kết vào
chương trình. Để thực hiện được các lời gọi này thì một chương trình trình Windows
*.EXE luôn chứa một tham chiếu đến thư viện liên kết động khác mà nó cần dùng. Khi
đó, một chương trình Windows được nạp và
o bộ nhớ sẽ tạo thành con trỏ tham chiếu đến
những hàm thư viện DLLs mà chương trình dùng, nếu thư viện này chưa được nạp vào bộ
nhớ trứơc đó thì bây giờ sẽ nạp
Chương trình liên kết động với các DLLs này, nghĩa
là code của hàm API sẽ
không được include vào trong file .EXE của chương trình. Để chương trình của bạn biết
tìm các hàm API mà nó đang cần “ở đâu” trong lúc chương trình đang thực thi, thì bạn
phải gắn thông tin nhận biết nó vào trong file .EXE. Thông tin này nằm trong “thư viện
nhập” (import libraries) đặc biệt được cung cấp bởi môi trường lập trình. Bạn phải liên
kết chương trình với thư viện được import một cách chính xác, nếu không, thì nó sẽ
không t
hể tìm được các hàm API mà chương trình cần sử dụng.
Khi một chương trình được nạp vào bộ nhớ, HĐH sẽ đọc các thông tin của
chương trình. Các thông tin này chính là tên của các hàm (function) đư
ợc sử dụng trong
chương trình và các thư viện DLLs mà các hàm sử dụng chứa trong nó. Khi HĐH tìm
thấy các thông tin như thế trong chương trình, nó sẽ load các DLLs và thực hiện việcliên
kết địa chỉ của các hàm trong DLLs vào trong chương trình của bạn, vì vậy các lời gọi
Người dịch: Benina (REA TEAM) Trang 1
Tổng hợp và hiệu chỉnh: NhatPhuongLe (VNCERT TEAM)
Iczelion’s Tutorial Win32 ASM Tutorial 2 : MessageBox
hàm được xem như sẽ chuyển quyền điều khiển đến đúng hàm API mà chương trình sử

dụng khi thực thi.
Có hai loại hàm API: một cho hệ thống ký tự ASCII (là các hàm dành cho các
HĐH từ Wins 98 trở về trước, không hỗ trợ Unicode) và một cho UNICODE (đây là do
thuật ngữ dân lập trình gọi tắt, nhưng bạn phải hiểu là nó vẫn là chuẩn ANSI; nó chỉ khác
ở chỗ là có bổ sung các hàm hỗ trợ Unicode và chuẩn này có được hỗ trợ từ HĐH Wins
2000/WinNT trở về sau nà
y). Tên của hàm cho ký tự ASCII được gắn hậu tố “A” như
MessageBoxA. Còn tên hàm cho UNICODE có hậu tố là “W” (viết tắt của wide
character ký tự mở rộng).
Chúng ta thường quen dùng những chuỗi (string) ANSI, chúng là một mảng các ký
tự kết thúc bằng ký tự NULL (\0). Các ký tự ASCII có kích thước 1 byte. Chúng ta thấy
rằng, với độ dài 8-bit của mã ANSI chỉ đủ biểu diễn đủ cho ngôn ngữ các nước thuộc
C
hâu Âu, còn với các ngôn ngữ khác thì không, với hàng triệu các ký tự riêng biệt. Đó
chính là khái niệm sơ khởi của Unicode. UNICODE là một hệ thống 16-bit đồng nhất,
cho phép có kích thước 2 byte, cho phép biểu diễn đến 65536 ký tự. Điều này đủ cho tất
cả các ký tự và chữ tượng hình trong tất cả các ngôn ngữ viết của thế giới, bao gồm nhiều
ký hiệu toán học, biểu tượng, … Sau này, UNICODE được phát triển thành hệ thống
32-
bit.
Đa phần bạn sẽ dùng một file include (file có phần mở rộng .INC) m
à nó có thể
xác định và chọn lựa các hàm API thích hợp cho platform của bạn. Nó chỉ tham chiếu đến
các tên hàm mà không có các hậu tố nói trên.

Cấu trúc của một chương trình ASM 32-bit

Tôi
sẽ trình bày cấu trúc thường thấy của một chương trình ASM. Sau đó, chúng ta
sẽ tìm hiểu từng từ khóa (keyword) một cách chi tiết hơn :




Chương trình sẽ thực thi bắt đầu từ chỉ thị sau nhãn <label> được chỉ định (nhãn
start) cho đến chỉ thị end <label> (end start). Trong cấu trúc trên, quá trình thực thi sẽ
bắt đầu từ chỉ thị đầu tiên đứng sau nhãn start. Quá trình thực thi sẽ thực thi từ chỉ thị này
đến chỉ thị kế cho đến khi gặp chỉ thị điều khiển như jmp, je, ret … Các chỉ thị điều
khiển nà
y sẽ làm rẽ nhánh luồng chỉ thị này sang luồng chỉ thị khác. Khi chương trình cần
thoát để về lại Window, nó sẽ gọi API ExitProcess.


Người dịch: Benina (REA TEAM) Trang 2
Tổng hợp và hiệu chỉnh: NhatPhuongLe (VNCERT TEAM)
Iczelion’s Tutorial Win32 ASM Tutorial 2 : MessageBox
Dòng lệnh trên đây được gọi là một prototype (khai báo tên hàm) của hàm. Khi khai báo
một prototype, thì định nghĩa các thuộc tính của hàm cho trình hợp dịch và trình liên kết
biết để nó có thể thực hiện việc kiểm tra cú pháp giúp bạn. Cú pháp khai báo một
prototype của hàm như sau:

Tên_hàm PROTO Tên_tham_số_1 : <Kiểu dữ liệu> , Tên_tham_số_2 : <Kiểu dữ liệu>


Tóm
lại, tên hàm đứng trước từ khóa PROTO và sau đó là danh sách các kiểu dữ liệu của
các tham số, cách nhau bởi dấu phẩy. Trong hàm ExitProcess như ví dụ trên, nó định
nghĩa hàm ExitProcess như một hàm chỉ có duy nhất một tham số có kiểu là DWORD.
Các prototype của hàm rất hay dùng khi bạn sử dụng cú pháp gọi hàm cấp cao là Invoke
(thực thi hàm). Bạn có thể nghĩ rằng Invoke như là một lời gọi hàm đơn giản, nó được
gọi để kiểm tra lỗi cú phá

p. Ví dụ, bạn muốn gọi gọi hàm ExitProcess để thoát, bạn sẽ
viết như sau : Call ExitProcess hoặc Invoke ExitProcess

Khi không đẩy một tham số kiểu DW
ORD vào trong ngăn xếp, thì trình hợp dịch và trình
liên kết sẽ không thể bắt lỗi cho bạn. Bạn chỉ nhận biết lỗi này khi chương trình của bạn
bị treo. Nhưng nếu bạn dùng INVOKE ExitProcess thì trình liên kết sẽ thông báo cho
bạn biết rằng “Bạn ơi, bạn quên đẩy một tham số có kiểu là DWORD vào trong stack
rồi kìa!”, như thế sẽ ngăn đư
ợc lỗi này. Tôi khuyên bạn nên dùng Invoke thay cho một
lời gọi hàm đơn giản. Cú pháp của INVOKE như sau:
Invoke Biểu thức [,Các đối số]
Biểu thức có thể là tên của một hàm, hay nó có thể là một con trỏ hàm. Các tham
số hàm ngăn cách bởi dấu phẩy. Hầu hết các prototype của hàm API được khai báo trong
trong file include (file có phần mở rộng là .INC). Nếu bạn dùng hutch’s MASM32, chúng
sẽ nằm trong thư mục MASM32/include.

Các file include có phần mở rộng l
à .INC và các prototype cho các hàm trong
một DLL được chứa trong file .INC với cái tên giống như tên file DLL.
Ví dụ, hàm ExitProcess được export bởi kernel32.lib vì vậy các protot
ype cho hàm
ExitProcess được chứa trong kernel32.inc.

Bạn cũng có thể cài đặt prototype của hàm cho chính các hàm do chính bạn lập
trình. Trong các ví dụ của tôi, tôi sẽ dùng hutch’s window.inc mà bạn có thể download tại

. Bây giờ trở lại với hàm ExitProcess, tham số uExitCode là giá
trị mà bạn muốn chương trình trả về cho Windows sau khi chương trình kết thúc. Bạn có
thể gọi ExitProcess như sau: Invoke ExitProcess, 0


Nếu bạn đặt dòng lệnh này (Invoke ExitProcess, 0 ) ngay dưới nhãn start, bạn sẽ
có một chương trình Win32 ASM chỉ có chức năng thoát về Windows, nhưng dù sao nó
cũng là một chương trình hoàn toàn hợp lệ và không bị crash.



Người dịch: Benina (REA TEAM) Trang 3
Tổng hợp và hiệu chỉnh: NhatPhuongLe (VNCERT TEAM)
Iczelion’s Tutorial Win32 ASM Tutorial 2 : MessageBox
Source code của một chương trình ASM. Chương trình này đơn giản là sau khi được load
lên bộ, ngay lập tức sẽ được thoát ra, trả quyền kiểm soát về cho HĐH :

Giải thích:
opti
on casemap:none: nói cho MASM biết rằng tên các nhãn trong chương trình phân
biệt chữ hoa, chữ thường, vì vậy ExitProcess sẽ khác với exitprocess.

include: chỉ thị này được theo sau là tên file (nói chính xác là tên của thư viện nhập) mà
bạn muốn liên kết vào, để khi chương trình được thực thi, thì nó sẽ tìm các hàm API nào
được sử dụng trong các “thư viện nhập”.

Chú ý
: Tên file được chứa trong đường dẫn tương đối hoặc tuyệt đối, nghĩa là nếu
bạn đang muốn liên kết với các file thư viện của trình biên dịch (cụ thể thông qua tên của
thư viện nhập) cho chương trình bạn sử dụng khi thực thi, và bạn đã chỉ rõ trong lúc cấu
hình rằng môi trường lập trình (IDE) sử dụng trình biên dịch này để làm trình biên dịch
chính của IDE (nếu như trên máy của bạn có nhiều trình biên dịch) thì chỉ cần ghi đư
ờng
dẫn tương đối mà thôi.


 Để khai báo chỉ thị include theo đường dẫn tương đối đối
include
windows.inc


Ngược lại, phải ghi đường dẫn tuyệt đối để cho IDE giao nhiệm vụ tìm thư viện mà
chương trình cần cho trình biên dịch, vì thế phải ghi rõ chính xác rằng trình biên dịch cần
phải tìm nó (thư viện nhập) nằm ở đâu, trong thư mục nào, nếu như thư viện nhập đó
được sử dụng cho nhiều template khác nhau (template ở đây hiểu theo nghĩa là có nhiều
dạng ứng dụng trong ứng dụng c
hạy trên nền Wins, thí dụ đối với ngôn ngữ C for Wins,
cũng cùng là ứng dụng chạy trên nền Windows, nhưng ứng dụng được code theo template
Win32 Application thì khác với ứng dụng được code theo template MFC Application).

 Để khai báo chỉ thị include theo đường dẫn tuyệt đối

include \masm32\include\windows.inc

Người dịch: Benina (REA TEAM) Trang 4
Tổng hợp và hiệu chỉnh: NhatPhuongLe (VNCERT TEAM)
Iczelion’s Tutorial Win32 ASM Tutorial 2 : MessageBox
Trong ví dụ trên, khi MASM thực thi dòng include
\masm32\include\windows.inc
, nó
sẽ tìm file windows.inc trong thư mục \masm32\include\ và thực thi nội dụng của file
windows.inc cũng như bạn copy nội dung của window.inc vào thay thế cho câu lệnh.
Thư viện windows.inc chứa hầu hết (không phải là bao hàm tất cả) các định nghĩa của
hằng số và cấu trúc mà bạn cần trong chương trình Win32 ASM. Nó không chứa bất kỳ
prototype hàm nào. Có rất nhiều hằng số và cấu trúc, mà trong windows.inc chưa được

định nghĩa. Nó sẽ đư
ợc cập nhật một cách thường xuyên.

Từ window.inc, chương trình có được các hằng số và các định nghĩa cấu trúc. Đối với
các prototypes của hàm, bạn cần phải include các file include khác. Chúng được đặt trong
thư mục \masm32\include. Trong ví dụ trên, chúng ta gọi một hàm được export bởi
kernel32.dll, vì vậy chúng ta cần phải include prototypes hàm từ kernel32.dll. File đó là
kernel32.inc. Nếu bạn open nó bằng một chương trình sọan thảo editor bạn sẽ thấy rằng
nó chứa đầy các prototyes của hàm trong k
ernel32.dll. Nếu bạn không include
kernel32.inc, bạn vẫn có thể gọi hàm ExitProcess nhưng chỉ với lời gọi hàm là Call
ExitProcess. Bạn không thể invoke hàm được.

Điểm cần chú ý ở đây là để invoke một hàm, bạn phải đặt prototyes của chính hàm ở
đâu đó trong mã nguồn chương trình.

Nếu bạn không include ker
nel32.inc, bạn có thể định nghĩa prototype của hàm ở
bất kỳ đâ
u trong mã nguồn trên, lệnh invoke và nó sẽ làm việc. File include rất tiện dụng,
sẽ giúp bạn sử dụng các prototypes của hàm do bạn tạo ra bất cứ khi nào khi bạn có nhu
cầu tái sử dụng.

Bây
giờ chúng ta sẽ tìm hiểu với một chỉ thị mới, đó là includelib. includelib
không làm việc giống như include. Nó báo cho trình hợp dịch biết thư viện nhập nào mà
chương trình của bạn cần sử dụng. Khi trình hợp dịch
thấy chỉ thị includelib, nó sẽ đặt
một lệnh linker vào trong file object, để trình liên kết sẽ biết được thư viện nhập nào mà
chương trình bạn cần để liên kết. Tuy vậy, không bắt buộc phải sử dụng chỉ thị includelib.

Bạn có thể chỉ tên của thư viện import trong dòng lệnh của linker nhưng hãy tin tôi đi, nó
rất mệt mõi, đồng thời dòng lệnh chỉ có thể tối đa là 128 ký tự m
à thôi. Bạn nên sử dụng
chỉ thị includelib thì tốt hơn.
Người dịch: Benina (REA TEAM) Trang 5
Tổng hợp và hiệu chỉnh: NhatPhuongLe (VNCERT TEAM)

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×