| Для поиска введите икомое слово в
текстовое поле и нажмите 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],0 ;
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],0 -Заносим в 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(которую я вам советовал скачать).
Удачи!
|
|