5. Основные элементы программ с оконным пользовательским интерфейсом. Минимальная программа для ос Windows с окном на экране. Создание и отображение окна.
Каждое приложение представлено на экране дисплея своим окном, которое выглядит как прямоугольная рабочая область с набором стандартных элементов управления. Окно идентифицируется своим заголовком, имеет кнопки минимизации и максимизации размеров, а также кнопку завершения приложения. Под заголовком обычно находится строка меню для выбора различных команд или режимов работы. Большинство программ для Windows поддерживают работу и с клавиатурой, и с мышью. Стандартизация графического интерфейса имеет очень большое значение для пользователя, потому что одинаковый интерфейс экономит его время и упрощает изучение новых приложений. С точки зрения программиста, стандартный вид интерфейса обеспечивается использованием подпрограмм, встроенных непосредственно в Windows, что также приводит к существенной экономии времени при написании новых программ.
Минимальная программа:
#include <windows.h>
LONG WINAPI WndProc(HWND, UINT, WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HWND hwnd;
MSG msg;
WNDCLASS w;
memset(&w, 0, sizeof(WNDCLASS));
w.style = CS_HREDRAW | CS_VREDRAW;
w.lpfnWndProc = WndProc;
w.hInstance = hInstance;
w.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
w.lpszClassName = "My Class";
RegisterClass(&w);
hwnd = CreateWindow("My Class", "My title", WS_OVERLAPPEDWINDOW,
300, 200, 200, 180, NULL, NULL, hInstance, NULL);
ShowWindow(hwnd,nCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LONG WINAPI WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)
{
switch (Message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, Message, wparam, lparam);
}
return 0;
}
WinMain - это главная функция в Windows-приложениях. Именно с нее и начинается выполнение программы. Аналогичной функцией в консольных приложениях является функция main. Разумеется, функция WinMain должна быть ровно одна - не больше и не меньше.
В WinMain передается 4 параметра. Первые два из них имеют тип HINSTANCE. Этот тип - это Windows-тип который означает экземпляр приложения. Первый параметр при этом содержит указатель (в смысле handle) на текущий экземпляр приложения, второй - всегда равен NULL. Третий параметр представляет из себя указатель на строку, заканчивающуюся нуль-символом (стандартное представление строк в C/C++). Эта строка - это параметры командной строки, передаваемой в приложение. Параметры командной строки включают и имя программы. И, наконец, четвертый параметр определяет способ показа главного окна нашего приложения - т. е. показывать ли его развернутым на целый экран, или в нормальном виде, или в сложенном и др.
Сначала мы создаем класс окна, потом регистрируем его в Windows, после чего создаем на основе этого класса окно и показываем его. На последнем этапе мы запускаем цикл обработки сообщений (так называемый message pump).
Создание класса окна начинается с объявления переменной типа WNDCLASS: WNDCLASS w;
Далее мы заполняем поля этой переменной. Она имеет структурный тип, так что мы должны заполнить все поля. Так как большинство из них можно поставить в ноль, то сначала мы обнуляем их всех:
memset(&w, 0, sizeof(WNDCLASS));
а потом задаем для остальных подходящие значения:
w.style = CS_HREDRAW | CS_VREDRAW;
w.lpfnWndProc = WndProc;
w.hInstance = hInstance;
w.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
w.lpszClassName = "My Class";
Тут мы последовательно задавали стиль окна, установили, что переменная hInstance нашей структуры должна содержать handle на текущий экземпляр приложения (это первый параметр функции WinMain), установили цвет фона и задали имя класса окна.
Далее мы регистрируем наш класс в системе Windows: RegisterClass(&w);
После этого мы, наконец-то, создаем окно с помощью функции CreateWindow:
hwnd = CreateWindow("My Class", "My title", WS_OVERLAPPEDWINDOW,
300, 200, 200, 180, NULL, NULL, hInstance, NULL);
Параметры этой функции задают внешний вид нашего окна. Она возвращает в качестве значения handle на созданное окно. Это у нас переменная hwnd типа HWND. Далее все операции с окном мы делаем через этот handle. В частности, мы показываем окно и обновляем его:
ShowWindow(hwnd,nCmdShow);
UpdateWindow(hwnd);
После того, как окно создано и показано, мы запускаем цикл обработки сообщений:
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Окнонная процедура у нас названа WndProc. Это название произвольное - в принципе мы могли назвать ее как угодно. Основное предназначение оконной процедуры - это обработка сообщений Windows. Для этого мы пишем большой (как правило) switch, внутри которого пишем несколько case'ов. Если мы хотим, например, чтобы наша программа обращала внимание на изменение размера окна, то мы должны написать
switch (Message)
{
...
case WM_SIZE:
//Обработчик сообщения WM_SIZE.
...
Если же мы такого не напишем, то наша программа никак реагировать на изменение размеров окна не будет. При этом соответствующее сообщение Windows программа все равно получит.
Мы писали минимальную программу, так что у нас обработчик только одного сообщения Windows - WM_DESTROY. Это сообщение окно получает при своем уничтожении. В этом обработчике мы только делаем некоторые действия, связанные с уничтожением нашего окна.
Обратите внимание на ветку default:
...
default:
return DefWindowProc(hwnd, Message, wparam, lparam);
...
Тут мы вызываем API-функцию DefWindowProc. Основное предназначение этой API-функции - это обработка сообщений Windows, которые не обрабатываются в нашей программе (т. е. тех, для которых нет своего case). При этом ничего особенно это функция не делает, но очередь из сообщений при этом двигается. И это самое важное - если у нас не было обработчика по умолчанию, то сообщения, не обрабатываемые нашей программой, забили бы очередь, и она бы встала - и даже те сообщения, для которых есть обработчики, никогда бы не были обработаны. Таким образом, основное предназначение функции DefWindowProc - это обработка ("проглатываение") тех сообщений, которые не обрабатываются в каком-нибудь case'е.
В оконную процедуру передаются 4 параметра:
LONG WINAPI WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)
{
...
Первый из этих параметров - это окно, в которое мы передаем сообщение Windows. Второй - это само сообщение. Третий и четвертый параметры - это дополнительные параметры для конкретного сообщения. Эти параметры будет разными для разных сообщений (и для некоторых сообщений Windows могут вообще не использоваться). Например, для сообщения WM_LBUTTONDOWN в дополнительных параметрах передаются x и y той точки, в которой мы щелкнули, информация и том, были ли при этом нажаты кнопки shift, atl и ctrl и другое; для сообщения WM_SIZE - новые размеры окна и т. д.. Еще обратите внимание, что эти же параметры у нас передаются в функцию DefWindowProc.
Yandex.RTB R-A-252273-3
- Модель программного интерфейса ос windows. Понятие объекта ядра и описателя объекта ядра операционной системы Windows. Нотация программного интерфейса.
- Понятие пользовательского режима и режима ядра операционной системы Windows. Модель виртуальной памяти процесса в пользовательском режиме и в режиме ядра операционной системы Windows.
- Обзор архитектуры и основных модулей операционной системы Windows.
- Системный реестр операционной системы Windows.
- 5. Основные элементы программ с оконным пользовательским интерфейсом. Минимальная программа для ос Windows с окном на экране. Создание и отображение окна.
- Понятие оконного сообщения. Источники сообщений. Очередь сообщений. Цикл приема и обработки сообщений. Процедура обработки сообщений.
- 8. Вывод информации в окно. Механизм перерисовки окна.
- 9. Принципы построения графической подсистемы ос Windows. Понятие контекста устройства. Вывод графической информации на физическое устройство.
- 10. Рисование геометрических фигур. Графические инструменты. Управление цветом. Палитры цветов.
- 11. Растровые изображения. Вывод растровых изображений. Значки и курсоры. Вывод растровых изображений с эффектом прозрачного фона.
- 12. Вывод текста. Логические и физические шрифты.
- 13. Системы координат. Трансформации. Режимы масштабирования.
- 14. Понятие ресурсов программ. Виды ресурсов. Работа с ресурсами. Меню. Окна диалога.
- 15. Понятие динамически подключаемой библиотеки. Структура dll-библиотеки. Создание dll-библиотеки. Использование dll-библиотеки в программе. Статический и динамический импорт.
- 16. Отображение файлов в память.
- 17. Организация многозадачности в операционной системе Windows. Понятие процесса и потока. Контекст потока. Создание и завершение процессов и потоков.
- 18. Механизм приоритетов в операционной системе Windows. Класс приоритета процесса. Относительный приоритет потока. Базовый и динамический приоритеты потока.
- 19. Синхронизация потоков в пределах одного процесса. Критические секции. Спин-блокировки. Interlocked-функции.
- 20. Синхронизация потоков разных процессов. Объекты синхронизации: флаги, семафоры, события, ожидаемые таймеры, именованные и неименованные «трубы» (каналы).
- 21. Синхронизация потоков при создании общих данных с помощью двойных проверок (double-checked locking).
- 22. Синхронизация потоков с помощью мониторов Хоара.
- 24. Структуры данных общего назначения в режиме ядра. Представление строк стандарта Unicode. Представление двусвязных списков.
- 25. Понятие прерывания, исключения и системного вызова.
- 26. Аппаратные и программные прерывания. Таблица обработчиков прерываний. Понятие процедуры обработки прерываний (isr).
- 27. Программируемый контролер прерываний. Уровни прерываний. Механизм вызова прерываний. Функция KeBugCheckEx.
- 28. Исключения. Механизм обработки исключения.
- 29. Системные вызовы. Выполнение системного вызова.
- 30. Понятие отложенной процедуры (dpc). Назначение отложенных процедур.
- 31. Понятие асинхронной процедуры (apc). Назначение асинхронных процедур. Асинхронные процедуры режима ядра и пользовательского режима.
- 32. Понятие рабочего элемента ядра (Work Item). Назначение рабочих элементов.
- 33. Пулы памяти. Пул подкачиваемой памяти, пул неподкачиваемой памяти, пул сессии, особый пул. Тегирование пулов. Структура данных пула.
- 34. Оптимизация использования оперативной памяти с помощью списков предыстории (look-aside lists).
- 35. Блокирование страниц в памяти. Списки описателей памяти (mdl) и их использование
- 36. Представление объекта ядра в памяти. Менеджер объектов.
- 37. Структура драйвера операционной системы Windows. Точки входа в драйвер.
- 38. Объект, описывающий драйвер. Объект, описывающий устройство. Объект, описывающий файл. Взаимосвязь объектов.
- 39. Запрос ввода-вывода (irp). Схема выполнения ввода-вывода в стеке драйверов.
- 40. Структура api ядра ос Windows: Kernel api, Windowing api, Messaging api. Функции ZwXxx/NtXxx в пользовательском режиме и в режиме ядра.
- 42. Перехват функций ос Windows api в пользовательском режиме. Интерфейсный модуль ntdll.Dll.
- 43. Перехват вызова функций ос Windows в режиме ядра. Встроенная защита от перехвата в новейших версиях ос Windows.