Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Ассемблер? Это просто! Учимся программировать


Информационный Канал Subscribe.Ru


Ассемблер под Windows №3

Приложение Windows, почему и зачем!


Доброго время суток, уважаемые подписщики. В этом выпуске я постараюсь подробно объяснить что мы делали в первой программе.


Однако вначале давайте разберёмся с архивами, которые я предлагаю вам скачать! Они не битые, просто запакованы WinRaR 3.0 и раннии версии их не открывают, могу конечно перейти и на zip, однако лучше скачайте WinRaR3, так как он архивирует лучше и скоро все будут пользоваться только им!


Как я уже говорил, код программы кажется полной глупостью, однако, если получше присмотреться, можно понять что зачем и почему! Я думаю зачем нужны файлы kernel32.inc и user32.inc все уже и так поняли, они содержат ссылки на процедуры одноимённых библиотек windows, поэтому первым будет подвержен детальному рассмотрению файл def.inc. Скорее всего многим из Вас уже знакома дериктива equ. При помощи этой дериктивы можно присвоить какому-то слову или выражению опредилённое значение. Это может быть очень полезно если программа общается с операционной системой при помощи закодированных сообщений. В этом случае нет нужды помнить какому номеру соответствует какое сообщение. В Windows общение програм происходит как раз путём передачи закодированных сообщений, поэтому мы каждому такому сообщению присвоим виртуальное название, а чтобы компилятор знал что мы имеем ввиду мы должны ему указать что есть что. Для этого мы и создаём файл def32.inc и записоваем как мы будем что называть. В случае Windows, Microsoft облегчила нам эти описания, официально назвав все значения. Нам остаётся только записать нужные нам значения.

IDI_APPLICATION equ 32512
IDC_ARROW equ 32512

Мы используем это при инициализации мышки и иконки в нашем приложении

WM_DESTROY equ 2

Сообщение о закрытии окна

CS_HREDRAW equ 2
cs_vREDRAW equ 1
CW_USEDEFAULT equ 80000000H
WS_OVERLAPPEDWINDOW equ 0CF0000H
SW_SHOWNORMAL equ 1

Параметры окна

СOLOR_WINDOW equ 5

Цвет окна

WNDCLASSEXstruc
cbSizedd?
styledd?
lpfnWndProcdd?
cbClsExtradd?
cbWndExtradd?
hInstancedd?
hIcondd?
hCursordd?
hbrBackgrounddd?
lpszMenuNamedd?
lpszClassNamedd?
hIconSmdd?
WNDCLASSEXends

А вот это структура нашего окна.

MSGstruc
hwnddd?
messagedd?
wParamdd?
lParamdd?
timedd?
ptdd?
MSGends

И структура сообщения, которое получает наше окно!

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

