Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скляров И. Изучаем Assembler за 7 дней (2010).pdf
Скачиваний:
1335
Добавлен:
23.02.2015
Размер:
2.11 Mб
Скачать

http://www.sklyaroff.ru

154

.data

 

 

hello_mess

db "Первая программа под Windows на ассемблере", 0

 

hello_title

db "Hello, World!", 0

 

.code

 

 

start:

 

 

push

MB_OKCANCEL

 

push

offset hello_title

 

push

offset hello_mess

 

push

0

 

call

MessageBoxA

 

push

0

 

call

ExitProcess

 

end start

7.2.1. Директива INVOKE

Вы можете для вызова API-функций использовать директиву INVOKE, которая позволяет записывать вызовы в более удобном виде. Например, следующий вызов:

push MB_OKCANCEL

push offset hello_title push offset hello_mess push 0

call MessageBoxA

с помощью директивы INVOKE будет записан следующим образом:

invoke MessageBoxA,0,addr hello_mess,addr hello_title, MB_OKCANCEL

Вызов функции ExitProcess можно записать следующим образом: invoke ExitProcess, 0

В директиве INVOKE можно использовать оператор ADDR вместо OFFSET. Далее в примерах кода мы будем использовать директиву INVOKE.

7.3. Консольное приложение

Хотя Windows является графической оконной системой, но вместе с тем она позволяет создавать консольные приложения, т. е. приложения которые подобно DOS-приложениям работают с командной строкой. Для создания консольных приложений в Windows существуют специальные API-функции.

Ввод и вывод в консоли выполняется с помощью функций ReadConsole и WriteConsole соответственно:

BOOL WINAPI WriteConsole(

HANDLE hConsoleOutput, const VOID* lpBuffer,

DWORD nNumberOfCharsToWrite, LPDWORD lpNumberOfCharsWritten, LPVOID lpReserved

);

Параметры функции:

hConsoleOutput — дескриптор стандартного потока вывода;

http://www.sklyaroff.ru

155

lpBuffer — указатель на строку которую нужно вывести;

nNumberOfCharsToWrite — число символов строки, которые нужно вывести;

lpNumberOfCharsWritten — указатель на переменную DWORD, куда будет помещено количество действительно выведенных символов после выполнения функции;

lpReserved — зарезервированный параметр для использования в будущем, поэтому должен быть равен нулю.

BOOL WINAPI ReadConsole(

HANDLE hConsoleInput, LPVOID lpBuffer,

DWORD nNumberOfCharsToRead, LPDWORD lpNumberOfCharsRead, LPVOID lpReserved

);

Параметры функции:

hConsoleInput дескриптор стандартного потока ввода;

lpBuffer — указатель на буфер, в который будет записана принятая строка;

nNumberOfCharsToRead — максимальное число символов, которые будут приняты;

lpNumberOfCharsRead — число фактически считанных символов;

lpReserved — зарезервированный параметр для использования в будущем, поэтому должен быть равен нулю.

Дескрипторы ввода-вывода необходимо получить с помощью функции GetStdHandle:

HANDLE WINAPI GetStdHandle(DWORD nStdHandle);

Параметр nStdHandle может иметь одно из трех значений:

STD_INPUT_HANDLE equ -10 STD_OUTPUT_HANDLE equ -11 STD_ERROR_HANDLE equ -12

Эти идентификаторы определены в файле WINDOWS.INC.

В листинге 7.2 показана простейшая программа, которая просит пользователя ввести свое имя и затем приветствует его по имени, например:

Your name: Ivan Sklyaroff Hello, Ivan Sklyaroff

С помощью API-функции

BOOL WINAPI SetConsoleTitle(LPCTSTR lpConsoleTitle);

мы выводим в заголовке консоли фразу "DEMO CONSOLE PROGRAM".

Единственный аргумент этой функции — адрес строки символов, которая будет выведена в заголовке окна консоли.

Компиляция:

ml /c /coff /Cp conwin.asm

link.exe /SUBSYSTEM:CONSOLE /LIBPATH:d:\masm32\lib conwin.obj

Листинг 7.2. Консольная программа под Windows (conwin.asm)

.386

.model flat,stdcall

include \masm32\include\windows.inc include \masm32\include\kernel32.inc

http://www.sklyaroff.ru

 

156

includelib \masm32\lib\kernel32.lib

 

 

 

.const

 

 

 

 

ConsoleTitle

db

