На главную  Программирование на Ассемблере в Fasm  Операционные Системы  Написать Автору  Полезные ссылки



Для поиска введите икомое слово в текстовое поле и нажмите Enter:



Вот первые строки нашего исходника:
format PE GUI 4.0
entry start

include '%fasminc%\win32a.inc';подключаем win32a заголовочный файл
include '%fasminc%\macro\if.inc';подключаем HLL-Style заголовочный файл

Что изменилось?Конечно вы заметили странное нечто.Вот оно:
include '%fasminc%\macro\if.inc';подключаем HLL-Style заголовочный файл -Это тот самый файл который позволит нам использовать .if -.else -.endif, .while -.endw и т.д.
Смотрим дальше:

AppName db 'Простое окно в fasm',0     ;Имя программы
ClassName db 'Simple Window',0 ;Класс окна

  mainhwnd dd ?
  hinstance dd ?

  msg MSG             ; структура msg
  wc WNDCLASSEX       ; структура WC
-Мы видим три группы по две строки.Впервых двух мы определили строки с названием программы и именем создаваемого нами класса окна.Вторая группа-две переменные для хранения хендлов создаваемого окна и программы.Далее мы видим две структуры(Это такие штуки похожие на шкафы с книгами в библиотеке.Каждый шкаф получает своё имя.Кроме того каждая книга имеет своё имя.Нам надо книгу "Властелин колец" из шкафа фентези?Нашли нужный шкаф и находим в нём книгу.Нужна другая книга по данной тематике-перероем этот же шкаф (но не сто шкафов-ведь книги собранны по тематике.)Так и в структуре собраны данные(в виде членов структуры) по одной теме.)
Затем нам надо получить хендл программы(модуля),который нам пригодиться потом не раз для вызова других функций:

invoke GetModuleHandle,0;Взять дескриптор пpогpаммы
mov    [hinstance],eax

Функция GetModuleHandle с параметром 0(NULL) возврашает нам хендл модуля(который используется для вызова функцийй загружающих иконки,Курсоры,Изображения и т.д.).Мы помешаем его из eax в переменную hinstance.Обратите внимание что для того чтобы занести что-либо в переменную(ячейку памяти),надо взять имя переменной в скобки:
mov [переменная],eax
-где eax регистр в котором функция(любая) возвращает резкльтат своей деятельности.
Для создания окна нам надо указать предопределённый класс окон или зарегестрировать новый.Мы создадим новый класс.Для этого мы заполняем структуру WNDCLASSEX данными необходимыми для регистрации класса:

    mov [wc.cbSize],WNDCLASSEX;(12 dd *4(dd=4byte))
    invoke    LoadIcon,[hinstance],10 ;загрузка иконки
    mov    [wc.hIcon],eax  ;Вносим в wc хендл иконки
    mov [wc.hIconSm],eax
    invoke LoadCursor,0,IDC_ARROW;Вносим в wc хендл
курсора.

    mov    [wc.hCursor],eax
    mov    [wc.style],CS_HREDRAW       ;стиль окон
    mov    [wc.lpfnWndProc],WindowProc ;Адpес пpоцедуpы окна,ответственной за окна, создаваемых из класса.
    mov    [wc.cbClsExtra],0 ;Количество дополнительных байтов,котоpые нужно заpезеpвиpовать (они будут следовать за самой стpуктуpой). По умолчанию, опеpационная система инициализиpует это количество в 0. Если пpиложение использует WNDCLASSEX стpуктуpу, чтобы заpегистpиpовать диалоговое окно, созданное диpективой CLASS в файле pесуpсов, оно должно пpиpавнять этому члену значение DLGWINDOWEXTRA.

    mov    [wc.cbWndExtra], ;
    mov    eax,[hinstance]    ;Хэндл модуля.
    mov    [wc.hInstance],eax
    mov    [wc.hbrBackground],COLOR_WINDOW+1 ;Цвет фона
    mov    [wc.lpszMenuName],NULL ;Хэндл меню для окон, созданных из класса по умолчанию.
    mov    [wc.lpszClassName],ClassName  ;Имя класса окна.

Итак в wc.cbSize мы помещаем размер структуры WNDCLASSEX(мы могли и прямо указать 48 байт.12 членов структуры по 4 байта (dd=4 байта)).Затем загружаем иконку:
invoke    LoadIcon,[hinstance],10 -Функция LoadIcon требует хендл приложения [hinstance]ID иконки которую мы в прошлом уроке поместили в RC-файл(ID = 10).
И заносим полученый в eax хендл иконки в члены структуры отвечающие за иконку приложения и маленькую иконку отображающуюся в заголовке окна:

mov [wc.hIcon],eax  -Вносим в wc хендл иконки
mov [wc.hIconSm],eax

Затем загружаем курсор.
invoke LoadCursor,0,IDC_ARROW -Вносим в wc хендл
курсора.

mov    [wc.hCursor],eax -Всё аналогично.Только вместо [hinstance] мы ставим 0(курсор который мы грузим не является собственостью нашей программы,а является системным курсором.),а IDC_ARROW-стандартный курсор системы(просто стрелка).

    mov    [wc.style],CS_HREDRAW   -помещаем стиль окон в пункт wc.style.
    mov    [wc.lpfnWndProc],WindowProc -Заносим Адpес пpоцедуpы окна,ответственной за окна, создаваемых из класса в wc.lpfnWndProc.
    mov    [wc.cbClsExtra],0 -Заносим количество дополнительных байтов,котоpые нужно заpезеpвиpовать (они будут следовать за самой стpуктуpой) в wc.cbClsExtra. По умолчанию, опеpационная система инициализиpует это количество в 0. Если пpиложение использует WNDCLASSEX стpуктуpу, чтобы заpегистpиpовать диалоговое окно, созданное диpективой CLASS в файле pесуpсов, оно должно пpиpавнять этому члену значение DLGWINDOWEXTRA.
    mov    [wc.cbWndExtra], -Заносим в wc.cbWndExtra ноль(такова традиция работников Мелкософта).
Помещаем в wc.hInstance хэндл модуля:
    mov    eax,[hinstance]    
    mov    [wc.hInstance],eax
Далее:
    mov    [wc.hbrBackground],COLOR_WINDOW+1 -Цвет фона Окна,которое мы получим,заносим в wc.hbrBackground.
    mov    [wc.lpszMenuName],NULL -Хэндл меню для окон, созданных из класса по умолчанию.У нас нет меню-ставим NULL.
    mov    [wc.lpszClassName],ClassName  -Имя класса окна помещаем в wc.lpszClassName.

Анализ:

cbSize Размер структуры WNDCLASSEX в байтах. Вы можете получить этот размер так:
mov [ws.cbSize],WNDCLASSEX
style Стиль окон, создаваемых из это класса.
lpfnWndProc Указатель на процедуру окна (об этом я расскажу ниже)
cbClsExtra Количество дополнительных байтов, которые нужно зарезервировать (они будут следовать за самой структурой).
cbWndExtra Количество дополнительных батов, которые нужно зарезервировать (они будут следовать за window instance).
hInstance Хэндл вашей программы. Вы можете получить это хэндл функцией GetModuleHandle.
hIcon Хэндл иконки. Получите его функцией LoadIcon.
hCursor Хэндл курсора. Получите его функцией LoadCursor.
hbrBackground Хэндл кисти для закрашивания фона, или один из стандартных, таких как COLOR_WINDOW, COLOR_BTNFACE , COLOR_BACKGROUND.
lpszMenuName Указатель на строку с нулевым символом в конце, которая определяет имя ресурса меню класса. Это также может быть ID ресурса.
lpszClassName Указатель на строку с нулевым символом в конце, которая определяет имя класса для окон.
hIconSm Хэнд маленькой иконки.
;-------------------------------------------------------
;Создание нашего окна
;-------------------------------------------------------

    invoke    CreateWindowEx,0,ClassName,AppName,\
    WS_VISIBLE+WS_OVERLAPPEDWINDOW ,128,128,\
    192,192,NULL,NULL,[hinstance],NULL -Создаём окно.Т.к это окно имеет стиль WS_VISIBLE мы не должны вызывать show window и update window
    mov    [mainhwnd],eax -заносим полученый хендл окна в переменную mainhwnd .

Прототип функции:

invoke CreateWindowEx, dwExStyle,  lpClassName,  lpWindowName,  dwStyle,x, y, nWidth, nHeight,  hWndParent, hMenu, hInstance, lpParam 


dwExStyle и dwStyle это два параметра, которые определяют стиль окна.
lpClassName это указатель на ваше зарегистрированное имя класса.
lpWindowName это имя вашего окна (оно будет в заголовке вашего окна)
x, y, nWidth, nHeight определяют позицию и размер вашего окна.
hWndParent это хэндл окна, которому принадлежит новое окно. Может быть нулевым, если нет родительского окна.
hMenu это хэндл меню окна.
hInstance это хэндл программного модуля, создающего окно.
lpParam дополнительное значение, которое вы можете использовать в своей программе.

Далее создаём цикл сообщений:

msg_loop:
    invoke    GetMessage,msg,NULL,0,0;Получаем сообщение
    or eax,eax  ;логическое или (Если 1 операнд равен 0 ,а второй 1 всё равно ответ равен 1,если оба равны 0,ответ равен 0).Можно делать итак: cmp eax,0
    jz    EXIT ;eax == 0?Выходим!
    invoke    TranslateMessage,msg
    invoke    DispatchMessage,msg
    jmp    msg_loop ;Прыжок на msg_loop(новый цикл)

   EXIT:
    invoke    ExitProcess,[msg.wParam] -Завершаем процесс возвращая windows результат работы WindowProc.


Windows может связываться с вашей программой и другими онами, используя сообщения. Оконная процедура (см. ниже в этом уроке) вызывается всякий раз, когда для определенного окна ожидается сообщение. Каждое окно имеет цикл сообщений. Это бесконечный цикл, который проверяет есть ли сообщение для вашего окна, и если есть, то передает сообщение функции dispatchmessage. Эта функция вызовет вашу оконную процедуру.

Вот, как может выглядеть цикл сообщений. 

msg_loop:
invoke    GetMessage,msg,NULL,0,0 -Получаем сообщение
or eax,eax          -проверка на 0(можно и так:cmp eax,0)
jz    EXIT          -Если равно 0,переходим на EXIT.

Содержимое цикла.

jmp    msg_loop -принудительно переходим на msg_loop.

EXIT:
invoke    ExitProcess,[msg.wParam] -Завершаем процесс возвращая windows результат работы WindowProc.

Цикл поторяет всё до тех пор , пока eax не стпнет равным 0. Функция GetMessage возвращает 0, если получает сообщение WM_QUIT, которое должно закрыть окно, так что программа должна выйти из цикла сообщений всякий раз, когда GetMessage возвращает 0. Если нет, то сообщение передается функции TranslateMessage (эта функция транслирует нажатия клавиш в сообщения) и затем сообщение посылается окной процедуре, с помощью функции DispatchMessage. Сообщение непосредственно в цикле сообщений состоит из структуры MSG.Вы можете использовать этот цикл сообщений во всех своих программах.

proc WindowProc, hwnd,wmsg,wparam,lparam -Процедура окна WindowProc с параметрами:hwnd-хендл окна,uMsg - сообщение.Заметьте, что uMsg - это не MSG стpуктуpа. Это всего лишь число. Windows опpеделяет кучу сообщений, большинством из котоpых ваша пpогpамма интеpесоваться не будет. Windows будет слать подходящее сообщение, в случае если пpоизойдет что-то относящееся к нашему окну. Пpоцедуpа окна получает сообщение и pеагиpует на это соответствующе. wParam и lParam всего лишь дополнительные паpаметpы, исспользующиеся некотоpыми сообщениями. Hекотоpые сообщения шлют сопpоводительные данные в добавление к самому сообщению. Эти данные пеpедаются пpоцедуpе окна в пеpеменных wParam и lParam.
     push    ebx esi edi -Сохраняем регистры(в принципе можно это и не делать,но лучше играть по правилам).
    .if [wmsg],e,WM_DESTROY  -проверяем эквивалентно(равно) ли сообщение wmsg сообшщению WM_DESTROY.
     invoke  PostQuitMessage,0 -Если да - вызываем PostQuitMessage котоpая пошлет сообщение WM_QUIT, что вынудит GetMessage веpнуть нулевое значение в eax, что в свою очеpедь, повлечет выход из цикла обpаботки сообщений, а значит из пpогpаммы.
     xor     eax,eax     -обнуляем eax.
     pop     edi esi ebx -востанавливаем регистры.
     return -Возврат из функции в цикл сообшений.
    .else  -Если  это не то сообщение, котоpое вас интеpесует, вы ДОЛЖHЫ вызвать DefWindowProc, пеpедав ей все паpаметpы, котоpые вы до этого получили. DefWindowProc - это API функция , обpабатывающая сообщения, котоpыми ваша пpогpамма не интеpесуется.
     invoke DefWindowProc,[hwnd],[wmsg],[wparam],[lparam]
     pop     edi esi ebx -востанавливаем регистры.
     return -Возврат из функции в цикл сообшений.
    .endif
endp -Конец процедуры.

Я знаю вы подумали:Ужас!Так много старались,устали и всё это за примитивное окно...
Но насамом деле эта программа - шаблон.Вам надо добавить к ней немного кода и у неё появиться меню.В окне отобразим большую надпись,изображение...Главное уметь создавать окно(надеюсь у вас это получиться).Если вы не поняли зачем я использовал какую либо инструкцию - прочтите о ней в FasmBook от Mario79(которую я вам советовал скачать).

Удачи!

Страница1 из 2-хНаверхСтраница2 из 2-х
Сайт управляется системой uCoz