Ос Windows предоставляет программисту большой набор функций (API - application programming interface). Ипользуя их, можно значительно упростить программу, сделать ее независимой от аппаратного обеспечения.
Функции находятся в библиотеках - файлах .dll (Dynamic link library), идентифицируются по имени (английской ASCIIZ строкой) либо по номеру (ordinal).
Большинству функций свойственна обратная совместимость. Т.е более новые версии Windows поддерживают почти все функции предыдущих.
Для просмотра функций, экспортируемых модулем, можно использовать программу PE Viewer, которая находится на сайте рассылки (раздел разработки)
-------------------------------
Функции Windows обычно используют соглашение о вызове процедур, называемое stdcall:
Параметры передаются через стэк в обратном порядке
После выполнения, функция возвращает результат в регистр eax
изменяет значения регистров eax,ecx,edx, eflags
очищает стэк (от помещенных в него параметров при вызове)
Процедура, написанная вами и вызываемая функциями Windows, также должна соответствовать этому соглашению.
Пример:
Вызов функции Windows - MessageBoxA
push 0
push offset MsgTitle ;параметр #3 - заголовок сообщения
push offset MsgText ;параметр #2 - текст сообщения
push 0
call MessageBoxA
Если функция использует другое соглашение о вызове, это указано в документации. Например, функция wsprintf использует соглашение "C" (_cdecl), т.к количество передаваемых ей параметров не постоянно. Разница между stdcall и "C" только в том, что в последнем случае, вызывающая функцию программа должна сама очищать стэк. После вызова функций "C" нужно удалить параметры из стэка: add esp,(количество параметров)*4.
Для более простого и понятного вызова функций можно использовать макросы:
TASM: call MessageBoxA,0,offset MsgText,offset MsgCaption,0
MASM: invoke MessageBoxA,0,offset MsgText,offset MsgCaption,0
При компиляции, Assembler автоматически генерирует код, который показан в предыдущем примере.
Строчкой .model flat,stdcall задается модель памяти (flat для программ под Windows), и алгоритм действия макросов работы с процедурами (stdcall для функций Windows).
-------------------------------
Многие функции Windows имеются в двух версиях: с окончанием "A" для Ansi текста, и "W" для Unicode. В документации указано только общее название функции (например MessageBox). Т.к мы хотим отобразить Ansi строку, то добавляем суффикс "A". Почти все функции, работающие с текстовыми строками, имеют соответствующие суффиксы.
Числа, передаваемые функции, обычно имеют тип dword. Некоторые числа обозначаются константами, например в описании MessageBox последний параметр - тип окошка - константы MB_
Список некторых констант находится в файле include\windows.inc в каталоге с компилятором. Для его использования нужно указать в программе:
include "папка с компилятором"\include\windows.inc
-------------------------------
Для использования функций Windows в программе, нужно указать, что они содержатся в другом модуле (пример: extrn ExitProcess:proc),
и подключить lib файл с описанием функций (либо задать линкеру в командной строке, либо строчкой: includelib путь .lib файла).
Для вызова большинства функций можно использовать файл import32.lib в пакете с компилятором (папка lib). Для остальных функций можно создать свой .lib файл из .dll, используя программу implib.exe из пакета с компилятором (ключ -c).
При загрузке программы, Windows автоматически загружает все используемые библиотеки, и находит адреса всех используемых функций, по которым и передается управление при вызове из программы.
Преимущество данного метода - простота использования функций.
Недостаток - если библиотека или функция отсутствует, ОС выдаст сообщение об ошибке при загрузке программы. В таком случае код программы не получит управления и загрузка прервется.
Следующим образом можно самому загрузить библиотеку с функцией, найти ее адрес и вызвать.
.data
LibName db 'user32.dll',0
ApiName db 'MessageBoxA',0
MsgTitle db 'Message',0
MsgText db 'Вызвана функция MessageBoxA',0
.code
call LoadLibraryA,offset LibName ;загрузка библиотеки. возвращает хэндл библиотеки
;(адрес, по которому произошла загрузка). Ноль при ошибке.
cmp eax,0
jz ErrorLoadingLib
call GetProcAddress,eax,offset ApiName ;возвращает адрес функции из библиотеки.
;Ноль- ошибка. Последний параметр - адрес с названием или ordinal
cmp eax,0
jz ErrorGettingAddress
call eax,0,offset MsgText,offset MsgTitle,0
Преимущество использования данного метода вызова функций - возможность порграммно отреагировать на отсутствие библиотеки.
Недостаток - усложнение программы.
Однажды загрузив библиотеку, можно на протяжении всей программы использовать ее функции (до выгрузки). Полученный адрес функции действителен до выгружения библиотеки.
-------------------------------
При ошибке, функции обычно возвращают число, обозначающее ошибку (иногда - код ошибки). Обычно код ошибки можно узнать вызвав функцию GetLastError.
Вместо неиспользуемых, или неважных параметров чаще всего нужно передавать ноль (указывается в документации).
-------------------------------
Для объявления своей процедуры в программе, можно использовать следующую форму записи (см DisplayErrorCode в примере к статье):
AnyProc proc AnyParam1:dword,AnyParam2:dword
local LocalVar:byte
local AnyDword:dword
....
ret
AnyProc endp
Код объявленной таким образом процедуры, может удобно использовать входные параметры обращаясь к ним по именам, и локальные переменные (находятся в стэке, адресуются регистром ebp). Все команды ret автоматически заменяются на ret (размер всех параметров в стэке), если указано соответствующее соглашение.
-------------------------------
Часто в описании функции используется термин handle (хэндл). Хэндл - это 32 битное число, обозначающее какой - либо используемый объект. Для доступа к объекту обычно вызывается функция открытия, которая возвращает хэндл (до открытия хэндл не существует).
При дальнейшей работе указывается хэндл объекта, а после использования нужно освободить объект, перередав соответствующей функции хэндл. Многие объекты автоматически освобождаются при выгрузке программы. Хэндл действителен только в текущем процессе.
-------------------------------
В MSDN информация об основных функциях Windows находится в Windows Development\Windows Base Services. А также в User Interface Design and Development.
Пример использования функцйй Windows и работы с хэндлами. Для упрощения программы и подтверждения обратной совместимости, используются функции, существующие еще в 16 битной версии Windows. Программа записывает в файл c:\test.txt текстовую строку. Процедура DisplayErrorCode может быть использована вами для отладки. Для ее выполнения можно, например, указать недопустимое имя файла (переменная TestFileName).
.386
.model flat,stdcall
extrn _lcreat:proc ;используемые функции
extrn _lwrite:proc
extrn _lclose:proc
extrn MessageBoxA:proc
extrn ExitProcess:proc
.data
MsgTitle db 'Запись в '
TestFileName db 'с:\test.txt',0
WriteString db 'Текст для записи в файл'
StringSize equ $-offset WriteString
FmtString db '%lu байт',0
FmtHex db '%lX',0
ErrNumStr db 'Ошибка #'
ErrCode db 9 dup (?)
OkString db 'Успешно записано '
WBytes db 20 dup (?)
FileHandle dd ?
.code
start:
call _lcreat,offset TestFileName,0 ;создадим файл.
;Получим хэндл (-1 при ошибке)
mov [FileHandle],eax
inc eax
jnz FileCreated
call DisplayErrorCode
jmp ExitProgram
FileCreated:
call _lwrite,[FileHandle],offset WriteString,StringSize ;запишем в файл.
;Получим количество записанных байт (-1 при ошибке)
inc eax
jnz TextWrited
call DisplayErrorCode
jmp ExitAndClose
TextWrited:
dec eax
extrn _wsprintfA:proc
call _wsprintfA,offset WBytes,offset FmtString,eax ;переведем число
;(количество записанных байт) в текст.
add esp,3*4 ;т.к функция "C" очистим стэк от параметров
call MessageBoxA,0,offset OkString,offset MsgTitle,0
ExitAndClose:
call _lclose,[FileHandle] ;закроем файл.
ExitProgram:
call ExitProcess,0
;Процедура, отображающая код последней ошибки.
;Входных параметров нет.
;Использует переменные: запись ErrCode;
; чтение:FmtHex;ErrNumStr
; функции Windows
extrn GetLastError:proc
extrn FormatMessageA:proc
extrn LocalFree:proc
FORMAT_MESSAGE_FROM_SYSTEM equ 1000h
FORMAT_MESSAGE_ALLOCATE_BUFFER equ 100h
DisplayErrorCode proc
local ErrStrPointer:dword
call GetLastError
push eax
call _wsprintfA,offset ErrCode,offset FmtHex,eax
add esp,3*4
pop eax
lea ecx,ErrStrPointer
call FormatMessageA,FORMAT_MESSAGE_FROM_SYSTEM or \
FORMAT_MESSAGE_ALLOCATE_BUFFER,0,eax,0,ecx,0,0
call MessageBoxA,0,[ErrStrPointer],offset ErrNumStr,0
call LocalFree,[ErrStrPointer]
ret
DisplayErrorCode endp
end start
-------------------------------
Содержание дальнейших выпусков зависит от вас. Будут разъясняться те темы, которые непонятны большинству читателей. Сайт рассылки: asm32.nm.ru. Присылайте свои вопросы и предложения по адресу: asm32@nm.ru . -------------------------------
Автор рассылки Владимир Пронин. Любое коммерческое использование материалов рассылки без ведома и прямого согласия автора запрещено.
Письма присланные автору рассылки могут быть опубликованы целиком или частично без предварительного уведомления. Если вы не хотите, чтобы ваше письмо было опубликовано укажите это в начале письма.
Перепечатка материалов разрешена только с непосредственной ссылкой на asm32.nm.ru