Главная » Win32 API » Вызов функций WinAPI в среде MASM32

0

MASM32 использует набор макросов, позволяющий приблизить синтаксис ассемблера к синтаксису языков высокого уровня и умень­шить количество ошибок. Каждый макрос имеет имя и формальные параметры, однако, в отличие от классических макросредств ассемб­лера, имена формальных параметров могут быть снабжены дополни­тельными модификаторами. Например, рассмотрим макрос с именем Prim, который имеет 4 параметра, из них первый обязателен, второй по

умолчанию инициализируется заданным значением, третий описан стандартным образом, а вместо четвертого в тело макроса может быть подставлена строка, указанная в макровызове:

Pr±m MACRO pl:REQ,   р2: = <eax>,p3,   p4:VARARG

Ключевое слово REQ указывает, что параметр является обязатель­ным. Если при макровызове второй параметр не будет указан, то он будет равен значению по умолчанию. Модификатор VARARG указы­вается только для последнего параметра и означает, что этот параметр при макроподстановке заменяется на оставшуюся строку фактических параметров, включая запятые между ними. Для данного примера мож­но указать больше 4 параметров, и тогда весь текст начиная с 4 пара­метра ассоциируется с формальным параметром р4, вместо которого подставится в тело макроса.

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

szText MACRO Name, Text:VARARG LOCAL ХЫ jmp 1±>1

Name db Text,0 ХЫ: ENDM

Для возврата из функции результата ее работы через еах использу­ется макрос:

return MACRO  arg mov eax,   arg ret ENDM

В MASM присутствует поддержка высокоуровневых операторов передачи управления. Они часто используются для облегчения вос­приятия исходного кода. Макрос .IF с директивами .ELSE, .ELSEIF, .ENDIF используются для организации ветвлений, директивы .WHILE/ .ENDW и .REPEAT/ .UNTIL [CXZ] позволяют организо­вать циклы. .BREAK производит выход из цикла, a .CONTINUE пе­реход на новую итерацию.

Удобство условного и циклического макросов заключается в воз­можности использования   в выражениях знаков сравнений и логических операций, связывающих мнемоники регистров и имен перемен­ных.

Использование макроса .IF позволяет организовать перебор значе­ний в оконной функции, аналогичный оператору switch. Он имеет син­таксис:

.IF условие1

операторы 1 [.ELSEIF] условие2

операторы2

[.ELSE]

операторы N .ENDIF

Этот макрос генерирует сравнение и условные переходы таким об­разом, чтобы при истинности условия1 выполнялись операторы1 до тех пор, пока не встретится следующий .ELSEIF, .ELSE, или .ENDIF. Макросы .IF могут быть вложенными. Оператор .ELSEIF использует­ся для выделения блока операторов, выполняющихся, если предшест­вующие условия в .IF и .ELSEIF ложны, а условие в текущем .ELSEIF истинно. Внутри .IF могут быть несколько блоков .ELSEIF. .ELSE определяет выполняемый блок операторов, если все предыду­щие условия были ложны. .ENDIF закрывает текущий .IF.

Макрос REPEAT выполняет тело макроса, пока условие не станет истинным, например, следующий макрос повторяет код между repeat и until, пока значение регистра ebx не станет равным 5:

.REPEAT

; тело макроса

.UNTIL ebx=5

Макрос WHILE служит для организации выполнения тела макроса до тех пор, пока условие истинно:

.WHILE ebx=5 ; тело макроса .ENDW

Чтобы прервать цикл и выйти из него, используется директива .BREAK:

mov eax,2

.WHILE ebx=5

inc eax

.IF eax==4

.BREAK

.ENDIF

.ENDW

Если еах=4, цикл будет прерван.

В макросах .REPEAT и .WHILE для перехода на проверку условия цикла используется директива CONTINUE.

Для упрощения вызова API-функций используется макрос invoke. Пусть необходимо вызвать API-функцию с именем FunctionName, имеющую 4 параметра. Четвертый и второй параметры представляют собой адреса некоторых объектов. Традиционный вызов функции име­ет вид:

push offset par4

push рагЗ

push offset par2

push parl

call FunctionName

С использованием invoke вызов имеет вид:

invoke FunctionName,par1,ADDR par2,par3,ADDR par4

Рассмотрим программу на MASM32, выводящую окно сообщения с кнопкой ОК, текстом и заголовком.

.model flat, stdcall

option casemap :none   ; case sensitive

include \masm32\include\windows.inc

include \masm32\include\user32.inc

include \masm32\include\kernel32.inc

szText MACRO Name, Text:VARARG

LOCAL 1Ы

jmp 1Ы

Name db Text,0 1Ы:

