Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скляров И. Изучаем Assembler за 7 дней (2010).pdf
Скачиваний:
1548
Добавлен:
23.02.2015
Размер:
2.11 Mб
Скачать

http://www.sklyaroff.ru

 

158

result dt

 

?

; сюда будет помещен результат

stdout dd

 

?

; хендл для вывода

cWritten

dd

?

; хендл для ввода

buf

db

BSIZE dup (?)

.code

 

 

 

start:

 

 

 

 

main

proc

 

 

invoke GetStdHandle,STD_OUTPUT_HANDLE

mov

stdout,eax

fld

num1

; загружаем 1-й операнд в ST

fld

num2

; 2-й операнд в ST, 1-й операнд в ST(1)

fadd

 

; складываем: сумма помещается в ST

fstp

result

; скопировать из ST в result

invoke

FpuFLtoA,ADDR result,5,ADDR buf,SRC1_REAL or SRC2_DIMM

invoke

WriteConsoleA,stdout,ADDR buf,BSIZE,ADDR cWritten,NULL

invoke

ExitProcess,0

main

endp

 

 

end

start

 

 

7.4. Графическое приложение

В предыдущем разделе мы увидели, как просто создаются консольные приложения на ассемблере под Windows. Однако основными приложениями в Windows являются графические оконные приложения. Мы уже рассматривали создание простого окна сообщения с помощью единственной API-функции MessageBox. Однако построение стандартных окон приложений Windows, таких как на рис. 7.2, намного сложнее и одной API-функцией уже не обойтись.

Рис. 7.2. Простейшее оконное графическое приложение

Прежде чем перейти к программированию стандартного окна, необходимо понять принципы работы графических приложений в Windows.

http://www.sklyaroff.ru

159

Функционирование ОС Windows основано на сообщениях. Сообщение — это небольшой пакет данных, который генерируется в результате определенного произошедшего события в системе. Например, после нажатия пользователем клавиши на клавиатуре, щелчка или перемещения указателя мыши, изменения размера окна, выбора пункта меню, перемещении бегунка прокрутки и т. д. Сообщения могут генерироваться системным таймером и самой Windows, например, в случае завершения работы системы Windows посылает каждому открытому окну сообщение о необходимости проверить сохранность данных и закрыть окна. Существуют тысячи различных видов сообщений, но все они представлены следующей структурой (определена в winuser.h):

typedef struct tagMSG {

// msg

HWND hwnd;

 

UINT message;

 

WPARAM wParam;

 

LPARAM lParam;

 

DWORD time;

 

POINT pt;

 

} MSG;

 

Параметры:

hwnd — дескриптор окна, которому адресуется сообщение;

message — тип Windows-сообщения (например WM_RBUTTONDOWN –

нажатие правой кнопки мыши). Имена всех типов сообщений начинаются с приставки WM_;

wParam — параметр сообщения, содержащий дополнительные сведения о сообщении, например координаты указателя мыши;

lParam — параметр сообщения, содержащий дополнительные сведения о сообщении;

time — время постановки сообщения в очередь;

pt — координаты мыши в момент time.

На ассемблере эта структура с помощью неизученной пока нами директивы STRUC будет выглядеть следующим образом:

MSG STRUCT

 

 

hwnd

DWORD

?

message

DWORD

?

wParam

DWORD

?

lParam

DWORD

?

time

DWORD

?

pt

DWORD

?

MSG ENDS

 

 

В таком виде эта структура определена в файле WINDOWS.INC. Чтобы использовать поля этой структуры в программе нужно с помощью директивы INCLUDE подключить файл WINDOWS.INC и в сегменте данных сделать следующее определение:

msg MSG <?>

Знак вопроса означает, что все поля структуры будут инициализированы неизвестным значением, но можно, например, инициализировать их нулем:

msg MSG <0>

Доступ к отдельным полям осуществляется с помощью точки: mov msg.hwnd, EAX ; запись значения из EAX в поле hwnd mov msg.lParam, EAX ; запись значения из EAX в поле lParam

