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

Windows = Окна


Доброго время суток, уважаемые подписчики. Сегодня у нас первый урок ассемблера под Windows. А что есть Windows?! В переводе с английского это значит окна, и самым главным элементом Windows, на мой взгляд, являются окна.(Думаю MessageBox все уже умеют вызывать;) В этом уроке Вы узнаете как создавать оконное приложение на языке ассемблер. Для начала нам нужны инструменты для компиляции наших программ, поэтому я предполагаю, что следующие программы у Вас есть(всё это есть в MASM32):
- ml.exe
- link.exe
- kernel32.lib
- user32.lib
- mspdb50.dll
Для написания програм Вам понадобится любой текстовой редактор, я лично пользуюсь блокнотом (Notepad) из стандартной инсталяции Windows. На мой взгляд, лучше создать директорию, в которую сложить все эти файлы, и в которой создавать свои, но это личное дело каждого.


В Windows, в отличии от Доса, всё происходит путём обращения к системным функциям, а прирывания используются для системных нужд. Существует набор так называемых библиотек (файлы с расширением .dll), к которым и происходит обращение. Библиотеки удобны тем, что их можно загрузить в память, если они требуются, и выгрузить, когда их никто не использует. Также одну и ту же библиотеку может использовать одновременно несколько программ. То есть это, как процедуры в памяти, которые можно использовать из любого места памяти. Однако надо сказать программе, где находятся эти процедуры. Именно для этого нам и нужны файлы kernel32.lib и user32.lib, они и содержат эти метки. Но чтоб ассемблер мог понять что они значат, и как их использовать, нам самим нужно создать файлы .inc с описанием процедур. Поэтому для начала нам потребуется создать два файла, kernel32.inc и user32.inc. В них нам надо указать, какие процедуры из какой библиотеки нам доступны.

kernel32.inc:
includelib kernel32.lib
   extrn __imp__GetModuleHandleA@4:dword
   extrn __imp__ExitProcess@4:dword
ExitProcess     equ __imp__ExitProcess@4
GetModuleHandle equ __imp__GetModuleHandleA@4

user32.inc:
includelib user32.lib
   extrn __imp__DispatchMessageA@4:dword
   extrn __imp__TranslateMessage@4:dword
   extrn __imp__GetMessageA@16:dword
   extrn __imp__LoadIconA@8:dword
   extrn __imp__UpdateWindow@4:dword
   extrn __imp__ShowWindow@8:dword
   extrn __imp__CreateWindowExA@48:dword
   extrn __imp__DefWindowProcA@16:dword
   extrn __imp__PostQuitMessage@4:dword
   extrn __imp__RegisterClassExA@4:dword
   extrn __imp__LoadCursorA@8:dword
   extrn __imp__DestroyWindow@4:dword
DispatchMessage  equ __imp__DispatchMessageA@4
TranslateMessage equ __imp__TranslateMessage@4
GetMessage       equ __imp__GetMessageA@16
LoadIcon         equ __imp__LoadIconA@8
UpdateWindow     equ __imp__UpdateWindow@4
ShowWindow       equ __imp__ShowWindow@8
CreateWindowEx   equ __imp__CreateWindowExA@48
DefWindowProc    equ __imp__DefWindowProcA@16
PostQuitMessage  equ __imp__PostQuitMessage@4
RegisterClassEx  equ __imp__RegisterClassExA@4
LoadCursor       equ __imp__LoadCursorA@8
DestroyWindow    equ __imp__DestroyWindow@4

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

def32.inc:
IDI_APPLICATION     equ 32512
WM_DESTROY          equ 2
CS_HREDRAW          equ 2
CS_VREDRAW          equ 1
CW_USEDEFAULT       equ 80000000h
WS_OVERLAPPEDWINDOW equ 0CF0000h
IDC_ARROW           equ 32512
SW_SHOWNORMAL       equ 1
COLOR_WINDOW        equ 5

WNDCLASSEX struc
 cbSize        dd ?
 style         dd ?
 lpfnWndProc   dd ?
 cbClsExtra    dd ?
 cbWndExtra    dd ?
 hInstance     dd ?
 hIcon         dd ?
 hCursor       dd ?
 hbrBackground dd ?
 lpszMenuName  dd ?
 lpszClassName dd ?
 hIconSm       dd ?
