Ассемблерное программирование в Windows

15.09.2004
Новиков Максим Глебович.

Глава 5. Описание исходника

В общем-то, приведенный исходный текст уже снабжен подробнейшими комментариями, поэтому рассмотрим здесь лишь основной смысл всех наших действий.

Весь исходник для ясности мы разбили на 5 файлов. Первый файл «bloknot.asm» — это основной файл программы, в остальных файлах содержаться вспомогательные сведения:

«bloknot.rc» — файл ресурсов. Здесь мы опишем структуру меню нашего приложения, и каждому пункту присвоим код сообщения, который он будет генерировать при его выборе. Кроме структуры меню в файле ресурсов может содержаться много другой информации, и для упрощения создания таких файлов в дальнейшем мы будем пользоваться специальной программой — редактором ресурсов.

«def32.inc» — файл, содержащий присвоения имен стандартным константам, наиболее часто использующимся в приложениях Windows, а также описания трёх стандартных структур, использующихся для описания класса окна и передачи сообщений приложению.

«kernel32.inc» — файл, содержащий объявления внешних функций и упрощающий их названия. Функции, отвечающие за управление программой.

«user32.inc» — файл, содержащий объявления внешних функций и упрощающий их названия. Функции, отвечающие за оконный интерфейс.

Файл ресурсов мы больше не трогаем — им будет пользоваться компилятор при сборке программы. Названия же оставшихся трех файлов прописываем в начало нашего основного файла bloknot.asm:

include def32.inc    ;Включить в исходник файл с определениями  
                     ;разных констант и структур.
include kernel32.inc ;Включить файл с объявлениями внешних функций 
                     ;из библиотеки kernel32.dll.
include user32.inc   ;Включить файл с объявлениями внешних функций 
                     ;из библиотеки user32.dll, в которую входят все
                     ;основные функции, отвечающие за оконный интерфейс.

Это означает, что ассемблер при сборке программы вместо этих строчек подставит текст из этих файлов.

Ниже следуют стандартные строки указания системы команд процессора и модели памяти — используем команды 386 процессора и плоскую модель памяти. Компьютер предоставит для программы с такой моделью память в виде сплошного пространства, и мы будем, в общем-то, не против…

Теперь организуем сегменты программы — для неинициализированных, инициализированных данных и для кода:

Директивой .data открываем сегмент инициализированных данных. В нём указываем несколько строковых констант, а также создаем структуру, помогающую описать класс основного окна. В структуру записываем известные параметры окна, а вместо неизвестных пока параметров ставим знаки вопроса.

Директивой .data ? открываем сегмент неинициализированных данных (т.е. переменных). В нем создадим структуру, в которую будем считывать сообщения, приходящие в программу.

Далее директивой .code открываем сегмент кода. Здесь, собственно, и начинается программа.

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

В процессе дозаполнения структуры, вызовами соответствующих функций мы создаём иконку приложения и курсор мыши, и подключаем их к окну, передавая в структуру их идентификаторы.

После создания окна управление должно передаться в цикл обработки сообщений, приходящих в программу. Организуем цикл обработки сообщений, работающий следующим образом: если пришло сообщение 0, значит выйдем из программы, иначе вызовем оконную процедуру для дальнейшей обработки сообщения. Замкнем цикл. Основная процедура завершена.

Теперь напишем оконную процедуру, в которой будут обрабатываться все остальные сообщения (кроме уже обработанного сообщения о выходе из программы). Приходящее сообщение сначала проверяем на соответствие сообщению о закрытии окна. Если оно соответствует, то генерим сообщение о выходе из программы, и отправляем его в очередь сообщений. В следующем цикле обработки сообщений мы получим его и, не входя в оконную процедуру, выйдем из программы. Если сообщение не соответствует сообщению о выходе из программы, двигаемся дальше.

Теперь нам надо перехватывать сообщения только от меню, поэтому если сообщение не от меню (не WM_COMMAND), то передадим его на обработку стандартной оконной процедуре, по умолчанию созданной операционной системой для нашего приложения. Иначе это сообщение от нашего меню, и мы обработаем его ниже.

Идентификаторами пунктов меню у нас служат следующие по порядку цифры от 0 до 3, поэтому мы сможем организовать переключатель на соответствующие процедуры обработки пунктов меню довольно компактным образом. Запишем смещения к процедурам обработки в виде четырех следующих друг за другом значений:

menu_handlers dd offset menu_about, offset menu_open
              dd offset menu_save, offset menu_exit

а чуть выше организуем безусловный переход на адрес, составленный из идентификатора пункта (0, 1, 2 или 3), размерности смещений к процедурам (4 байта) и смещения к списку смещений:

jmp dword ptr menu_handlers[eax*4]

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

Подпрограммы организовывают вывод на экран окна с текстом, соответствующим выбранному пункту меню. В случае выбора пункта «Выход» отправляем сообщение о закрытии окна и возвращаемся в цикл нашей программы.

Мы написали шаблонное приложение, которое можем использовать при создании любых других наших проектов.

В программе мы использовали ряд API-функций. Подробное их описание на английском языке можно найти в файле win32.hlp, входящем пакет среды программирования любого языка высокого уровня. Поищите этот файл у себя в папке:

«C:\Program Files\Common Files\Borland Shared\MSHelp».

Русифицированную справку по большенству API функций вы можете скачать у меня (338 кб.)

[Вернуться в начало]
Глава 4
Глава 6–7 [Оставить отзыв в гостевой]
Hosted by uCoz