1. Trang chủ
  2. » Công Nghệ Thông Tin

Tìm hiểu về MessageBox

9 435 1
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Tìm hiểu về MessageBox
Tác giả Iczelion
Người hướng dẫn Benina, REA Team, NhatPhuongLe, VNCERT Team
Chuyên ngành Khoa học Máy tính
Thể loại Hướng dẫn
Định dạng
Số trang 9
Dung lượng 255,03 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Để 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

Trang 1

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 thể 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

Trang 2

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 Châ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

Trang 3

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 DWORD 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 prototype 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

http://win32asm.cjb.net 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

Trang 4

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:

option 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 chạ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)

Trang 5

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

Trang 6

Bây giờ hãy save ví dụ với tên là msgbox.asm Giả sử file ml.exe trong đường dẫn, biên dịch file msgbox.asm như sau:

option /c : nói cho MASM biết chỉ cần dịch chương trình ra mã máy (machine code)

mà thôi Không invoke link.exe Hầu như là bạn không muốn gọi link.exe một cách tự động khi bạn cần phải thi hành một vài nhiệm vụ ưu tiên khác trước khi gọi link.exe.

option /coff : nói cho MASM biết tạo ra file có phần mở rộng obj theo định dạng COFF (Common Object File Format) MASM dùng sự khác nhau của COFF, được sử

dụng dưới hệ điều hành Unix như định dạng file object và executable của chúng

otpion /Cp : nói cho MASM vẫn tôn trọng các định danh do người dùng tự đặt ra Nếu bạn sử dụng hutch’s MASM32 package, bạn có thể đặt “option casemap:none” dưới chỉ thị model

Sau khi dịch file ASM sang mã máy thành công, bạn sẽ có file msgbox.obj (file object)

Từ file này, chúng ta chỉ cần làm một thao tác nữa là có thể tạo ra file EXE (executable)

Nó chứa các chỉ thị và dữ liệu ở dạng nhị phân Nó còn thiếu, cần phải điều chỉnh lại vài địa chỉ bằng linker Chúng ta sẽ làm tiếp bước cuối cùng là liên kết tạo ra EXE như sau:

option /SUBSYSTEM:WINDOWS cho trình liên kết biết loại của file exe của chương trình

là gì (ý nói file EXE chạy trên nền platform là gì, ở đây là HĐH Windows)

option /LIBPATH: <path to import library> : nói cho trình liên kết biết các thư viện

Trang 7

Trình liên kết đọc trong file object và điều chỉnh các địa chỉ từ thư viện nhập Khi tiến

trình này hoàn tất, bạn sẽ có file msgbox.exe

Bây giờ bạn có file msgbox.exe, run nó đi bạn Bạn sẽ thấy nó không vì ngay từ đầu bạn không viết để cho chương trình thực thi gì Nhưng nó thật sự là một chương trình chạy trên nền HĐH Windows Kích thước của file chỉ có vài bytes Kế đến chúng ta khai báo Prototype của một MassageBox:

MessageBox PROTO hwnd:DWORD, lpText:DWORD, lpCaption:DWORD, uType:DWORD

hwnd là handle của cửa sổ cha (handle được xem như là ID của cửa sổ, đó là một số nguyên không dấu 32bit do HĐH tạo ra để làm định danh cho mỗi đối tượng, dùng để phân biệt cửa sổ này với cửa sổ khác trong hệ thống, sở dĩ phải cần có thông số này vì trong hệ thống có rất nhiều cửa sổ tồn tại với cửa sổ bạn đang muốn tham chiếu tới nó, nếu không dùng handle để quản lý, thì rất có thể chương trình bạn coding sẽ bị lỗi) Giá trị của nó là bao nhiêu không quan trọng Bạn chỉ nhớ rằng nó miêu tả cho một window

(cửa sổ, không có s phía sao, bạn nhớ phân biệt Windows là HĐH, còn window chính là

cửa sổ chương trình) Khi bạn muốn làm bất cứ điều gì với một cửa sổ, bạn phải tham chiếu đến nó qua handle của nó

lpText là con trỏ trỏ đến text mà bạn muốn hiển thị trong vùng client của MessageBox Một con trỏ thực ra là một địa chỉ nằm trong bộ nhớ Một con trỏ trỏ tới chuỗi Text chính

là địa chỉ của chuỗi đó