"DEMO CONSOLE PROGRAM",0

 

.data

 

 

 

 

msg1

db

"Your name: "

 

 

msg1_len = $-msg1

 

 

 

msg2

db

"Hello, "

 

 

msg2_len = $-msg2

 

 

 

InputBuffer

db

100 dup (?)

; буфер для ввода

len_InputBuffer = $-InputBuffer

 

 

 

.data?

 

 

 

 

hOutputdd

?

; хендл для вывода

hInput

dd

?

; хендл для ввода

nRead

dd

?

; прочитано байт

nWritendd

?

; напечатано байт

.code

start:

invoke SetConsoleTitleA,addr ConsoleTitle

; получаем хендл для вывода

invoke GetStdHandle,STD_OUTPUT_HANDLE mov hOutput,eax

invoke WriteConsoleA,hOutput,addr msg1,msg1_len,addr nWriten,NULL

; получаем хендл для ввода

invoke GetStdHandle,STD_INPUT_HANDLE mov hInput,eax

invoke ReadConsoleA,hInput,addr InputBuffer,len_InputBuffer,addr nRead,NULL

invoke WriteConsoleA,hOutput,addr msg2,msg2_len,addr nWriten,NULL

invoke WriteConsoleA,hOutput,addr InputBuffer,nRead,addr nWriten,NULL

invoke ExitProcess,0

end start

В листинге 7.3 показано еще одно консольное приложение. Данная Windowsпрограмма является аналогом MS-DOS программы из листинга 5.2, которая складывает два вещественных числа с плавающей запятой.

Кроме функции FpuFLtoA все остальные функции в этой программе вам уже знакомы. Функция FpuFLtoA предназначена для вывода вещественного числа (в нашем случае результат сложения вещественных чисел) на экран. Данная функция не является API-функцией, а является внутренней MASM32-функцией и входит в специальную библиотеку FPU.LIB, которая подключается в начале нашей программы также как и остальные библиотеки. Подробное описание функции на английском языке можно найти в справке MASM32, которая обычно располагается в каталоге

\masm32\help\fpuhelp.chm.

http://www.sklyaroff.ru

157

Функция FpuFLtoA может работать только с 80-битовыми числами и имеет четыре параметра:

FpuFLtoA ( lpSrc1 lpSrc2 lpszDest uID

)

lpSrc1 — адрес 80-битового числа, которое будет выводиться на экран (этот параметр игнорируется, если uID имеет значение SRC1_FPU);

lpSrc2 — беззнаковое целое указывающее количество десятичных знаков после запятой или адрес беззнакового целого (в зависимости от параметра uID);

lpszDest — адрес буфера, куда будут записаны символы, в которые преобразуется число. Буфер должен быть достаточно большим, чтобы вместить возвращаемые символы. Самое большое число может иметь 17 символов перед знаком десятичной точки, знак десятичной точки, 15 десятичных цифр после точки, и завершающий нуль (таким образом, максимум 34 символа);

uID — флаги, управляющие работой функции. Один из флагов SRC1_? может объединяться с помощью операции OR только с одним из SRC2_? и одним из STR_? флагов (Флаг STR_REG не нужно объединять оператором OR, если строка должна быть возвращена в десятичном формате; потому что по умолчанию так).

uID флаги и их назначение:

SRC1_FPU — первый параметр функции Src не используется (уже на FPU);

SRC1_REAL — первый параметр Src должен быть адресом 80-битного числа хранящегося в обычной памяти;

SRC2_DMEM — второй параметр Src2 должен быть адресом 32-битного беззнакового числа;

SRC2_DIMM — второй параметр Src2 должен быть простым 32-битным беззнаковым числом;

STR_REG — строка должна быть возвращена в десятичном формате;

STR_SCI — строка должна быть возвращена в научном формате. Компиляция:

ml /c /coff /Cp fpuconwin.asm

link.exe /SUBSYSTEM:CONSOLE /LIBPATH:d:\masm32\lib fpuconwin.obj

Листинг 7.3. Консольная программа под Windows складывающая два вещественных числа (fpuconwin.asm)

.386

.model flat,stdcall option casemap:none

include \masm32\include\windows.inc include \masm32\include\kernel32.inc include \masm32\include\fpu.inc includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib includelib \masm32\lib\fpu.lib

BSIZE

equ

30

 

 

.data

 

 

num1

dd

45.56

; первое вещественное число

num2

dd

30.13

; второе вещественное число