Файл определения модуля.
Первая строка необходима для 16-битных приложений, для 32-битных не нужна.
EXETYPE WINDOWS
Директива CODE имеет следующий синтаксис:
CODE
[FIXED | MOVEABLE]
[DISCARDABLE | NONDISCARDABLE]
[PRELOAD | LOADONCALL]
Опции означают: сегмент фиксированной длины, сегмент может быть перемещён в памяти, может быть выгружен, не может быть выгружен, загружается в память при запуске приложения, загружается при обращении к некоторому его элементу.
Директива DATA имеет следующий синтаксис:
DATA
[NONE | SINGLE | MULTIPLE]
[READONLY | READWRITE]
[PRELOAD | LOADONCALL]
[SHARED | NONSHARED]
Опции означают: сегмент данных отсутствует, 1 сегмент, разделяемый всеми процессами, несколько сегментов данных, данные в сегменте можно читать, но не изменять, можно читать и изменять, сегмент заранее автоматически загружается в память, загружается при обращении к нему, одна копия сегмента разделяется всеми процессами, отдельная копия сегмента загружается для каждого процесса.
Директивы HEAPSIZE и STACKSIZE устанавливают размер локальной динамической памяти и стека программы.
Директива STUB вставляет в файл .EXE кода для WINDOWS программу DOS.
Базовые и производные типы, используемые при создании WINDOWS – программ.
- байт — восемь последовательно расположенных битов, пронумерованных от 0 до 7, при этом бит 0 является самым младшим значащим битом;
- слово — последовательность из двух байт, имеющих последовательные адреса. Размер слова — 16 бит; биты в слове нумеруются от 0 до 15. Байт, содержащий нулевой бит, называется младшим байтом, а байт, содержащий 15-й бит - старшим байтом. Микропроцессоры Intel имеют важную особенность — младший байт всегда хранится по меньшему адресу. Адресом слова считается адрес его младшего байта. Адрес старшего байта может быть использован для доступа к старшей половине слова.
- двойное слово — последовательность из четырех байт (32 бита), расположенных по последовательным адресам. Нумерация этих бит производится от 0 до 31. Слово, содержащее нулевой бит, называется младшим словом, а слово, содержащее 31-й бит, - старшим словом. Младшее слово хранится по меньшему адресу. Адресом двойного слова считается адрес его младшего слова. Адрес старшего слова может быть использован для доступа к старшей половине двойного слова.
- учетверенное слово — последовательность из восьми байт (64 бита), расположенных по последовательным адресам. Нумерация бит производится от 0 до 63. Двойное слово, содержащее нулевой бит, называется младшим двойным словом, а двойное слово, содержащее 63-й бит, — старшим двойным словом. Младшее двойное слово хранится по меньшему адресу. Адресом учетверенного слова считается адрес его младшего двойного слова. Адрес старшего двойного слова может быть использован для доступа к старшей половине учетверенного слова.
Кроме трактовки типов данных с точки зрения их разрядности, микропроцессор на уровне команд поддерживает логическую интерпретацию этих типов.
- Целый тип со знаком — двоичное значение со знаком, размером 8, 16 или 32 бита. Знак в этом двоичном числе содержится в 7, 15 или 31-м бите соответственно. Ноль в этих битах в операндах соответствует положительному числу, а единица — отрицательному. Отрицательные числа представляются в дополнительном коде. Числовые диапазоны для этого типа данных следующие:
- 8-разрядное целое — от –128 до +127;
- 16-разрядное целое — от –32 768 до +32 767;
- 32-разрядное целое — от –231 до +231–1.
- Целый тип без знака — двоичное значение без знака, размером 8, 16 или 32 бита. Числовой диапазон для этого типа следующий:
- байт — от 0 до 255;
- слово — от 0 до 65 535;
- двойное слово — от 0 до 232–1.
- Указатель на память двух типов:
- ближнего типа — 32-разрядный логический адрес, представляющий собой относительное смещение в байтах от начала сегмента. Эти указатели могут также использоваться в сплошной (плоской) модели памяти, где сегментные составляющие одинаковы;
- дальнего типа — 48-разрядный логический адрес, состоящий из двух частей: 16-разрядной сегментной части — селектора, и 32-разрядного смещения.
- Цепочка — представляющая собой некоторый непрерывный набор байтов, слов или двойных слов максимальной длины до 4 Гбайт.
- Битовое поле представляет собой непрерывную последовательность бит, в которой каждый бит является независимым и может рассматриваться как отдельная переменная. Битовое поле может начинаться с любого бита любого байта и содержать до 32 бит.
- Неупакованный двоично-десятичный тип — байтовое представление десятичной цифры от 0 до 9. Неупакованные десятичные числа хранятся как байтовые значения без знака по одной цифре в каждом байте. Значение цифры определяется младшим полубайтом.
- Упакованный двоично-десятичный тип представляет собой упакованное представление двух десятичных цифр от 0 до 9 в одном байте. Каждая цифра хранится в своем полубайте. Цифра в старшем полубайте (биты 4–7) является старшей
Тип данных | Определение типа в файле windows.h | Описание |
BOOL | int | Булевый (двоичный) |
BYTE | unsigned char | Байт |
WORD | unsigned short | Беззнаковое целое размером 16 бит |
DWORD | unsigned long | Беззнаковое целое размером 32 бит |
UINT | unsigned int | Беззнаковое целое естественного для данной системы размера |
На основе приведенного выше набора базовых типов в файле windows.h определены производные типы, которые являются указателями:
Тип данных | Определение типа в файле windows.h | Описание |
PSTR | char NEAR * | Ближний указатель на символ типа char |
NPSTR | char NEAR * | Ближний указатель на символ типа char |
LPSTR | char FAR * | Дальний указатель на символ типа char |
LPCSTR | const char FAR * | Константный дальний указатель на символ типа char |
PBYTE | BYTE NEAR * | Ближний указатель на байт |
LPBYTE | BYTE FAR * | Дальний указатель на байт |
PINT | int NEAR * | Ближний указатель на int |
LPINT | int FAR * | Дальний указатель на int |
PWORD | WORD NEAR * | Ближний указатель на беззнаковое целое размером 16 бит |
LPWORD | WORD FAR * | Дальний указатель на беззнаковое целое размером 16 бит |
PLONG | long NEAR * | Ближний указатель на знаковое целое размером 32 бит |
LPLONG | long FAR * | Дальний указатель на знаковое целое размером 32 бит |
PDWORD | DWORD NEAR * | Ближний указатель на беззнаковое целое размером 32 бит |
LPDWORD | DWORD FAR * | Дальний указатель на беззнаковое целое размером 32 бит |
LPVOID | void FAR * | Дальний указатель, для которого не определен тип данных |
Сообщения.
Большинство сообщений создают драйверы устройств ввода/вывода, таких, как клавиатура, мышь или таймер. Драйверы создают сообщения при поступлении аппаратных прерываний. Например, когда вы нажимаете и затем отпускаете клавишу, драйвер обрабатывает прерывания от клавиатуры и создает несколько сообщений. Аналогично сообщения создаются при перемещении мыши или в том случае, когда вы нажимаете кнопки на корпусе мыши. Можно сказать, что драйверы устройств ввода/вывода транслируют аппаратные прерывания в сообщения. В операционной системе Windows обычные приложения никогда не обращаются напрямую к аппаратуре и не работают с системными областями памяти, такими, как таблицы дескрипторов прерываний или видеопамять. Все это делают драйверы и виртуальные драйверы. Поэтому ограничения, накладываемые на обычные приложения Windows, никак не сказываются на функциональных возможностях самого приложения.
Прежде всего, сообщения попадают в системную очередь сообщений Windows. Системная очередь сообщений одна. Далее из нее сообщения распределяются в очереди сообщений приложений. Для каждого приложения создается своя очередь сообщений.
Очередь сообщения приложений может пополняться не только из системной очереди. Любое приложение может послать сообщение любому другому сообщению, в том числе и само себе.
Основная работа, которую должно выполнять приложение, заключается в обслуживании собственной очереди сообщений. Обычно приложение в цикле опрашивает свою очередь сообщений. Обнаружив сообщение, приложение с помощью специальной функции из программного интерфейса Windows распределяет его нужной функции окна, которая и выполняет обработку сообщения.
Сообщение, в основном, состоит из полей wParam и lParam. В сообщении, формируемом при нажатии любой кнопки мыши, младшее слово lParam содержит X – координату курсора, а старшее – Y – координату. Семь младших бит поля wParam содержит состояние кнопок мыши и клавиш Shift и Ctrl. Если кнопка или клавиша нажата, то соответствующий бит находится в состоянии 1.
Создание окна в Windows
Структура программы в Windows:
GetMessage |
SendMessage |
Асинхронное событие |
TranslateMessage |
DispatchMessage |
PostMessage |
Синхронное событие |
WM_QUIT |
Цикл сообщений |
Выход |
Case WM_COMMAND Case WM_DESTROY default |
MainWindowProc |
WinMain |
Начало |
Функция WinMain в цикле обработки сообщений с помощью функции GetMessage выбирает сообщения из очереди сообщений приложения и распределяет их функциям окон, вызывая функцию DispatchMessage.
Функция GetMessage предназначена для выборки сообщения из очереди приложения. Сообщение выбирается из очереди и записывается в область данных, принадлежащую приложению.
Функция DispatchMessage предназначена для распределения выбранного из очереди сообщения нужной функции окна. Так как приложение обычно создает много окон и эти окна используют различные функции окна, необходимо распределить сообщение именно тому окну, для которого оно предназначено. Поэтому приложение должно распределить сообщение после его выборки из очереди приложения, в котором находятся сообщения для всех окон. Windows оказывает приложению существенную помощь в решении этой задачи - для распределения приложению достаточно вызвать функцию DispatchMessage.
Окна
#include <windows.h>
#include <stdlib.h>
const char szClassName[] = "WinLab_01";
const char szWindowName[] = "Term II. Windows Lab 01.";
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam);
#pragma argsused
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
HWND hWnd;
// Описание класса окна
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = 5;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szClassName;
if (!RegisterClass(&wndclass)) // Регистрируем класс окна
exit(FALSE);
// Создаем окно
hWnd=CreateWindow(szClassName,szWindowName, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0,CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd) exit(FALSE);
// Показываем окно
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// Цикл сообщений
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{TranslateMessage(&msg);
DispatchMessage(&msg);}
return msg.wParam;}
/* Обработчик сообщений */
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{switch (iMessage)
{case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, iMessage, wParam, lParam); }
return 0;}
Сообщение с кодом WM_CREATE передается функции окна в момент создания окна.
В процессе работы приложения функция окна может получать сообщения с различными кодами как через очередь сообщений приложения, так и непосредственно, в обход очереди сообщений. Обработчики этих сообщений, определенные в функции окна, являются методами для работы с окном как с объектом.
При разрушении структуры данных окна (при уничтожении окна) функция окна получает сообщение с кодом WM_DESTROY. Обработчик этого сообщения действует как деструктор.
Модификатор Pascal требует компилировать функцию в стиле языка Паскаля – с очисткой стека от параметров функции. Если указать другой модификатор (cdecl, WINAPI) то вызов функции будет компилироваться в стиле С, стек будет очищен вызывающей программой.
Параметр hInstance идентифицирует данное приложение. Он содержит адрес памяти, выделенной для работы. Этот адрес является виртуальным и по умолчанию настроен таким образом, что равен 0x40000.
Второй параметр hPrevInstance определяет, по какому адресу будет загружено приложение, запущенное повторно. Это позволяло дублировать при повторных запусках не весь код. В настоящее время не используется и сохраняется для обеспечения совместимости с предыдущими версиями.
Поле lpszCmdLine позволяет передавать запускаемому приложению командную строку. Если на рабочем столе для запуска создан ярлык, то щелчок правой кнопкой вызывает появление окна свойств. Если программа запускается из среды разработки, то командная строка может быть задана в свойствах проекта Project - Property-Debugging - CommandArguments. В командной строке (в отличие от argc и argv) отсутствует первый параметр, определяющий путь к исполняемому файлу. Получит командную строку с первым параметром можно с помощью функции GetCommandLine(). Порядок записи операндов в стек не зависит от модификатора. Первый параметр передаётся последним и будет в вершине стека.
В области стека функции WinMain созданы две переменные с именами msg и hwnd:
MSG msg; // структура для работы с сообщениями
HWND hwnd; // идентификатор главного окна приложения
Переменная msg представляет собой структуру типа MSG, описанную в файле windows.h следующим образом:
typedef struct tagMSG
{
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG;
Эта переменная предназначена для временного хранения сообщений и используется в цикле обработки сообщений.
Если регистрация класса произошла успешно, функция RegisterClass возвращает атом с ненулевым значением.
Структура WNDCLASS используется для регистрации класса окна. Эта структура определена в файле windows.h:
typedef struct tagWNDCLASS
{
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCSTR lpszMenuName;
LPCSTR lpszClassName;
} WNDCLASS;
Перед регистрацией вам необходимо заполнить все поля в этой структуре.
Поле style определяет стиль класса и задается в виде констант (описанных, как всегда, в файле windows.h), имя которых начинается с префикса CS_, например CS_HREDRAW, CS_VREDRAW. Стиль задает реакцию окна на изменение его размера, на выполнение в окне операции двойного щелчка мышью (double click), а также позволяет определить другие характеристики окна, создаваемого на базе данного класса. Например, если для стиля задать значение CS_HREDRAW | CS_VREDRAW, при изменении вертикального или горизонтального размера окна приложение должно его перерисовать, то есть нарисовать заново все или часть того, что было изображено в окне до изменения размера.
Если стиль класса не используется, то для него задается нулевое значение:
wc.style = 0;
В поле lpfnWndProc необходимо записать адрес функции окна, которая будет выполнять обработку сообщений, поступающих во все окна, созданные на базе данного класса. Имя функции окна можно выбрать любое. В нашем случае используется имя WndProc, хотя вы можете использовать другое имя. Запись адреса функции окна должна выполняться следующим образом:
wc.lpfnWndProc = (WNDPROC) WndProc;
Поле lpfnWndProc имеет тип WNDPROC (дальний указатель на функцию), который мы рассмотрим чуть позже, при описании функции окна. Для того чтобы избежать получения от компилятора предупреждающего сообщения о несоответствии типов, вы должны использовать явное преобразование типа.
Поле cbClsExtra используется для резервирования дополнительной памяти, общей и доступной для всех окон, создаваемых на базе данного класса.
Чтобы это было понятно, отметим, что при регистрации класса окна в памяти, принадлежащей операционной системе Windows, резервируется и заполняется некоторая область (структура данных). В этой области хранится вся информация о классе, необходимая для создания окон на базе этого класса. Вы можете увеличить размер области описания класса для хранения своей собственной информации, предназначенной для всех создаваемых на базе этого класса окон. Поле cbClsExtra определяет размер дополнительной памяти в байтах.
Если приложение не создает в описании класса никаких дополнительных областей, поэтому для заполнения поля cbClsExtra используется нулевое значение:
wc.cbClsExtra = 0;
Так же как и при создании нового класса, при создании нового окна Windows резервирует в своей памяти область, описывающую окно. С помощью параметра cbWndExtra вы можете увеличить размер этой области для хранения информации, имеющей отношение к создаваемому окну. В нашем случае размер области описания окна не увеличивается, поэтому для заполнения поля cbWndExtra используется нулевое значение:
wc.cbWndExtra = 0;
Поле hInstance перед регистрацией класса окна должно содержать идентификатор приложения, создающего класс окна. В качестве этого идентификатора следует использовать значение, полученное функцией WinMain в параметре hInstance:
wc.hInstance = hInstance;
Следующее поле имеет имя hIcon и тип HICON. Это идентификатор пиктограммы, в которую превращается окно при уменьшении его размеров до предела (при минимизации окна).
Для загрузки пиктограммы в приложении вызывается функция программного интерфейса Windows с именем LoadIcon:
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
Прототип функции LoadIcon:
HICON WINAPI LoadIcon(HINSTANCE hinst, LPCSTR pszicon);
Первый параметр функции (hinst) содержит идентификатор приложения, второй (pszicon) - имя ресурса-пиктограммы.
Позже мы научим вас определять для окон собственные пиктограммы, нарисованные с помощью приложения Resource Workshop, входящего в комплект поставки Borland C++ for Windows.
В поле hCursor (имеющем тип HCURSOR) вы можете задать вид курсора мыши при его прохождении над окном. Вы знаете, что курсор мыши меняет свою форму при перемещении над различными окнами приложений Windows. При регистрации класса окна вы можете указать форму курсора, для чего и используется поле hCursor.
В нашем приложении мы задаем курсор в виде стандартной стрелки, для чего вызываем функцию LoadCursor и указываем в качестве второго параметра константу IDC_ARROW:
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
Прототип функции LoadCursor:
HCURSOR WINAPI LoadCursor(HINSTANCE hinst, LPCSTR pszCursor);
Вы можете определить для окна свой курсор, нарисовав его аналогично пиктограмме при помощи такого приложения, как Resource Workshop или Microsoft SDKPaint. Однако пока для простоты мы будем использовать стандартный курсор.
Далее нам необходимо заполнить поле hbrBackground, имеющее тип HBRUSH. Это поле позволяет определить кисть (brush), которая будет использована для закрашивания фона окна. В качестве кисти можно использовать "чистые" цвета или небольшую пиктограмму размером 8 х 8 точек.
В нашем приложении мы использовали системный цвет, который Windows использует для закрашивания фона окон:
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
Системный цвет можно изменять при помощи приложения Control Panel. Позже мы научим вас задавать для фона окна другие цвета и раскрашивать окно при помощи пиктограмм.
Поле lpszMenuName (указатель на строку типа LPCSTR) определяет меню, располагающееся в верхней части окна. Если меню не используется, при заполнении этого поля необходимо использовать значение NULL:
wc.lpszMenuName = (LPSTR)NULL;
Тип LPCSTR определяется как константный дальний указатель на строку символов:
typedef const char FAR* LPCSTR;
Очень важно поле lpszClassName. В это поле необходимо записать указатель на текстовую строку, содержащую имя регистрируемого класса окон:
wc.lpszClassName = (LPSTR)szClassName;
На этом подготовку структуры wc к регистрации класса окна можно считать законченной. Можно вызывать функцию RegisterClass.
Создание главного окна приложения
Далее приложение вызывает функцию CreateWindow для того, чтобы создать главное окно приложения:
hwnd = CreateWindow(
szClassName, // имя класса окна
szWindowTitle, // заголовок окна
WS_OVERLAPPEDWINDOW, // стиль окна
CW_USEDEFAULT, // задаем размеры и расположение
CW_USEDEFAULT, // окна, принятые по умолчанию
CW_USEDEFAULT,
CW_USEDEFAULT,
0, // идентификатор родительского окна
0, // идентификатор меню
hInstance, // идентификатор приложения
NULL); // указатель на дополнительные параметры
В случае успеха функция CreateWindow возвращает идентификатор окна (типа HWND). Если окно создать не удалось, функция возвращает нулевое значение.
Приведем прототип функции CreateWindow:
HWND CreateWindow(LPCSTR lpszClassName, LPCSTR lpszWindowName, DWORD dwStyle,int x, int y, int nWidth, int nHeight,HWND hwndParent, HMENU hmenu, HINSTANCE hinst,void FAR* lpvParam);
Многочисленные параметры функции CreateWindow дополняют описание окна, сделанное при создании класса окна.
Первый параметр функции (lpszClassName) - указатель на строку, содержащую имя класса, на базе которого создается окно. В процессе инициализации приложения мы зарегистрировали класс с именем "WindowAppClass" (переменная szClassName).
Второй параметр функции (lpszWindowName) - указатель на строку, содержащую заголовок окна (Title Bar). В нашем случае окно будет иметь заголовок "Window Application" (переменная szWindowTitle).
Третий параметр (dwStyle) - стиль создаваемого окна. Этот параметр задается как логическая комбинация отдельных битов. Константа WS_OVERLAPPEDWINDOW соответствует окну, которое может перекрывать другие окна, имеет заголовок, системное меню, кнопки для минимизации и максимизации окна, а также рамку вокруг окна, с помощью которой можно изменять размер окна. Операционная система Windows позволяет задавать различные стили для создаваемых окон. Мы их рассмотрим в дальнейшем.
Четвертый и пятый параметры функции CreateWindow для окна данного стиля определяют горизонтальную (x) и вертикальную (y) координату относительно верхнего левого угла экрана видеомонитора.
Шестой и седьмой параметры определяют ширину (nWidth) и высоту (nHeight) создаваемого окна.
Наше приложение в качестве координат окна и его размеров использует константу CW_USEDEFAULT. При этом операционная система Windows сама определяет положение и размеры создаваемого окна.
Восьмой параметр (hwndParent) определяет индекс родительского окна. Для нашего приложения в качестве значения используется нуль, так как в приложении создается только одно окно.
Девятый параметр (hmenu) - идентификатор меню или идентификатор порожденного (child) окна. В нашем случае никакого меню или порожденного окна нет, поэтому в качестве значения используется нуль.
Десятый параметр (hinst) - идентификатор приложения, которое создает окно. Необходимо использовать значение, передаваемое функции WinMain через параметр hInstance.
Одиннадцатый, последний параметр функции (lpvParam) представляет собой дальний указатель на область данных, определяемых приложением. Этот параметр передается в функцию окна вместе с сообщением WM_CREATE при создании окна. Наше приложение не пользуется этим параметром.
Отображение окна на экране
Окно создано, но на экране оно еще не появилось, в чем вы можете убедиться, запустив приложение под управлением отладчика. Поэтому, проверив, что создание окна выполнено успешно (функция CreateWindow вернула ненулевое значение), необходимо сделать окно видимым (нарисовать его на экране). Это можно сделать с помощью функции ShowWindow:
ShowWindow(hwnd, nCmdShow);
Прототип функции:
BOOL ShowWindow(HWND hwnd, int nCmdShow);
Функция отображает окно, идентификатор которого задан первым параметром (hwnd), в нормальном, максимально увеличенном или уменьшенном до пиктограммы виде, в зависимости от значения второго параметра (nCmdShow). После отображения окна в нормальном или максимально увеличенном виде внутренняя поверхность окна закрашивается кистью, определенной при регистрации класса.
Внешний вид окна, создаваемого нашим приложением, показан на рис.
Сразу после функции ShowWindow в приложении вызывается функция UpdateWindow.
UpdateWindow(hwnd);
Прототип функции:
void UpdateWindow(HWND hwnd);
Функция UpdateWindow вызывает функцию окна, заданного идентификатором, передаваемым в качестве параметра hwnd, и передает ей сообщение WM_PAINT. Получив это сообщение, функция окна должна перерисовать все окно или его часть. Наше приложение не обрабатывает это сообщение, передавая его функции DefWindowProc.
Цикл обработки сообщений
После отображения окна функция WinMain запускает цикл обработки сообщений:
while(GetMessage(&msg, 0, 0, 0))
{
DispatchMessage(&msg);}
Функция GetMessage предназначена для выборки сообщений из очереди приложения и имеет следующий прототип:
BOOL GetMessage(LPMSG lpmsg, HWND hwnd,WORD uMsgFilterMin, WORD uMsgFilterMax);
Первый параметр функции (lpmsg) является дальним указателем на структуру типа MSG, в которую будет записано выбранное из очереди сообщение. Тип LPMSG определен в файле windows.h следующим образом:
typedef MSG FAR* LPMSG;
Второй параметр (hwnd) является идентификатором окна, для которого необходимо выбрать сообщение из очереди приложения.
Очередь приложения содержит сообщения, предназначенные для всех окон, созданных приложением. Если в качестве второго параметра функции GetMessage указать нуль, будет выполняться выборка всех сообщений, предназначенных для всех окон приложения.
Третий (uMsgFilterMin) и четвертый (uMsgFilterMax) параметры функции GetMessage позволяют определить диапазон сообщений, выбираемых из очереди приложения, задавая соответственно минимальное и максимальное значение кодов выбираемых сообщений. Если для этих параметров указать нулевые значения (как это сделано в нашем приложении), из очереди приложения будут выбираться все сообщения.
Как работает функция GetMessage?
Эта функция может выбирать сообщения только из очереди того приложения, которое ее вызывает. Если очередь сообщений приложения пуста или содержит только сообщения с низким приоритетом, функция GetMessage передает управление другим работающим приложениям, обеспечивая невытесняющую мультизадачность. Таким образом, проверяя очередь сообщений, приложение может передать управление другим приложениям. Эти приложения, в свою очередь, тоже вызывают функцию GetMessage. Таким образом, приложения распределяют между собой процессорное время.
Выбранное функцией GetMessage сообщение удаляется из очереди сообщений приложения и записывается в структуру, адрес которой задан первым параметром функции.
Если из очереди выбирается сообщение с кодом WM_QUIT, функция GetMessage возвращает значение FALSE. В этом случае приложение должно завершить цикл обработки сообщений. При выборке из очереди любых других сообщений функция GetMessage возвращает значение TRUE.
После выборки сообщения из очереди в цикле обработки сообщений его необходимо распределить функции окна, для которой это сообщение предназначено. Для этого должна быть использована функция программного интерфейса Windows с именем DispatchMessage. Эта функция имеет следующий прототип:
DWORD DispatchMessage(LPMSG lpmsg);
Единственный параметр функции (lpmsg) является указателем на структуру, содержащую сообщение. Функция DispatchMessage возвращает значение, полученное при возврате из функции окна. Обычно это значение игнорируется приложением.
Даже если ваше приложение содержит только одно окно и одну функцию окна, вы не должны вызывать функцию окна самостоятельно. Функция окна имеет нестандартный пролог и эпилог, поэтому ее прямой вызов может привести к аварийному завершению приложения. Единственный правильный способ вызова функции окна в цикле обработки сообщений - косвенный вызов при помощи функции DispatchMessage.
С помощью специальных функций, таких, как SendMessage или CallWindowProc, вы все же можете при необходимости вызвать функцию окна. Однако в цикле обработки сообщений следует использовать именно функцию DispatchMessage, так как она для каждого сообщения вызывает именно ту функцию окна, которой это сообщение предназначено.
Завершение работы приложения
Приложение обычно завершает свою работу, когда вы нажимаете комбинацию клавиш <Alt+F4> или выбираете строку "Close" в системном меню главного окна приложения. При этом в его функцию окна попадает сообщение WM_DESTROY. В ответ на это сообщение функция окна помещает в очередь сообщение WM_QUIT, вызывая для этого функцию PostQuitMessage. Как вы уже знаете, выборка этого сообщения приводит к завершению цикла обработки сообщений и, следовательно, к завершению работы приложения.
Если операционная система Windows завершает свою работу, функциям окна каждого работающего приложения передается сообщение WM_QUERYENDSESSION. Обрабатывая это сообщение соответствующим образом, приложение может завершить свою работу, предварительно сохранив все необходимые данные.
Стиль класса окна
Стиль класса окна определяется при регистрации класса окна. Во всех предыдущих примерах приложений мы не задавали стиль окна, определяя содержимое соответствующего поля в структуре WNDCLASS следующим образом:
wc.style = 0;
Стиль класса окна задается в виде отдельных битов, для которых в файле windows.h определены символические константы с префиксом CS_:
Стиль | Описание |
CS_BYTEALIGNCLIENT | Внутренняя область окна (client area) должна быть выравнена по границе байта видеопамяти. Иногда используется для ускорения процесса вывода изображения |
CS_BYTEALIGNWINDOW | Все окно (не только внутренняя область окна) должно быть выравнено по границе байта видеопамяти |
CS_CLASSDC | Необходимо создать единый контекст отображения, который будет использоваться всеми окнами, создаваемыми на базе данного класса |
CS_DBLCLKS | Функция окна будет получать сообщения при двойном щелчке клавишей мыши (double click) |
CS_GLOBALCLASS | Данный класс является глобальным и доступным другим приложениям. Другие приложения могут создавать окна на базе этого класса |
CS_HREDRAW | Внутренняя область окна должна быть перерисована при изменении ширины окна |
CS_NOCLOSE | В системном меню окна необходимо запретить выбор функции закрытия окна (строка Close будет отображаться серым цветом, и ее нельзя выбрать) |
CS_OWNDC | Для каждого окна, определяемого на базе данного класса, будет создаваться отдельный контекст отображения |
CS_PARENTDC | Окно будет пользоваться родительским контекстом отображения, а не своим собственным. Родительский контекст - это контекст окна, создавшего другое окно (см. дальше) |
CS_SAVEBITS | Для данного окна Windows должна сохранять изображение в виде битового образа (bitmap). Если такое окно будет перекрыто другим окном, то после уничтожения перекрывшего окна изображение первого окна будет восстановлено Windows на основании сохраненного ранее образа |
CS_VREDRAW | Внутренняя область окна должна быть перерисована при изменении высоты окна |
Чаще всего используются стили CS_HREDRAW и CS_VREDRAW:
wc.style = CS_HREDRAW | CS_VREDRAW;
Если для класса заданы стили CS_HREDRAW и CS_VREDRAW, при изменении размеров окна функция окна может получить сообщение WM_PAINT. В этом случае функция окна должна перерисовать часть окна или все окно.
Стиль CS_DBLCLKS используется при необходимости отслеживать двойные щелчки мышью. При этом в функцию окна посылаются сообщения WM_LBUTTONDBLCLK и WM_RBUTTONDBLCLK. Если этот стиль не будет задан, как бы быстро вы ни щелкали мышью, функция окна получит только идущие парами сообщения о том, что вы нажимаете и отпускаете левую или правую клавишу мыши.
Стиль окна
Определенный в классе окна стиль класса окна используется при создании на базе этого класса всех окон. Для дальнейшего уточнения внешнего вида и поведения окна используется другая характеристика - стиль окна. Стиль окна указывается при создании окна функцией CreateWindow. В наших примерах основное окно приложения не имело стиля класса окна, но для него был определен стиль окна WS_OVERLAPPEDWINDOW:
Для определения стиля окна используются символические константы с префиксом WS_, определенные в файле windows.h. С помощью этих констант можно определить примерно два десятка стилей окна, однако чаще всего используются несколько основных стилей.
Мы рассмотрим три основных стиля окон - перекрывающиеся окна (overlapped window), временные окна (pop-up window) и дочерние окна (child window).
Дата добавления: 2016-07-22; просмотров: 1887;