lpCaption là con trỏ trỏ tới tiêu đề của MessageBox

uType chỉ ra icon và number và lọai của button trên hộp thọai

Thay đổi file msgbox.asm, thêm vào MessageBox như sau:

Trang 8

Biên dịch và chạy chương trình Bạn sẽ thấy một hộp thoại được hiển thị với dòng text

“Win32 Assembly is Great!” như sau:

Hãy nhìn lại source code:

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

.386

.model flat, stdcall

option casemap:none

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

include windows.inc

include user32.inc

include kernel32.inc

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

.data

MsgBoxCaption db "Iczelion Tutorial No.2",0

MsgBoxText db "Win32 Assembly is Great!",0

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

.code

start:

invoke MessageBox,NULL, addr MsgBoxText,

addr MsgBoxCaption, MB_OK

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

end start

Chúng ta định nghĩa 2 string kết thúc bằng zero trong section data Hãy nhớ rằng, tất cả

các string ANSI trong Windows phải được kết thúc bởi giá trị NULL (0 hexa)

Chúng ta dùng 2 hằng số NULL và MB_OK Những hằng số này có trong file

windows.inc Vì vậy bạn có thể tham chiếu đến chúng bằng tên thay cho giá trị Sự cải

cách này có thể đọc được trong mã chương trình của bạn

Toán tử addr được dùng để chuyển địa chỉ một nhãn label đến 1 hàm Nó chỉ có giá trị khi bạn dùng chỉ thị invoke Bạn không thể dùng nó để gán địa chỉ của một label cho thanh ghi hay biến Bạn có thể dùng offset thay vì addr trong ví dụ trên Tuy nhiên có vài

sự khác nhau giữa hai toán tử này:

Trang 9

Toán tử addr Toán tử offset

_ Không được quản lý trước khi tham

chiếu

Ví dụ, nếu bạn sử dụng lệnh invoke trước

khi khai báo một label thì addr sẽ không

làm việc

.code

start:

invoke MessageBox,NULL,

addr MsgBoxText,

addr MsgBoxCaption, MB_OK

MsgBoxCaption

db "Iczelion Tutorial No.2",0

MsgBoxText

db "Win32 Assembly is

Great!",0

invoke ExitProcess,NULL

end start

MASM sẽ báo lỗi như sau :

Test.asm(16) : error A2114: INVOKE

argument type mismatch : argument

: 2

Make error(s) occured

Total compile time 468 ms

_ Có thể xử lý biến cục bộ

_ Được quản lý trước khi tham chiếu

Nếu bạn dùng offset thay vì addr trong đọan code trên, MASM sẽ assemble nó một cách trơn tru

.code start:

invoke MessageBox,NULL,

offset MsgBoxText,

offset MsgBoxCaption, MB_OK

MsgBoxCaption

db "Iczelion Tutorial No.2",0 MsgBoxText

db "Win32 Assembly is Great!",0 invoke ExitProcess,NULL end start

MASM sẽ thông báo biên dịch thành công:

"C:\RadASM\Masm\Projects\Test\Test.exe"

Make finished

Total compile time 125 ms

_ Không thể xử lý biến cục bộ

Biến cục bộ là một vùng nhớ được dành riêng trong ngăn xếp Bạn chỉ chú ý tới địa chỉ của nó

trong thời gian thực thi chương trình

_ addr có thể xử lý biến cục bộ bởi vì

trong thực tế trình biên dịch kiểm tra biến

này được tham chiếu bởi addr là một biến

toàn cục hay cục bộ Nếu nó là một biến

toàn cục, nó sẽ đặt địa chỉ của biến vào

trong file object Trong trường hợp này, nó

làm việc như offset Nếu nó là một biến

cục bộ, nó sẽ sinh ra một chuỗi chỉ thị

giống như sau, trước khi nó gọi hàm:

lea eax, LocalVar

push eax

Khi đó, lệnh lea có thể xác định được địa

chỉ của label lúc thực thi

_ offset được dịch trong suốt thời gian biên dịch bởi trình biên dịch Vì vậy là điều tất nhiên khi

offset không làm việc cho biến cục bộ

Ngày đăng: 08/11/2013, 01:15

HÌNH ẢNH LIÊN QUAN

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 - Tìm hiểu về MessageBox
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 (Trang 4)

TỪ KHÓA LIÊN QUAN

w