WNDCLASSEX ends

MSG struc
 hwnd    dd ?
 message dd ?
 wParam  dd ?
 lParam  dd ?
 time    dd ?
 pt      dq ?
MSG ends

Всё, приготовления закончены! Теперь начинаем писать программу!
window.asm:
;добавляем наши библиотеки и описания
include def32.inc
include user32.inc
include kernel32.inc
 .386        ;модель памяти flat появилась на 386 - ом процессоре
 .model flat

;константы
 .const
class db "window class 1",0 ;класс окна
name_ db "Da window!",0     ;Имя окна
;переменные

 .data
wc   wndclassex<4*12, cs_hredraw or cs_vredraw, offset win_proc,0,0,?,?,?, color_window+1,0,offset class,0>

 .data?
msg_ msg <?,?,?,?,?,?> ;сообщения

;сам код
 .code
_start: ;начальная метка
 xor ebx,ebx
 push ebx
 call GetModuleHandle
 mov esi,eax                    ;получаем hanle нашей программы в esi
 mov dword ptr wc.hInstance,eax ;так-же устанавливаем его отцом нашего окна
 push IDI_APPLICATION
 push ebx
 call LoadIcon
 mov wc.hIcon,eax               ;стандартная иконка Windows
 push idc_arrow
 push ebx
 call LoadCursor
 mov wc.hCursor,eax             ;стандартную мышь
 push offset wc
 call RegisterClassEx           ;регистрируем его (переменную окна wc)
 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            ;И создаём окно!
 push eax
 push SW_SHOWNORMAL
 push eax
 call ShowWindow                ;показываем его народу;)
 call UpdateWindow              ;показываем его и обновляем!
 mov edi,offset msg_
main_:
 push ebx
 push ebx
 push ebx
 push edi
 call GetMessage                ;получаем сообщение
 test eax,eax
 jz exit_                       ;если это 0, то выход
 push edi
 call TranslateMessage
 push edi
 call DispatchMessage           ;преобразуем сообщения для процедуры окна.
 jmp main_
exit_:
 push ebx
 call ExitProcess               ;выход из программы

win_proc proc                   ;процедура окна!
 push ebp
 mov ebp,esp

wp_hWnd   equ dword ptr [ebp+08h] ;так как сообщения передаются
wp_uMsg   equ dword ptr [ebp+0Ch] ;при помощи стека,
wp_wParam equ dword ptr [ebp+10h] ;то можно напрямую
wp_lParam equ dword ptr [ebp+14h] ;к ним обращатся!

 cmp wp_uMsg,WM_DESTROY            ;если сообщение о закрытии окна
 jne not_
 push 0
 call PostQuitMessage              ;послать сообщение о выходе
 jmp end_
not_: ;если нет
 leave
 jmp DefWindowProc                 ;Пусть Windows обрабатывает сообщение
end_:
 leave
;Возвращение из процедуры с удалением из стека четырёх(16/4=4) параметров
 ret 16
win_proc endp

 end _start

Конечно это кажется каким-то бредом, однако в этом есть логика!

И, самое главное, как это компилировать (переводить в запускаемый формат!). Для этого Вам понадобятся вышеописанные инструменты! Можно компилировать двумя способами, в ручную и "батником" (файл формата .bat, в который вносятся все команды поочерёдно в порядке их выполнения!). Я предпочитаю батник, и Вам советую. Итак нужно создать файл имя.bat и вписать в него:

ml /c /coff имя_программы.asm
link имя_программы.obj /subsystem:windows

где имя_программы имя файла с кодом!


К сожалению, еслиб я ещё всё объяснил, то этот урок занял-бы конкретно времени и места, к тому же всегда есть те, кто жаждет понять сам, без чьей либо помощи, поэтому здесь только очень поверхносная информация, обещаю в течении пары дней описать всё это дело подробно, а на пока хватит! Если что пишите, Dark_Lord

Сайт управляется системой uCoz