ENDM

includelib \masm32\lib\user32.lib

includelib \masm32\lib\kernel32.lib . code start:

szText  szDlgTitie, "First MASM"

szText  szMsg,"Assembler   "

invoke MessageBox,0,ADDR  szMsg,ADDR  szDlgTitle,

MB_OK invoke ExitProcess,0 end start

Используем плоскую модель памяти и стандартный вызов подпро­грамм, согласно которому параметры помещаются в стек в порядке справа налево, а убираются из стека подпрограммой за счет ret N. Для работы программы в нее необходимо включить файл windows.inc, со­держащий описание всех констант, макроопределений и структур Windows, используемых в системе. Например, определение структуры сообщения на Ассемблере имеет вид:

MSG   STRUCT

hwnd

DWORD

?

message

DWORD

?

wParam

DWORD

?

lParam

DWORD

?

time

DWORD

?

pt

POINT

<> 

MSG  ENDS

Определение структуры для регистрации класса окна WNDCLASS:

WNDCLASS STRUCT

style

DWORD

?

lpfnWndProc

DWORD

?

cbClsExtra

DWORD

?

cbWndExtra

DWORD

?

hlnstance

DWORD

?

hi con

DWORD

?

hCursor

DWORD

?

hbrBackground

DWORD

?

lpszMenuName

DWORD

?

lp s z ClassName

DWORD

?

WNDCLASS ENDS

Если программисту не нужны все описания из windows.inc, он должен явно включить в программу только нужные описания систем­ных констант и структур данных.

Включаемые в программу kernel32.inc и user32.inc содержат опи­сания прототипов всех функций, содержащихся соответственно в ис­пользуемых библиотеках функций kernel32.1ib и user32.1ib. Прототипы нужны для облегчения проверки при трансляции количества и раз­меров параметров процедуры. Описания прототипов имеют вид:

Имя_процедуры PROTO список_описаний_типов

Список_описаний_типов состоит из разделенных запятыми кон­струкций, начинающихся двоеточием, за которым следует ключевое слово, характеризующее размер параметра DWORD, WORD, BYTE. Например, прототипы рассмотренных WinMain и WndProc имеют вид:

WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD

Если программисту нужны не все функции из библиотек, а только некоторые, он должен явно описать прототипы используемых внешних процедур и подключить только библиотеки без файлов с расширением inc.

С учетом вышеизложенного, описание функции WinMain на MASM32 имеет вид:

hWnd    dd     ?

WinMain proc hlnst:DWORD, hPrevInst :DWORD, CmdLine:DWORD, CmdShow :DWORD

LOCAL wc:WNDCLASSEX

LOCAL msg:MSG

szText szClassName,"My_Class"

szText szAppName,"Application" ; заполнение полей wc

mov wc.lpfnWndProc, offset WndProc ;адрес WndProc

push hlnst

pop wc.hlnstance

mov wc.lpszClassName, offset szClassName

invoke LoadIcon,hlnst,500

mov wc.hlcon, eax

invoke LoadCursor,NULL,IDC_ARROW

mov wc.hCursor,eax

invoke RegisterClassEx,ADDR wc ; регистрация класса окна

invoke CreateWindowEx, NULL, addr szClassName, addr szAppName,  WS_OVERLAPPEDWINDOW, 100,100, 400, 200, NULL, NULL, hlnst, NULL

mov hWnd, eax

invoke ShowWindow, hWnd, SW_SHOWNORMAL

invoke UpdateWindow, hWnd

.while TRUE

invoke GetMessage, addr msg, NULL, 0, 0

.break .if (!eax)

invoke    TranslateMessage, addr msg invoke    DispatchMessage, addr msg

.endw

mov eax, msg.wParam

ret WinMain endp

Оконная функция на MASM32:

WndProc proc hWin:DWORD, uMsg: DWORD, wParam:DWORD, lParam :DWORD .if uMsg == WM_CLOSE

szText TheText,"Please Confirm Exit" invoke MessageBox,hWin,ADDR TheText,

ADDR szDisplayName, MB_YESNO .if eax == IDNO return 0 .endif .elseif uMsg = WM_DESTROY

invoke PostQuitMessage,NULL return 0 .endif invoke DefWindowProc,hWin,uMsg,wParam,lParam ret WndProc endp

Процесс компиляции программ на MASM32 осуществляет Ml.exe, a редактированием связей занимается Link.exe.

Источник: Сучкова, Л.И. Win32 API: основы программирования: учебное пособие/ Л.И. Сучкова; АлтГТУ им. ИИ. Ползунова. -Барнаул, АлтГТУ, 2010. 138 с, ил.

По теме:

  • Комментарии