http://www.sklyaroff.ru

160

Всего существует четыре основных источника, от которых приложение может получать сообщения: пользователь, ОС Windows, само приложение (от самого себя), другие приложения.

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

Существует два типа сообщений: синхронные и асинхронные. Очередь синхронных сообщений формируется по принципу FIFO (first in, first out — первым прибыл, первым обслужен). Асинхронные сообщения Windows всегда вставляет сразу в голову очереди. Например, сообщения о перерисовке окна, сообщения таймера и сообщения о завершении программы являются асинхронными. Они имеют наивысший приоритет и всегда передаются раньше всех других сообщений.

Это справедливо как для системной очереди сообщений, так и для локальных очередей приложений, т. к. локальные очереди формируются от системной очереди.

Таким образом, полноценное графическое приложение будет состоять из следующих основных частей:

регистрация класса окон;

создание окна;

цикл обработки очереди сообщений;

процедура главного окна.

Рассмотрим каждую часть графического приложения, а полный исходный код показан в листинге 7.4.

7.4.1. Регистрация класса окон

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

Класс регистрируется с помощью API-функции RegisterClass, которая имеет только один аргумент – указатель на структуру типа WNDCLASS. Структура WNDCLASS хранит характеристики создаваемого класса, поэтому перед регистрацией необходимо заполнить поля этой структуры.

typedef struct { UINT style;

WNDPROC lpfnWndProc; int cbClsExtra;

int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor;

HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName;

} WNDCLASS, *PWNDCLASS;

Параметры:

style — определяет свойства окна. Все идентификаторы свойств окна начинаются с приставки CS_ (ищите их полный перечень в MSDN). Можно задать комбинацию свойств;

lpfnWndProc — указатель на оконную процедуру, которая будет обрабатывать сообщения, получаемые окном;

http://www.sklyaroff.ru

161

cbClsExtra — количество байт, резервируемых в памяти после создания структуры класса окна. Может быть равным NULL;

cbWndExtra — количество байт, резервируемых в памяти после создания экземпляра окна. Может быть равным NULL;

hInstance — дескриптор экземпляра приложения, регистрирующего класс окна;

hIcon — дескриптор иконки, которая будет символом окна данного класса. Все идентификаторы предопределенных иконок начинаются с приставки IDI_. Этот параметр может быть равным NULL;

hCursor — дескриптор указателя мыши, используемого в окне приложения. Все идентификаторы предопределенных курсоров начинаются с приставки IDC_ (вероятно "IDentificator of Cursor"). Этот параметр может быть равным NULL;

hbrBackground — дескриптор кисти (brush), которой будет закрашен фон окна;

lpszMenuName — указатель на строку, завершающуюся нулевым символом и содержащую имя меню для данной программы. Если программа не работает с меню, то этот параметр может быть NULL;

lpszClassName — указатель на строку, завершающуюся нулевым символом и содержащую имя создаваемого класса окна.

Существует расширенный вариант структуры WNDCLASS, получивший название

WNDCLASSEX: typedef struct {

UINT cbSize; UINT style;

WNDPROC lpfnWndProc; int cbClsExtra;

int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor;

HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName; HICON hIconSm;

} WNDCLASSEX, *PWNDCLASSEX;

От WNDCLASS он отличается наличием двух дополнительных полей:

cbSize — задает размер всей структуры;

hIconSm — содержит дескриптор малого значка.

В файле WINDOWS.INC структура WNDCLASSEX определена следующим образом:

WNDCLASSEX STRUCT

 

 

cbSize

DWORD

?

style

DWORD

?

lpfnWndProc

DWORD

?

cbClsExtra

DWORD

?

cbWndExtra

DWORD

?

hInstance

DWORD

?

hIcon

DWORD

?

hCursor

DWORD

?

hbrBackground

DWORD

?

lpszMenuName

DWORD

?

lpszClassName

DWORD

?

hIconSm

DWORD

?

WNDCLASSEX ENDS