В начале мы добавляем файлы дополнения,
include def32.inc
include user32.inc
include kernel32.inc
Следующей строкой, .386, даём компилятору знать, что мы собираемся использовать возможности появившиеся в 386 - ом процессоре!
Указываем модель памяти, которая для Windows почти всегда flat.
.model flat
Указываем константы,
.const
classdb"window class 1",0
name_db"Da window!",0
Указываем переменные,
.data
wcwndclassex<4*12,cs_hredraw or cs_vredraw, offset win_proc,0,0,?,?,?, color_window+1,0,offset class,0>
.data?
msg_msg<?,?,?,?,?,?>
При указании структуры, после вида структуры в трехугольных скобках указываются параметры структуры. Рассмотрим структуру окна, первая переменная, размер окна, в нашем случае это 12 переменных по 4 байта каждая, поэтому размер структуры равен 48 или 12*4. Далее идёт стиль окна, в этой переменной каждый бит опредилят нужность/ненужность опредилённого действия, мы выставляем первый и второй биты. Следующая переменная опредиляет адрес процедуры, которая будет обрабатывать все сообщения Windows, эту процедуру мы должны написать сами! Следующие два параметра нам пока не понадобятся, поэтому оставим их на будущее. Следующие 3 двойных слова: указатель на программу-создателя, иконка и мышь. Они нам пока не известны, они будут заполнены в процессе выполнения программы. дальше двойное слово - цвет окна, 6! далее, имя меню, пока у нас нет меню, 0. Следующие два двойных слова: Имя окна, класс окна. Последнее на ненужен(пока;). Сообщения к нашему окну начнут приходить после его инициализации, поэтому все переменные этой структуры нам ещё не известны!
Далше начинаетсясам код программы, начинается он строкой .code!
Сразу после следует начальная метка, _start:. Отсюда и начинается программа.
Следующей строчкой, xor ebx,ebx мы обнуляем ЕВХ, для того чтоб когда нам понадобится записать команду "push 0", мы сможем заменить её командой "push ebx", которая в два раза короче и выполняется в 4 раза быстрее!
следующие две строки:
push ebx
call Getmodulehandle
В Windows все параметры процедурам передаются через стек, тоесть мы должны поместить в стек все параметры и вызвать процедуру, она их обработает и удалит при выходе. Процедура GetModuleHandle при входе должна получать номер модуля и возвращает так называемый указатель, при помощи которого можно работать с объектом в среде Windows. Если номер модуля 0, то процедура GetModuleHandle возвращает указатель на текущий модуль. Это мы и делаем, при этом получая указатель на нашу программу.
Следующим же шагом мы помещаем его в esi, mov esi,eax, чтобы потом можно было использовать esi как указатель на нашу программу.Следует заметить, что процедуры Windows обычно возвращают значение в eax!

Теперь начинаем создание нашего окна! В начале надо дополнить нашу структуру окна, вернее те её пункты, которые не всегда одинаковы.
В начале всего установим создателем окна нашу программу, mov dword ptr wc.hInstance,eax.
Затем загружаем обычную иконку Windows,
push IDI_Application
push ebx
call loadicon
И определяем её окну,
mov wc.hIcon,eax
Также мы поступаем с курсором,
push idc_arrow
push ebx
call LoadCursor
mov wc.hCursor,eax

Теперь наша структура готова, регистрируем её,
push offset wc
call registerclassEx
Для регистрации помещаем в стек адрес нашей структуры параметров окна и вызываем RegisterClassEx.
Далее надо создать окно. Так как это всего лишь показательнаю программа, не будем особо мучится и выставим позицию и размеры окна по умолчанию, сейчас они не имеют для нас особого значения. Чтобы выставить параметр по умолчанию надо за место параметра послать значение, которое мы назвали CW_USEDEFAULT, и так как нам придётся несколько раз подрят помещать это значение в стек, то лучше поместить это значение в регистр, например ecx, а потм уже помещать в стек этот регистр! Итак помещаем в стек параметры окна и создаём его,
mov ecx,CW_usedefault
push ebx
push esi
push ebx
push ebx
push ecx
push ecx
push ecx
push ecx
push ws_overlappedwindow
push offset name_
push offset class
push ebx
call createwindowex
После вызова CreateWindowEx мы получаем в eax указатель на наше окно.
А теперь мы совершаем маленький трюк, используя то, что параметры передаются процедурам через стек Код следующий:
push eax
push sw_shownormal
push eax
call showwindow
call updatewindow
Итак, вначале мы помещаем в стек указатель на наше окно, потом параметр показа окна, потом ещё раз указатель, и вызываем две процедуры, при этом каждая из них получает указатель на окно. Я Вас ещё не окончательно запутал!? А теперь давайте посмотрим, мы помещаем в стек три параметра, а процедура ShowWindow использует (и в конце удаляет) только 2, тоесть третий остаётся нетронутым и блогополучно передаётся процедуре UpdateWindow


Дальше продолжим в следующий раз. Я считаю, что лучше получать информацию в меньших количествах, но чаще, чем раз в месяц по паре мегабайтов текста;). Поэтому ждите вскоре продолжения разбора программы, в следующий раз мы разберем сообщения окна и процедуру окна. Счастливо оставаться! Если что пишите, Dark_Lord@land.ru, сюда, если первое мыло перегружено!


be number one Яндекс цитирования

© 2002 Россия, Москва. Авторское право: RusFAQ.ru

http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное