Iczelion’s Tutorial Win32 ASM Tutorial 3 : A Simple Window
Tìm hiểu về cửa sổ ứng dụng
Trong bài viết này, chúng ta sẽ xây dựng một chương trình với đầy đủ chức năng
của một cửa sổ ứng dụng trên desktop.
Tìm hiểu về cửa sổ, lớp cửa sổ
Trong một ứng dụng đồ họa 32-bit, cửa sổ (window) là một vùng hình chữ nhật
trên màn hình, nơi mà ứng dụng có thể hiện thị thông tin và nhận thông tin vào từ người
dùng (users). Do vậy, nhiệm vụ đầu tiên của một ứng dụng đồ họa 32-bit là tạo một cửa
sổ.
Một cửa sổ sẽ chia sẻ màn hình với các cửa sổ khác trong cùng một ứng dụng hay
với các ứng dụng khá
c. Chỉ một cửa sổ trong một thời điểm nhận được thông tin nhập từ
người dùng thông qua bàn phím, thiết bị chuột hay các thiết bị nhập liệu khác để tương
tác với cửa sổ và ứng dụng.
Tất cả các cửa sổ đều đựơc tạo từ một cấu trúc được cung cấp sẵn gọi là lớp cửa sổ
(window class). Cấu trúc này là một tập hợp các mô tả các thuộc tính m
à hệ thống dùng
như khuôn mẫu để tạo nên các cửa sổ. Mỗi một cửa sổ phải là thành viên của một lớp cửa
sổ. Tất cả các lớp cửa sổ này đều được xử lý riêng biệt.
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 3 : A Simple Window
Các chương trình trên Windows thường sử dụng các API để thiết kế giao diện
(GUI) cho chúng. Bằng cách này, nó có lợi cho cả người sử dụng và cả lập trình viên. Đối
với người sử dụng, họ không cần phải tìm hiểu làm thế nào để sử dụng giao diện đồ họa
5. Hiển thị cửa sổ trên desktop (trừ khi bạn không muốn hiển thị cửa sổ nga
y)
6. Luôn luôn vẽ (paint) và vẽ lại (repaint) vùng client của cửa sổ
Hiểu như thế nào là vẽ và vẽ lại? Có nghĩa là người dùng có thể di chuyển cửaa sổ của một hay nhiều
chương trình khác trên màn hình và sự di chuyển sẽ che một phần cửa sổ của ứng dụng. HĐH sẽ
không lưu phần cửa sổ mà bị chương trình khác che. Khi cửa sổ bị/được di chuyển, HĐH sẽ gửi yêu
cầu vẽ lại vùng client của cửa sổ.
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 3 : A Simple Window
7. Nhận và xử lý thông điệp thông qua vòng lặp thông điệp.
Chúng ta xét qua lược đồ quản lý sự kiện và thông điệp của HĐH :
Trình tự xử lý thông điệp được mô tả như sau:
Nhận một thông điệp thông qua hàm API GetMessage() từ hàng đợi thông điệp của ứng dụng.
Ngoại trừ thông điệp WM_QUIT, mỗi thông điệp sẽ trả về cho hàm GetMessage() một thông số
khác 0 (TRUE). Khi nhận thông điệp WM_QUIT thì chương trình sẽ thoát khỏi vòng lặp và
chấm dứt hoạt động chương trình. Hàm GetMessage() này nhận vào 4 tham số đầu vào tro
nhau. Trong trường hợp của chúng ta, chỉ có hai case là xử lý thông điệp WM_PAINT và thông điệp
WM_DESTROY. Trong thực tế các ứng dụng thường chứa một switch khổng
lồ với số lượng trường hợp
nhiều kinh khủng.
Giá trị trả về của WndProc() tùy thuộc vào loại thông điệp. Mỗi WndProc() đều cần 4 tham số đầu vào :
hwnd : handle của thông điệp msg và 2 thông số khác là wparam và lparam. Tham số hwnd này
rất quan trọng vì một WndProc() có thể hỗ trợ nhiều cửa sổ khác nhau trên màn hình cùng một
lúc. Do đó, tham số hwnd sẽ nhận diện cửa sổ nào đã gọi WndProc() của chúng ta.
msg : cho số thứ tự của thô
ng điệp. Nếu hwnd cho biết ai gọi thì msg cho biết nó muốn gì. Có thể.
Có thể nó muốn nói là cửa sổ mới tạo xong (WM_CREATE) hoặc di chuyển đến vị trí mới
(WM_MOVE) hoặc thay đổi kích thước (WM_SIZE) hoặc vẽ lại ứng dụng (WM_PAINT) hoặc
khi người dùng nhấn nút Close đóng cửa sổ ứng dụng lại (WM_DESTROY).
9. Thoát chương trình nếu người dùng đóng cửa sổ Như bạn thấy, cấu trúc của một chương trình chạy trên nền Windows khá phức tạp so với chương
trình chạy trên nền Dos. Nhưng trong thế giới Windows khác hoàn toàn so với thế giới Dos. Những
chương trình Winodws có thể “chung sống” êm thắm với nhau. Chúng phải tuân thủ theo các nguyên tắc.
Bạn - một lập trình viên - càng phải nghiêm ngặt hơn trong thói quen và phong cách lập trình của mình. Người dịch: Benina (REA TEAM) Trang 4
Tổng hợp và hiệu chỉnh: NhatPhuongLe (VNCERT TEAM)
giúp bạn đỡ phải tra cứu một vài mục Win32 API reference.
Sử dụng makefile để trình biê
n dịch tự động dịch chương trình của bạn. Điều này
sẽ giúp bạn tiết kiệm thời gian thay vì phải gõ lệnh biên dịch.
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib ; Goi cac ham trong user32.lib
; va kernel32.lib
include kernel32.inc
includelib kernel32.lib
; Khai bao prototype ham WinMain
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
.DATA ; Nhung du lieu duoc khoi tao truoc
ClassName db "SimpleWinClass",0 ; Ten cua lop cua so
AppName db "Our First Window",0 ; Ten cua cua so Người dịch: Benina (REA TEAM) Trang 5
Tổng hợp và hiệu chỉnh: NhatPhuongLe (VNCERT TEAM)
Iczelion’s Tutorial Win32 ASM Tutorial 3 : A Simple Window
.DATA? ; Nhung du lieu khong duoc khoi tao
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc ; Dang ky lop cua so voi HDH
invoke CreateWindowEx,NULL,\
ADDR ClassName,\
ADDR AppName,\
WS_OVERLAPPEDWINDOW,\
CW_USEDEFAULT,\
CW_USEDEFAULT,\
CW_USEDEFAULT,\
CW_USEDEFAULT,\
NULL,\
NULL,\
hInst,\
NULL
mov hwnd,eax
invoke ShowWindow, hwnd,CmdShow ; Hien thi cua so ra desktop
invoke UpdateWindow, hwnd ; Ve va ve lai vung client cua cua so
Bạn đã thấy một chương trình tạo một cửa sổ ứng dụng đơn giản cần phải code rất
nhiều mã lệnh như trên. Nhưng phần lớn những đoạn code đó chỉ là một template code
(mã nguồn mẫu) mà bạn có thể copy từ mã lệnh của file này đến mã lệnh của một file
khác. Hay nếu bạn thích, bạn có thể dịch một vài đoạn mã nguồn đó vào trong một thư
viện để dùng như một đọan
mở đầu hay đọan code cuối. Bạn có thể chỉ viết code trong
hàm WinMain. Thật vậy, đây là những gì mà trình biên dịch C đã làm sẵn. Chúng cho
phép bạn viết code hàm WinMain không cần phải lo làm những công việc “vặt vảnh”
khác. Khác với trình biên dịch C là bạn phải có một hàm có tên là WinMain, nếu không
sẽ không thể kết hợp code của bạn với đoạn đầu hay đọan cuối của code. Bạn không bị
hạn chế vấn đề nà
y trong ngôn ngữ ASM. Bạn có thể dùng bất kỳ tên hàm nào không nhất
thiết là WinMain hoặc không có hàm nào cũng không sao.
Tiếp theo là những giải thích về đoạn code đã viết ở trên. Nó rất dài, chúng ta hãy cùng
nhau phân tích chương trình này để làm rõ vấn đề xây dựng một ứng dụng Win32 ASM
không đến nổi quá phức tạp như bạn nghĩ.
.386
.model flat,stdcall
option casemap:none
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
include windows.inc
include user32.inc
include kernel32.inc
includelib user32.lib
includelib kernel32.lib
Người dịch: Benina (REA TEAM) Trang 7
Tổng hợp và hiệu chỉnh: NhatPhuongLe (VNCERT TEAM)
Bạn phải biết API nằm ở đâu để có thể gọi các hàm API. Ví dụ: nếu bạn gọi một hàm API
trong gdi32.dll , bạn phải liên kết với với gdi32.lib.
Đây là cách mà MASM giải quyết vấn đề. Còn đối với TASM, cách liên kết với các thư
viện nhập thì đơn giản hơn, chỉ cần liên kết đến một và chỉ một file mà thôi:
import32.lib.
.DATA
ClassName db "SimpleWinClass",0
AppName db "Our First Window",0
.DATA?
hInstance HINSTANCE ?
CommandLine LPSTR ?
Kế đến là section “DATA”
Trong section .DATA, chúng ta khai báo những chuỗi kết thúc bằng zero.
Classname là tên của lớp cửa sổ (Window class)
Appname là tên cửa sổ ứng dụng của chúng ta. Người dịch: Benina (REA TEAM) Trang 8
Tổng hợp và hiệu chỉnh: NhatPhuongLe (VNCERT TEAM)