Окна в Windows . Регистрация и создание окон



ТЕМА: ОСНОВЫ ПРОГРАММИРОВАНИЯ ДЛЯ WINDOWS С ИСПОЛЬЗОВАНИЕМ WIN32 API

 

Общая характеристика ОС Windows

Операционные системы Windows – это семейство ОС с графическим интерфейсом пользователя, разработанное фирмой Microsoft для использования на компьютерах типа IBM PC. В состав семейства Windows входит несколько групп ОС:

- Windows 95/98/Ме;

- Windows NT/2000/XP/Vista/ Windows Server 2008/Windows Small Business Server/Windows 7/Windows Server 2008 R2 /Windows Home Server 2011 /Windows 8/Windows Server 2012/Windows 8.1 (2013)/Windows Server 2012 R2/Windows 10/Windows Server 2016;

- ОС для смартфонов (Windows CE, Windows Mobile, Windows Phone, Windows 10 Mobile);

- встраиваемые (Windows Embedded CE, Windows Embedded Standard, Windows Embedded POSReady, Windows Embedded Enterprise, Windows Embedded NavReady).

Характерным для всех ОС Windows является: а) использование сообщений и окон; б) многозадачность и многопоточность.

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

Каждое Windows-приложение построено на основе цикла обработки сообщений, который принимает эти сообщения и отправляет их к соответствующим функциям – обработчикам сообщений.

С точки зрения пользователя, окно - это прямоугольная область экрана, которую занимает каждая программа Windows. Одна программа может создать несколько окон, но всегда имеется одно окно верхнего уровня, которое называется “главным окном” приложения.

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

ОС Windows являются многозадачными и многопоточными. Они позволяют запускать несколько процессов (задач) в виде приложений, каждое из которых может состоять из одного или более потоков. Различные приложения и потоки делят между собой ограниченные ресурсы ПК, распределение которых осуществляет операционная оболочка Windows. Имеются специальные механизмы управления процессами и потоками, которые будут рассмотрены позже.

Типичное Win32-приложение состоит из одного или более потоков, которые выполняются параллельно (например, один поток обрабатывает данные, вводимые пользователем, а другой поток занят передачей документа на принтер).

 

Win32 API

Win32 API (Application Programming Interface - интерфейс прикладного программирования) - это набор функций разработанных фирмой Microsoft, позволяющих программисту создавать приложения для Windows. Win32 API является основой для каждой Windows-программы.

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

Функции API содержатся в библиотеках динамической загрузки (Dynamic Link Libraries, или DLL), таких как Kernel32.dll, User32.dll и Gdi32.dll и др. Kernel32.dll содержит API-функции, работающие с памятью и управляющие процессами. User32.dll управляет пользовательским интерфейсом программы. Gdi32.dll содержит графические функции.

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

 

 

Типы данных в Windows

В Windows-программах кроме стандартных типов данных из языков С или С++, широко используются типы данных, определенные в различных заголовочных (.h) файлах MS Visual C++.

Основные типы данных, используемых в Win32 API приведены в таблице.

Обозначение типа Описание
BOOL, BOOLEAN Логический. Имеет 2 значения: 0 - FALSE и TRUE – любое друг. знач.
CHAR 8-битный символ (ANSI Windows) или целое 8-битное число со знаком
WCHAR 16-битный символ (Unicode)
TCHAR CHAR или WCHAR, если используется Unicode
BYTE Целое 8-битное число без знака
SHORT Целое 16-битное число со знаком
USHORT, WORD Целое 16-битное число без знака
INT, LONG, INT32, LONG32 Целое 32-битное число со знаком
DWORD, UINT, DWORD32 Целое 32-битное число без знака
LONGLONG, INT64, LONG64 Целое 64-битное число со знаком
ULONGLONG, DWORD64, UINT64 Целое 64-битное число без знака
FLOAT Число с плавающей точкой, 32-бита
HANDLE Дескриптор объекта Windows - 32-битное целое
HWND Дескриптор окна – 32-битное целое
LPSTR  Дальний указатель на строку с нуль-символом в конце (ANSI)
LPCSTR Дальний указатель на константную (const) строку с нуль-символом в конце (ANSI)
Другие типы данных Описание приведено в литературе и электр. справочниках

Примечание: Целые типы данных с числом в конце, указывающим длину значения в битах (INT32, LONG64 и т.д.) определены для использования в 64-разрядных версиях Windows.

 

Соглашение об именах (Венгерская нотация)

 

При задании имен функциям и переменным в Windows-программах рекомендуется соблюдать ряд правил, называемых "Венгерская нотация" или соглашением об именах идентификаторов. Автором этого соглашения является ведущий программист Microsoft, д-р Чарльз Симонии (Charles Simonyi), венгр по происхождению.

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

При задании нового идентификатора в программе, необходимо руководствоваться следующим:

1. Мнемоническое значение: идентификатор должен легко запоминаться

2. Смысловое значение: роль идентификатора должна быть ясна из его названия

3. Преемственность: похожие объекты должны иметь похожие идентификаторы.

4. Скорость решения: задание, ввод и редактирование идентификатора не должны занимать слишком много времени, идентификатор не должен быть слишком длинным.

Для функций используются имена, построенные из глаголов и существительных, причем первые буквы этих слов — заглавные. Например, CreateWindow – функция создания окна, GetFreeDiskSpace – функция для получения объема свободного дискового пространства.

Для имен переменных используется небольшой префикс из строчных букв, а собственно имя начинается с заглавной буквы и может состоять из нескольких слов.

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

 Префикс Назначение Тип в программе
g_ Префикс для глобальной переменной  
f Логическое значение (flag) BOOL, BOOLEAN
ch ASCII символ, 1 байт CHAR
b Короткое целое число без знака, 8 бит BYTE, UCHAR
w Целое число без знака, 16-бит WORD
i, n Длинное целое число со знаком, 32 бита INT
l Длинное целое число со знаком, 32 бита LONG
u Длинное целое без знака, 32 бита UINT
dw Длинное целое без знака, 32 бита DWORD
flt Вещественное число с плавающей точкой FLOAT
fn Функция  
p, lp Указатель, дальний указатель тип *
pv Указатель на произвольный тип VOID *, PVOID
sz Символьный массив - ASCII строка CHAR[]
lpsz Указатель на ASCII строку с нуль-символом в конце. CHAR *, PCHAR
lpcsz Указатель на константную ASCII строку с нуль-символом в конце. CONST CHAR *
h Дескриптор объекта Windows HANDLE

 

Примеры записи имен переменных:

szСlassName – строка с именем класса;

nCounter – счетчик, целый тип;

lParam – параметр, длинное целое;

lpObject – дальний указатель на объект;

lpfnWndProc – дальний указатель на оконную функцию;

hWnd – дескриптор окна.

 

При обозначении переменных, имеющих тип структуры удобно пользоваться именем самой структуры (или аббревиатурой имени структуры) и строчными буквами, используя их либо в качестве префикса имени переменной, либо как имя переменной в целом. Например, переменная msg относится к структуре типа MSG; wndclass или wc – к структуре типа WNDCLASS, переменная ps относится к структуре PAINTSTRUCT, rect — к RECT и т.д.

Тема: Структура семейства ОС Windows NT /2000/ XP . Объекты ядра ОС.

 

Структура Windows NT /2000/ XP

 

Отличительной особенностью семейства ОС Windows NT/2000/XP (Windows NT) от Windows 95/98 (Windows 9х) является то, что они построены на основе ядра (микроядра). Это обеспечивает более высокую надежность, устойчивость к сбоям и защищенность Windows NT.

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


Первая часть Windows NT, работающая в режиме ядра, называется NT executive - исполнительной частью. Она включает ряд компонентов, которые управляют виртуальной памятью, объектами (ресурсами), вводом-выводом и файловой системой, взаимодействием процессов и системой безопасности. Эти компоненты взаимодействуют между собой с помощью межмодульной связи.

Вторую часть Windows NT, работающую в режиме пользователя, составляют серверы - так называемые защищенные подсистемы. Каждая из них выполняется в отдельном процессе, память которого отделена от других процессов системой управления виртуальной памятью NT executive. Защищенные подсистемы автоматически не могут совместно использовать память, они общаются друг с другом посредством посылки сообщений. Все сообщения проходят через исполнительную часть Windows NT.

Клиенты, которыми могут быть либо прикладные программы различных типов (Win32/Win16/MS DOS, OS/2, POSIX/UNIX), либо другие компоненты ОС, запрашивают сервисы, посылая сообщения на серверы.

Исполнительная часть ОС - NT executive работает в пространстве ядра и никогда не сбрасывается на диск. Ее составными частями являются:

· Менеджер объектов. Создает, удаляет и управляет объектами NT executive - абстрактными типами данных, используемых для представления ресурсов системы.

· Монитор ссылок безопасности. Устанавливает правила защиты на компьютере. Охраняет ресурсы операционной системы, выполняет защиту и регистрацию исполняемых объектов.

· Менеджер процессов. Создает и завершает, приостанавливает и возобновляет процессы и потоки, а также хранит о них информацию.

· Средства вызова локальных процедур LPC (Local Procedure Call). Являются основным средством, скрепляющим все подсистемы Windows NT в единое целое путем передачи данных между клиентами и серверами.

· Менеджер виртуальной памяти. Обеспечивает выделение и защиту виртуальных адресных пространств всем процессам, выполняемым в ОС.

· Менеджер ввода-вывода, предоставляющий средства ввода-вывода, независимые от устройств. Включает в себя следующие компоненты:

· файловые системы - NT-драйверы, выполняющие файл-ориентированные запросы на ввод-вывод и транслирующие их в вызовы обычных устройств;

· кэш-менеджер, реализующий кэширование диска;

· драйверы устройств NT executive - низкоуровневые драйверы, которые непосредственно управляют устройствами.

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

· планирование процессов,

· обработка прерываний и исключительных ситуаций,

· синхронизация процессоров для многопроцессорных систем,

· восстановление системы после сбоев.

Уровень аппаратных абстракций HAL (Hardware Abstraction Level) располагается между NT executive и аппаратным обеспечением и концентрирует в одном месте большую часть машинно-зависимых процедур. HAL скрывает от системы такие детали, как контроллеры прерываний, интерфейсы ввода/вывода и механизмы взаимодействия между процессорами. Такое решение позволяет легко переносить Windows NT с одной платформы на другую путем замены только слоя HAL.

 

Объекты ядра ОС Windows NT /2000/ XP

Общая характеристика

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

Windows позволяет создавать и оперировать с несколькими типами таких объектов, в том числе:

 

Объект ядра Название объекта
Access token Маркер доступа
Change notification Уведомление об изменениях на диске
I/O completion ports Порты завершения ввода-вывода
Event Событие
File Файл
File mapping Проекция файла
Heap Куча
Job Задание
Mailslot Почтовый слот (ячейка)
Module Подгружаемый модуль (DLL)
Mutex Мьютекс
Pipe Канал
Process Процесс
Semaphore Семафор
Socket Сокет
Thread Поток
Timer Ожидаемый таймер

 

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

 

В пользовательское приложение передается только описатель (handle) объекта, а управлять объектом ядра можно с помощью функций Win32 API.

 

Учет пользователей объектов ядра

Ядру известно, сколько процессов использует конкретный объект ядра, поскольку в каждом объекте есть счетчик числа его пользователей. Этот счетчик — один из элементов данных, общих для всех типов объектов ядра.

В момент создания объекта счетчику присваивается 1. Когда к существующему объекту ядра обращается другой процесс, счетчик увеличивается на 1, А когда какой-то процесс завершается, счетчики всех используемых им объектов ядра автоматически уменьшаются на 1. Как только счетчик какого-либо объекта обнуляется, ядро уничтожает этот объект.

 

Таблица описателей объектов ядра

При инициализации процесса операционная система создает в нем таблицу описателей, используемую только для объектов ядра. Эта таблица представляет собой массив структур данных. Каждая структура содержит указатель на какой-либо объект ядра, маску доступа и некоторые флаги.

Ниже показано, как выглядит таблица описателей, принадлежащая процессу.

 

Ин-декс Указатель на блок памяти объекта ядра Маска доступа (DWORD с набором битовых флагов) Флаги (DWORD с набором битовых флагов)
1 Ох???????? Ох???????? Ох????????
2 Ох???????? Ох???????? Ох????????

 

Создание объекта ядра

Объект ядра создается при вызове одной из Create-функций Win32 API. Менеджер объектов ядра выделяет для этого объекта блок памяти и инициализирует его. При этом указатель устанавливается на внутренний адрес структуры данных объекта, маска доступа — на доступ без ограничений и определяется последний компонент — флаги.

Некоторые функции, создающие объекты ядра:

HANDLE CreateThread(…); // Создает объект ядра - поток

HANDLE CreateFile(…); // Создает объект ядра - файл

HANDLE CreateFileMapping(…); // Создает объект ядра – проекцию файла

HANDLE CreateSernaphore(…); // Создает объект ядра - семафор

Все функции, создающие объекты ядра, возвращают описатели, которые привязаны к конкретному процессу и могут быть использованы в любом потоке данного процесса.

Значение описателя представляет собой индекс в таблице описателей, принадлежащей процессу, и таким образом идентифицирует место, где хранится информация, связанная с объектом ядра.

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

 

Закрытие объекта ядра

Независимо от того, как именно был создан объект ядра, по окончании работы с ним его нужно закрыть вызовом функции CloseHandle:

BOOL CloseHandle(HANDLE hobj);

где параметр hobj – описатель ядра объекта.

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

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

Функцию CloseHandle следует вызывать, когда в ходе работы программы отпадает необходимость в каком-либо объекте ядра.

Если в программе не вызвать CloseHandle, то по завершении процесса операционная система гарантированно освобождает все ресурсы, принадлежавшие этому процессу, и в случае объектов ядра действует так: в момент завершения процесса просматривает его таблицу описателей и закрывает любые открытые описатели.

 

Совместное использование объектов ядра несколькими процессами

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

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

- объекты "проекции файлов" позволяют двум процессам, исполняемым на одной машине, совместно использовать одни и те же блоки данных;

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

Имеется три способа, позволяющих процессам совместно использовать одни и те же объекты ядра:

- создание именованных объектов;

- наследование описателя объекта родительского процесса дочерним процессом;

- дублирование описателей объектов.

Более подробно эти способы будут рассмотрены при изучении соответствующих объектов ядра.

 


Окна в Windows . Регистрация и создание окон

 

Определение окна. Основные элементы окон

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

При загрузке ОС Windows создается окно, занимающее весь экран (Desktop window). Каждое Windows-приложение создает хотя бы одно окно, называемое главным окном приложения (Main window, Overlapped window). Приложения могут создавать еще несколько дополнительных окон.

Окно приложения может состоять из следующих элементов, показанных на рисунке:

                 
       

 


8
7
6

     
10
 
9

 


1 - Пиктограмма приложения (Application icon)

2 – Строка заголовка (Title bar)

3 – Кнопка минимизации окна (Minimize button)

4 - Кнопка максимизации окна (Maximize button)

5 - Кнопка закрытия окна (Close button)

6 – Строка меню (Menu bar)

7 – Полоса вертикальной прокрутки (Vertical scroll bar)

8 – Граница установки размера окна (Sizing border)

9 - Полоса горизонтальной прокрутки (Horizontal scroll bar)

10 – Клиентская (рабочая) область (Client area)

 

Приложения могут использовать и другие типы окон, которые будут рассмотрены позже:

- окна сообщений (Message boxes),

- диалоговые окна (Dialog boxes),

- элементы управления (Controls).

У каждого окна в Windows имеется уникальный дескриптор типа HWND. Дескриптор окна – это один из важнейших описателей, которыми оперирует Windows-программа. Для выполнения различных операций с окнами в качестве параметра функций Windows API требуется указывать дескриптор окна.

 

Класс окна

Внешний вид и основные характеристики окна определяются классом этого окна. Окна одного класса имеют одинаковые вид и поведение.

Существует три типа классов окна:

1. Системные глобальные классы, которые регистрируются при загрузке ОС и доступны всем приложениям системы. К ним относятся классы окон элементов управления (кнопки, списки, полосы прокрутки и т.д.).

2. Прикладные глобальные классы, которые регистрируются динамически связываемыми библиотеками (DLL) и доступны всем приложениям, которые загружают эти библиотеки.

3. Прикладные локальные классы, которые приложения регистрируют для своего внутреннего использования.

Класс окна (он не является классом языка C++) это структура типа WNDCLASS (или WNDCLASSEX), которая содержит информацию о начальном внешнем виде окна, пиктограмме по умолчанию, курсоре и ресурсе меню, связанных с окном, а также - адрес функции, называемой оконной процедурой.

Структура WNDCLASS описана следующим образом:

typedef struct

{ UINT        style;

WNDPROC lpfnWndProc;

int            cbClsExtra;

int            cbWndExtra;

HANDLE    hInstance;

HICON      hIcon;

HCURSOR hCursor;

HBRUSH   hbrBackground;

LPCTSTR lpszMenuName;

LPCTSTR pszClassName;
} WNDCLASS;

Назначение полей этой структуры:

- style определяет стиль класса окна.

- lpfnWndProc указывает на функцию окна. Она будет рассмотрена позже.

- cbClsExtra равно количеству дополнительных байтов класса.

- cbWndExtra равно количеству дополнительных байтов окна этого класса.

- hlnstance указывает на дескриптор текущего приложения.

- hIcon задает дескриптор иконки (пиктограммы), которая отображается в заголовке окна. Если этот параметр равен NULL, то принимается иконка по умолчанию.

- hCursor задает дескриптор курсора мыши, который определяет его вид при прохождении над окном.

- hbrBackground задает дескриптор кисти для закрашивания фона окна.

- lpszMenuName указывает на имя ресурса главного меню окон этого класса. Если задать NULL, окна этого класса не имеют заданного по умолчанию меню.

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

Примечание: структура WNDCLASSEX аналогична WNDCLASS и отличается от неё наличием двух дополнительных полей: cbSize – длина структуры в байтах, hIconSm - дескриптор малой иконки для окон этого класса.

 

Стиль класса окна

Стиль класса окна style задается в виде набора символических констант с префиксом CS_, соединенных побитовой логической операцией |. Определенный в классе окна стиль класса определяет поведение всех окон, созданных на базе этого класса.

Чаще всего используются стиль:

CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS

Стили CS_HREDRAW и CS_VREDRAW определяют, что при изменении размеров окна по горизонтали или вертикали должна производиться перерисовка содержимого окна.

Стиль CS_DBLCLKS определяет, что окно должно реагировать на двойные щелчки кнопок мыши. Если этот стиль не будет задан, то окна будет получать только сообщения об одиночном нажатии кнопок мыши.

В поле style могут также задаваться и другие значения для стиля класса окна.

 

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

Для регистрации классов окон в Windows используется функция RegisterClass() (или RegisterClassEx() для структуры WNDCLASSEX). Синтаксис этой функции следующий:

ATOM RegisterClass(CONST WNDCLASS *lpWndClass);

Параметр lpWndClass является указателем на структуру типа WNDCLASS.

Возвращаемое значение является атомом (16-разрядным значением), идентифицирующим уникальную символьную строку в таблице атомов Windows.

Перед регистрацией класса окна необходимо объявить в программе переменную-структуру типа WNDCLASS, очистить её нулями, заполнить требуемые поля в ней и передать адрес этой структуры в функцию RegisterClass(). Например:

WNDCLASS wc;

// Очистка полей структуры 0

memset(&wc, 0, sizeof(wc));

// Заполнение полей стр-ры WNDCLASS

wc.style = CS_HREDRAW | CS_VREDRAW;

wc.lpfnWndProc = (WNDPROC) WndProc;

wc.lpszClassName = szClassName;

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

RegisterClass(&wc);

 

Создание окна

Приложение создает окно с помощью функции CreateWindow(), которая имеет прототип:

HWND CreateWindow(LPCSTR lpClassName,

     LPCSTR lpWindowName, DWORD dwStyle,

     int x, int y, int nWidth, int nHeight,

     HWND hWndParent, HMENU hMenu,

     HANDLE hInstance, LPVOID lpParam);

Параметры функции:

· lpClassName указывает имя класса, характеристики которого наследует данное окно. Этот класс должен быть зарегистрирован с помощью фунцкии RegisterClass() или может быть одним из предопределенных классов элементов управления с именами: “button”, “combobox”, “listbox”, “edit”, “scrollbar” и “static”.

· lpWindowName определяет строку, которая выводится в заголовке создаваемого окна.

· dwStyle задает стиль окна. Стили окон будут рассмотрены ниже.

· x, y задают координату левого верхнего угла окна.

· nWidth и nHeight задают ширину и высоту окна. Если при задании параметров x, y, nWidth и nHeight использовать константу CW_USEDEFAULT, то Windows установит расположение и размеры окна самостоятельно.

· hWndParent задает для создаваемого окна дескриптор его окна-родителя. Если окно является главным окном приложения, то этому параметру присваивается значение NULL.

· hMenu определяет для окна дескриптор меню. При значении параметра NULL у окна будет только меню, заданное в структуре класса этого окна.

· hInstance задает дескриптор экземпляра приложения, которое создает окно.

· lpParam является указателем на дополнительные данные, которые передаются окну при его создании (если их нет, то он должен быть равен NULL).

Функция CreateWindow() возвращает дескриптор типа HWND для созданного окна.

 

Стили окон

Стиль окна является одной из важнейших его характеристик и используется при создании окна. Для определения стиля окна используются символические константы с префиксом WS_.

В Windows используется три основных стиля окон:

- перекрывающиеся окна (Overlapped windows),

- всплывающие (временные) окна (Pop-up windows),

- дочерние окна (Child windows).

Перекрывающиеся окна

Overlapped window - это окно верхнего уровня, которое всегда имеет заголовок, рамку и рабочую об­ласть, может иметь системное меню, кнопки восста­новления размеров, закрытия и сворачивания окна в пиктограмму, го­ризонтальную и вертикальную полосы просмотра, меню (см. рис. выше). Окна этого типа предназначены для использования в качестве главного окна приложения.

Базовый стиль таких окон задается константой WS_OVERLAPPED. Чаще используется стиль окон WS_OVERLAPPEDWINDOW, который вдобавок к базовому указывает, что окно имеет системное меню, кнопки восста­новления размеров, закрытия и сворачивания окна.

Всплывающие окна

Pop-up window - это специальный тип окон, используемый для создания окон диалога, окон сообщений и других временных окон, которые отображаются на экране непродолжительное время.

Для создания всплывающего окна используется стиль WS_POPUP. Этот стиль может комбинироваться с WS_CAPTION, для наделения окна заголовком. Стиль WS_POPUPWINDOW используется для наделения всплывающего окна дополнительно системным меню и границей.

Дочерние окна

Для порождения дочернего окна служит стиль WS_CHILDWINDOW. Эти окна используются для создания элементов управления, таких, как кнопки, списки и др.

Дочернее окно отображается в пределах клиентской области родительского окна и по умолчанию имеет только клиентскую область. Дополнительно можно задать любые элементы кроме меню.

Особенности поведения дочерних окон следующие:

· Дочернее окно находится в пределах родительского окна и перемещается вместе с ним.

· Все дочерние окна скрываются при сворачивании окна-родителя в пиктограмму и появляются вновь при восстановлении родительского окна.

 

Отображение окна

Для отображения окна на экране используется функция:

BOOL ShowWindow(HWND hWnd, int nCmdShow);

Параметры функции:

- hWnd задает дескриптор окна, полученный функцией CreateWindow().

- nCmdShow задает начальный вид окна на экране. По умолчанию используется величина, передаваемая в качестве одноименного параметра функции WinMain(). Параметр nCmdShow может принимать ряд значений:

· SW_SHOWMAXIMIZED – окно становится активным и отображается максимальных размеров;

· SW_SHOWNORMAL -  окно становится активным и отображается в заданных размерах и позиции;

· SW_SHOWMINNOACTIVE окно отображается пиктограммой и становится не активным;

· другие значения (см. документацию).

Функция возвращает значение TRUE, если ранее окно было видимым и FALSE – в противном случае.

 

Обновление содержимого окна

Для перерисовки рабочей области окна hWnd производится вызов функции:

BOOL UpdateWindow(HWND hWnd);

Функция UpdateWindow() посылает оконной функции сообщение WM_PAINT, которая, получив его, обновляет содержимое рабочей области окна.

Возвращает значение TRUE при успешном завершении и FALSE – в противном случае.

 

Пример создания и отображения в программе 3-х окон разных стилей: главного, всплывающего (временного) и дочернего.

 

// Регистрация классов окон с именами "MainWindow”, "PopUpWindow", "ChildWindow"

. . .

// Создание главного (перекрывающегося) окна

HWND hWndMain = CreateWindow("MainWindow", 

"OVERLAPPEDWINDOW",

WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

if(hWndMain == NULL)

return FALSE; // Завершение работы при неудаче

ShowWindow(hWndMain, SW_SHOWMAXIMIZED);

UpdateWindow(hWndMain);

 

// Создание всплывающего (временного) окна

HWND hWndPopup = CreateWindow("PopUpWindow",

"POPUPWINDOW", WS_POPUPWINDOW|

WS_CAPTION|WS_MINIMIZEBOX|

   WS_MAXIMIZEBOX, 100, 100, 300, 300,

hWndMain, NULL, hInstance, NULL);

if(hWndPopup == NULL)

{ // Уничтожение главного окна при неудаче

DestroyWindow(hWndMain);

return FALSE;

}

ShowWindow(hWndPopup, SW_SHOWNORMAL);

UpdateWindow(hWndPopup);

 

// Создание дочернего окна

HWND hWndChild = CreateWindow("ChildWindow",

"CHILDWINDOW", WS_CHILDWINDOW|

WS_CAPTION|WS_MINIMIZEBOX| WS_MAXIMIZEBOX, 150, 150, 250, 250, hWndMain, NULL, hInstance, NULL);

if(hWndChild== NULL)

{ // Уничтожение главного и всплывающего

// окон при неудаче

DestroyWindow(hWndMain);

   DestroyWindow(hWndPopup);

   return FALSE;

}

ShowWindow(hWndChild, SW_SHOWNORMAL);

UpdateWindow(hWndChild);

 

Тема: Классы и стили окон

 

Основное поведение окна определяется классом окон. Класс окна (он не является классом языка программирования C++) несет информацию о начальном внешнем виде окна, пиктограмме по умолчанию, курсоре и ресурсе меню, связанном с окном; и – об адресе функции, называемой оконной процедурой.

Набор используемых ресурсов класса окна задают в структуре типа WNDCLASS . Эта структура описана следующим образом:

typedef struct

{ UINT style;

WNDPROC lpfnWndProc;

int     cbClsExtra;

int      cbWndExtra;

HANDLE hInstance;

HICON hlcon;

HCURSOR hCursor;

HBRUSH hbrBackground;

LPCTSTR lpszMenuName;

LPCTSTR lpszClassName;
} WNDCLASS;

 

Например, если описана структура для класса окна

WNDCLASS wc;

затем присваивают определенные значения ее полям.

 

Назначение полей этой структуры:

1. style определяет стиль класса окна и поведение окна, например:
wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;

2. lpfnWndProc указывает на функцию окна. Она будет рассмотрена позже.

3. cbClsExtra равно количеству дополнительных байтов класса.

4. cbWndExtra равно количеству дополнительных байтов окна этого класса.

5. hlnstance указывает на дескриптор текущего приложения.

6. hlcon указывает на имя пиктограммы (иконки), в которую превращается окно при минимизации.

7. hCursor задает вид курсора мыши при его прохождении над окном.

8. hbrBackground задает дескриптор кисти закрашивания фона окна.
9. lpszMenuName указывает на имя ресурса главного меню окон этого класса. Если задать NULL, окна этого класса не имеют заданного по умолчанию меню. Например: we.lpszMenuName = (LPCTSTR)NULL;

10. lpszClassName указывает на текстовую строку, содержащую имя ре­гистрируемого класса окон, например:

wc.lpszClassName = szName;

 

Стиль класса окна

Стиль класса окна определяется при регистрации класса окна. Стиль класса окна задается в виде отдельных битов, для которых определены символические константы с префиксом CS_. Определенный в классе окна стиль класса окна используется при создании всех окон на базе этого класса.

Чаще всего используются стиль CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS. Если для класса заданы стили CS_HREDRAW и CS_VREDRAW, то при изменении размеров окна функция окна может получить сообщение WM_PAINT. В этом случае функция окна должна перерисовать часть окна или все окно.

Стиль CS_DBLCLKS используется при необходимости отслеживать двойные щелчки мышью. При этом в функцию окна посылаются сообщения WM_LBUTTONDBLCLK и WM_RBUTTONDBLCLK. Если этот стиль не будет задан, функция окна получит только идущие парами сообщения об одиночном нажатии клавиш мыши WM_LBUTTONDOWN и WM_RBUTTONDOWN.

Стили окон, окна основных стилей

Определенный в классе окна стиль класса окна используется при создании всех окон на базе этого класса. Для дальнейшего уточнения внешнего вида и поведения окна используется другая характеристика - стиль окна. Стиль окна указывается при создании окна функцией CreateWindow. Для определения стиля окна используются символические константы с префиксом WS_.

Рассмотрим чаще всего используемые основные стили:

- перекрывающиеся окна (overlapped window),

- всплывающие (или временные, или выпадающие) окна (pop-up window),

- дочерние окна (child window).

Перекрывающиеся окна

Перекрывающиеся окна имеют заголовок (title bar), рамку и внутреннюю часть окна (client region). Дополнительно перекрывающиеся окна могут иметь системное меню, кнопки для максимального увеличения размера окна и для свертки окна в пиктограмму, вертикальную и горизонтальную полосу просмотра и меню.

Перекрывающиеся окна обычно используются в качестве главного окна приложения.

Для определения стиля перекрывающегося окна существует символическая константа WS_OVERLAPPEDWINDOW, определенная как поразрядное ИЛИ нескольких констант:

#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED|WS_CAPTION|

WS_SYSMENU|WS_THICKFRAME|        

WS_MINIMIZEBOX|WS_MAXIMIZEBOX)

Приложение Windows может создавать несколько перекрывающихся окон, связанных между собой “узами родства” и “отношениями собственности”. При создании окон при помощи функции CreateWindow в качестве восьмого параметра функции можно указать дескриптор окна-владельца (переменная типа HWND). Окно-владелец уже должно существовать на момент создания окна, имеющего владельца.

Основные особенности перекрывающихся окон:

· Если окно-хозяин сворачивается в пиктограмму, все окна, которыми оно владеет, становятся невидимыми.

· Если сначала свернули в пиктограмму окно, которым владеет другое окно, а затем и окно-хозяина, то пиктограмма подчиненного окна исчезнет.

· При уничтожении окна-владельца автоматически уничтожаются и все принадлежащие ему окна.

· Обычное перекрывающееся окно, не имеющее окна-владельца, может располагаться в любом месте экрана и принимать любые размеры. Подчиненные окна располагаются всегда над поверхностью окна-владельца, перекрывая его изображение.

· Координаты создаваемых функцией CreateWindow перекрывающихся окон указываются по отношению ко всему экрану, т.е. при создании окна с координатами (0,0), оно будет расположено в верхнем левом углу экрана.

· При изменении размеров перекрывающегося окна функция окна получает сообщение WM_SIZE, в параметрах которого указаны новые размеры окна.

Временные окна

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

Часто для создания выпадающих окон, имеющих рамку, используется стиль WS_POPUPWINDOW, определенный как поразрядное ИЛИ нескольких констант (для того чтобы к временному окну добавить системное меню и заголовок, следует использовать комбинацию WS_POPUPWINDOW | WS_CAPTION):

#define WS_POPUPWINDOW (WS_POPUP|WS_BORDER|WS_SYSMENU)

Перечислим особенности временных окон.

· Временные окна могут иметь окно-владельца и могут сами владеть другими окнами. Замечания относительно владения перекрывающимися окнами, справедливы и для временных окон.

· Начало системы координат, используемой при создании временных окон, находится в левом верхнем углу экрана. Поэтому при создании временных окон применяются экранные координаты, как и при создании перекрывающихся окон.

· При изменении размеров временного окна функция окна получает сообщение WM_SIZE, в параметрах которого указаны новые размеры окна.

Дочерние окна

Дочерние окна чаще всего используются приложениями Windows. Эти окна нужны для создания органов управления, таких, как кнопки или списки. Все органы управления - дочерние окна.

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

Особенности дочерних окон следующие:

· Дочерние окна должны иметь окно-родителя. Только дочерние окна могут иметь родителей, перекрывающиеся и временные окна могут иметь окно-хозяина, но не родителя. У дочерних окон могут быть “братья” (или “сестры”).

· Дочерние окна всегда располагаются на поверхности окна-родителя.

· При создании дочернего окна начало системы координат расположено в левом верхнем углу внутренней поверхности окна-родителя (но не в верхнем углу экрана, как для перекрывающихся и временных окон).

· Так как дочернее окно как бы “прилипает” к поверхности окна-родителя, то при щелчке мышью над поверхностью дочернего окна, сообщение от мыши попадет в функцию дочернего, а не родительского окна.

· При создании дочернего окна в качестве девятого параметра (вместо идентификатора меню, которого не может быть у дочернего окна) функции CreateWindow необходимо указать идентификатор дочернего окна (переменная типа int, любое целое число).

· Если для приложения создается несколько дочерних окон, для каждого окна необходимо указать свой идентификатор, эти идентификаторы будут использоваться дочерними окнами при отправлении сообщений родительскому окну.

· Дочернее окно “прилипает” к поверхности родительского окна и перемещается вместе с ним. Оно никогда не может выйти за пределы родительского окна.

· Все дочерние окна скрываются при сворачивании окна-родителя в пиктограмму и появляются вновь при восстановлении родительского окна.

· При изменении размеров родительского окна дочерние окна получаютсообщение WM_PAINT, но не получают сообщения WM_SIZE, это сообщение попадает только в родительское окно.


Примеры создания окон различных стилей

Ниже приведе фрагмент функции WinMain, создающей окна разных стилей на основе двух классов окон:

// регистрация классов окон с именами "MainWindow”, "Window1", "Window2"

     . . .

// создание главного перекрывающегося окна

HWND hWndMain = CreateWindow("MainWindow", "OVERLAPPEDWINDOW",

WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance,NULL);

if(hWndMain == 0) return FALSE;

ShowWindow(hWndMain, nCmdShow);

UpdateWindow(hWndMain);

 

// создание временного окна

HWND hWndPopup = CreateWindow("Window1","POPUPWINDOW",

     WS_POPUPWINDOW|WS_CAPTION|WS_MINIMIZEBOX|

WS_MAXIMIZEBOX|WS_VISIBLE,100,100,300,300,    

hWndMain,NULL,hInstance,NULL);

if(hWndPopup == 0) { DestroyWindow(hWndMain); return FALSE; }

ShowWindow(hWndPopup, nCmdShow);

UpdateWindow(hWndPopup);

 

// создание дочернего окна

HWND hWndChild = CreateWindow("Window2","CHILDWINDOW",

WS_CHILDWINDOW|WS_CAPTION|WS_MINIMIZEBOX|

WS_MAXIMIZEBOX, 150,150,250,250, hWndMain, NULL,

hInstance,NULL);

if(hWndChild== 0)

{ DestroyWindow(hWndMain);

  DestroyWindow(hWndPopup);

  return FALSE;

}

ShowWindow(hWndChild, nCmdShow);

UpdateWindow(hWndChild);

 

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

     . . .

 

Тема: Сообщения Windows . Типы сообщений

 

Сообщения Windows

Когда происходит какое-либо событие (нажатие клавиши, щелчок мыши), Windows преобразовывает его в сообщение, адресованное какому-либо окну, и помещает его в очередь сообщений приложения.

Программа извлекает сообщения из очереди сообщений и направляет их соответствующим оконным функциям (процедурам) для обработки. При этом необработанные сообщения передаются обратно в ОС.

Сообщения описываются структурой типа MSG, которая имеет следующий вид:

typedef struct tagMSG

{     

 HWND hwnd;

 UINT   message;

 WPARAM wParam;

 LPARAM lParam;

 DWORD time;        

 POINT pt;

} MSG;

Назначение элементов структуры:

- hwnd является дескриптором окна, которому посылается это сообщение;

- message представляет собой идентификатор (код) сообщения. Приложения могут использовать младшее слово этого параметра, старшее слово зарезервировано для использования Windows;

- wParam, lParam содержат дополнительную информацию о сообщении, конкретное содержание этих элементов зависит от значения message;

- time указывает время, когда это сообщение было отправлено системой;

- pt определяет позицию курсора мыши, в координатах экрана, во время отправления сообщения.

Для идентификаторов сообщений message обычно используются символьные представления(WM_PAINT, WM_TIMER), а не числовые значения. Эти символьные значения определены в стандартных заголовочных файлах Windows (в приложении необходимо включать в исходный текст только файл windows.h – он содержит директивы #include для остальных файлов). В среде MS Visual C++ в приложение необходимо включать заголовочный файл stdafx.h, который содержит включения всех стандартных заголовочных файл, в т.ч. и windows.h

Типы сообщений

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

Самой обширной является группа сообщений управления окнами. Символьные идентификаторы для этих сообщений начинаются с WM_. Эта большая группа сообщений, поэтому её разбивают на несколько категорий:

· сообщения мыши,

· сообщения клавиатуры,

· сообщения буфера обмена (clipboard),

· сообщения неклиентской (non-client) области окна,

· другие типы.

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

Ниже приведены наиболее часто обрабатываемые оконные сообщения:

· WM_CREATE - посылается окну перед тем, как оно станет видимым, но до завершения функции CreateWindow(). При обработке этого сообщения приложение может выполнить необходимые функции инициализации перед тем, как окно станет видимым.

· WM_DESTROY - посылается оконной процедуре окна, которое уже удалено с экрана и должно быть разрушено.

· WM_QUIT - это обычно последнее сообщение, которое получает главное окно приложения. Получение этого сообщения приводит к завершению работы программы.

· WM_LBUTTONDOWN - одиночное нажатие левой кнопки мыши.

· WM_RBUTTONDOWN одиночное нажатие правой кнопки мыши.

· WM_LBUTTONDBLCLK - двойной щелчок левой кнопкой мыши.

· WM_RBUTTONDBLCLK - двойной щелчок  правой кнопкой мыши.

· WM_KEYDOWN – нажата клавиша на клавиатуре.

· WM_SIZE – указывает, что размер окна был изменен.

· другие сообщения, описанные в документации.

 

Приложения также могут определять собственные сообщения.

Для этого необходимо определить символическое имя нового сообщения при помощи директивы #define, например:

#define СимволичИмяСообщения1 (WM_USER+1)

#define СимволичИмяСообщения2 (WM_USER+2)

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

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

 

Цикл обработки очереди сообщений в программе

Программа извлекает сообщения из очереди сообщений, выполняя блок команд, называемый циклом обработки сообщений (message loop).

Простейший цикл обработки сообщений имеет следующий вид:

MSG msg;

. . .

while(GetMessage(&msg, NULL, 0, 0))

{

TranslateMessage(&msg); 

DispatchMessage(&msg); 

}

. . .

Извлечение сообщений из очереди производится при помощи функции:

BOOL GetMessage(LPMSG lpMsg, HWND hWnd,

UINT uMsgFilterMin, UINT uMsgFilterMax);

Параметры функции:

- lpMsg является дальним указателем на структуру сообщения типа MSG.

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

- uMsgFilterMin и uMsgFilterMax позволяют задать диапазон значений для фильтрации сообщений, получаемых программой. Если на их месте задать 0, то программа будет получать все сообщения.

Если поле message сообщения msg, извлеченного из очереди сообщений, равно любому значению, кроме WM_QUIT, то функция GetMessage() возвращает TRUE. Если из очереди извлечено сообщение WM_QUIT, то GetMessage() возвращает FALSE, что прерывает цикл обработки сообщений. После этого приложение завершает свою работу.

Каждое получаемое приложением сообщение (за исключением WM_QUIT) направлено одному из окон приложения.

Для передачи сообщения нужному окну используется функция:

LRESULT DispatchMessage(const MSG *lpMsg);

Эта функция отправляет сообщение msg для обработки соответствующей оконной процедуре.

Перед вызовом функции DispatchMessage() помещена специальная функция, производящая преобразование сообщений от нажатых клавиш в символьные сообщения:

BOOL TranslateMessage(const MSG *lpMsg);

 

Тема: Общая структура Windows-приложения

Программирование Windows-приложений построено на работе с окнами и обработке сообщений, что и определяет соответствующую структуру программы.

Любая Windows-программа состоит минимум из двух функций – главной функции WinMain() и оконной функции.

 

Функция WinMain() является точкой входа для любой Windows-программы и должна выполнять следующие операции:

1. Определять класс окна;

2. Регистрировать класс окна;

3. Поиск уже запущенной копии приложения;

4. Создавать окно данного класса;

5. Отображать окно;

6. Запускать цикл обработки сообщений.

Функция WinMain() имеет следующий прототип:

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE

     hPrevInstance, LPSTR lpCmdLine, int nCmdShow);

Все параметры функции передаются ей операционной системой при запуске программы. Назначение параметров:

- hInstance называется дескриптором экземпляра приложения. Это уникальное число, идентифицирующее каждый запущенный экземпляр одной и той же программы.

- hPrevInstance ранее использовался в Win16 и в Win32 всегда равен NULL.

- lpCmdLine является указателем на оканчивающуюся нулем строку, в которой содержаться параметры, переданные программе при запуске из командной строки.

- nCmdShow определяет, как окно приложения первоначально отображается на экране: в виде открытого окна (SW_SHOWNORMAL), максимальных размеров (SW_SHOWMAXIMIZED) или иконкой (SW_SHOWMINIMIZED).

Функция WinMain() использует соглашение о передаче аргументов при вызове функций WINAPI и, по завершению, возвращает ОС Windows целое число.

 

Оконная функция предназначена для обработки сообщений, относящихся к данному окну приложения.

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

Оконная функция определяется следующим образом:

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg,

               WPARAM wParam, LPARAM lParam);

Все четыре параметра оконной процедуры идентичны первым четырем полям структуры MSG.

Функция окна не может вызываться приложением напрямую, а вызывается ОС Windows через её имя, указанное в структуре класса окна. Модификатор CALLBACK в заголовке WndProc указывает, что это функция обратного вызова.

 

Обработка сообщений в оконной функции

Функция окна получает сообщение из двух источников: из цикла обработки сообщений и от Windows:

· Из цикла обработки сообщений поступают сообщения ввода: перемещение и нажатие клавиш мыши, нажатие и отпускание клавиш клавиатуры или сообщения от таймера.

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

Если оконная процедура обрабатывает сообщение, то ее возвращаемым значением должен быть 0.

Все сообщения, не обрабатываемые оконной процедурой, должны передаваться в ОС Windows функцией:

LRESULT DefWindowProc(HWND hWnd, UINT msg,

                          WPARAM wParam, LPARAM lParam);

 

Пример исходного текста приложения, которое создает главное окно. При нажатии левой клавишей мыши в клиентской области окна при помощи стандартной диалоговой панели сообщений выдается информация о приложении.

(Приведен в электронном виде в файле "_Пример исх текста прогр.doc").

 

// --- Обязательный включаемый файл

#include "stdafx.h"

// --- Прототип оконной функции главного окна

LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

// --- Объявление глобальных переменных

HINSTANCE hInst; // Дескриптор экземпляра приложения

char ClassName[]="Window Class"; // Название класса окна

char AppTitle[]="Main Window"; // Заголовок главн. окна

// --- Главная функция приложения WinMain

int APIENTRY WinMain(HINSTANCE hInstance,

                HINSTANCE hPrevInstance,

                LPSTR lpCmdLine, int nCmdShow)

{

 WNDCLASS wc; // Структура для класса окна

 HWND hMainWnd; // Дескриптор главного окна прилож.

 MSG msg;   // Структура для хранения сообщения

 // --- Проверка, было ли приложение запущено ранее

 if((hMainWnd=FindWindow(ClassName, NULL))!=NULL)

 {

// Если прилож. было запущено ранее, активизировать

// и выдвинуть на передний план его главное окно

if(IsIconic(hMainWnd))

   ShowWindow(hMainWnd, SW_RESTORE);

SetForegroundWindow(hMainWnd);

// Работа новой копии прекращается

return FALSE;

 }

 hInst = hInstance; // Сохран. дескриптора экз. прилож.

 ZeroMemory(&wc, sizeof(wc)); // Очистка полей структуры

 // Заполнение полей стр-ры WNDCLASS

 wc.lpszClassName=ClassName; // Имя класса окон

 //Адрес оконной ф-ции

 wc.lpfnWndProc= (WNDPROC) MainWndProc;

 wc.style=CS_HREDRAW|CS_VREDRAW; // Стиль класса окон

 wc.hInstance=hInstance; // Экземпляр приложения

 // Пиктограмма для окон

 wc.hIcon=LoadIcon(NULL, IDI_APPLICATION);

 // Курсор мыши для окон

 wc.hCursor=LoadCursor(NULL, IDC_ARROW);

 // Кисть для окон

wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);  

 wc.lpszMenuName=NULL; // Ресурс меню окон

 wc.cbClsExtra=0;         // Дополнительная память класса

 wc.cbWndExtra=0;      // Дополнительная память окна

 // Pегистрация класса окна.

 RegisterClass(&wc);

 // Создание главного окна приложения.

 hMainWnd=CreateWindow(

           ClassName,          // Имя класса окон

           AppTitle,              // Заголовок окна

           WS_OVERLAPPEDWINDOW,   // Стиль окна

           CW_USEDEFAULT,                // X-координата

           CW_USEDEFAULT,                // Y-координата

           CW_USEDEFAULT,                // Ширина окна

           CW_USEDEFAULT,                // Высота окна

           NULL,          // Дескриптор окна-родителя

           NULL,          // Дескриптор меню окна

           hInst,          // Дескриптор экз. приложения

           NULL);         // Дополнительная информация

 if(!hMainWnd)

 {

 // Окно не создано, выдается сообщение.

 MessageBox(NULL,"Window create error", AppTitle,

   MB_OK|MB_ICONSTOP);

 return FALSE;

 }

 // Отображение окна и обновление его

 ShowWindow(hMainWnd, nCmdShow);

 UpdateWindow(hMainWnd);

 // Запуск цикла обработки очереди сообщений.

 while(GetMessage(&msg, NULL, 0, 0))

 {

// Преобразов. сообщений клавиатуры в символьные

TranslateMessage(&msg);

// Отправление сообщения оконной функции

DispatchMessage(&msg);

 }

return msg.wParam; // Завершение работы приложения

}

 

// --- Оконная функция главного окна

LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

 switch(uMsg)

 {

// Нажата левая кнопка мыши в клиентской обл. окна.

case WM_LBUTTONDOWN:

// Вывод информации о приложении с помощью

// диалогового окна сообщений MessageBox()

MessageBox(hWnd, "Windows Aplication", "MainWindow Message",MB_OK|MB_ICONINFORMATION);

 break;

// Пользователь удалил окно

case WM_DESTROY:

// Если это оконная функция главного окна, то в очередь

// сообщений посылается сообщение WM_QUIT

PostQuitMessage(0);

 break;

// Необработанные сообщения возвращаются в

// ОС с помощью функции DefWindowProc()

default:

return DefWindowProc(hWnd, uMsg, wParam, lParam);

}

return 0;

}

 

Обработка сообщения WM_DESTROY для разных

стилей окон

Сообщение WM_DESTROY указывает на необходимость удаления окна и поступает в оконную функцию, когда пользователь нажмет мышью на пиктограмме “Закрыть”, выберет пункт “ Закрыть ” из системного меню или нажмет комбинацию клавиш Alt+F4.

Главное окно стандартно реагирует на это сообщение, вызывая функцию:

PostQuitMessage(0);

которая посылает сообщение WM_QUIT в очередь сообщений приложения, что приводит к завершению цикла обработки сообщений и завершению работы программы.

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

DestroyWindow(hWnd);

которая удаляет окно с дескриптором hWnd.

 

Тема: Функции Win32 API для управления окнами и выдачи сообщений пользователям

Windows API содержит множество функций для поиска, определения состояния, перемещения окон, а также - для выдачи сообщений пользователям. Рассмотрим состав этих функций. Подробное описание функций приведено в файле "Ф-ции Win32 API для управл окнами и выдачи сообщ.doc".

 

1. Функции поиска и определения состояния окон

 

Функция Назначение
FindWindow() Производит поиск окна (не дочернего) с заданными классом и заголовком.
IsWindow() Определяет, существует ли окно для заданного де­скриптора.
IsIconic() Определяет, свернуто ли окно в пиктограмму.
IsWindowEnabled() Определяет, активно ли заданное окно.
IsWindowVisible() Определяет, видимо ли заданное окно.
IsZoomed() Определяет, является ли заданное окно распахнутым на весь экран.

 

2. Функции перемещения и получения параметров окон

 

Функция Назначение
MoveWindow() Перемещение и изменение размеров заданного окна.
SetForegroundWindow() Переводит заданное окно на передний план и акти­визирует его.
GetSystemMetrics() Получает системные метрики: габариты отображаемых элементов Windows и установки системной конфигурации.
GetWindowRect() Получает координаты обрамляющего окно прямоугольника.
GetClientRect() Получает координаты прямоугольника, об­рамляющего рабочую (клиентскую) область окна.

 

3. Сообщения приложения для пользователя

 

Функция Назначение
MessageBox() Создает и отображает диалоговое окно сообщения.
Beep() Генерирует звук заданной частоты и длительности, выводит его на системный динамик компьютера.
FlashWindow() Изменяет подсветку заданного окна.

 

Кроме вышеуказанных функций имеются и другие функции подобного назначения, которые описаны в справочной литературе и документации по Windows API.

 

Тема: Вывод в окно. Контексты устройств

 

Вывод в окно и его особенности

1. На протяжении всего выполнения Windows-приложения рисуют и перерисовывают содержимое своих окон в ответ на действия пользователя и другие события.

Windows следит за изменением расположения окон и при необходимости перерисовки окна посылает функции окна сообщение WM_PAINT. Функция окна при обработке это­го сообщения перерисовывает все окно или указанные части.

Windows-приложение обычно выводит информацию в рабочую (клиентскую) область окна.

2. Вывод информации осуществляется с помощью функций GDI (Graphics Device Interface - интерфейс графических устройств). Приложения, обращаясь к функциям GDI, работают не с физиче­скими устройствами вывода, а с логическими. GDI передает указания о выводе драйверу устройства вывода. Драйвер работает непо­средственно с физическим устройством и при управлении выводом учи­тывает его ограниченные возможности и аппаратные особенности. Бла­годаря этому приложения способны работать с любым устройством вывода, драйвер которого установлен в Windows.

3. Параметры вывода устанавливают в контексте устройства с помощью функций GDI. Контекст устройства (Device Context) - это структура данных Windows, которая содержит характеристики устройства вывода и указатели на вы­бранные инструменты рисования. Большинство функций GDI используют в качестве аргумента дескриптор контекста устройства (тип HDC).

 

Сообщение WM_PAINT

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

· Предварительно скрытая область окна открылась, когда пользователь передвинул окно или выполнил какие-то действия, в результате которых окно вновь стало видимым.

· Пользователь изменил размеры окна (и если в стиле класса окна были установлены биты CS_HREDRAW или CS_VREDRAW).

· Программа для прокрутки части рабочей области использовала функцию ScrollWindow() или ScrollDC().

· Программа информировала о необходимости перерисовки всего окна или его части при помощи функций InvalidateRect() или InvalidateRgn().

В некоторых случаях Windows всегда сохраняет перекрываемую область, а затем восстанавливает ее. Происходит это всегда, когда:

· Курсор мыши перемещается по рабочей области.

· Пиктограмму перемещают по рабочей области.

При работе с сообщением WM_PAINT необходимо учитывать следующее:

· Windows-программа должна быть построена таким образом, чтобы в ней рисование осуществлялось бы только “по запросу” – когда Windows отправит оконной процедуре сообщение WM_PAINT.

· Если же программе необходимо самой инициировать перерисовку своей рабочей области, она может заставить сгенерировать сообщение WM_PAINT (с помощью функций InvaldateRect() и UpdateWindow()).

 

Действительные и недействительные прямоугольники

При получении сообщения WM_PAINT часто бывает необходимо перерисовать не всю рабочую область окна, а только ее часть (обычно прямоугольную область).

Эту область называют недействительным регионом (invalid region) или регионом обновления (update region). Появление недействительного региона в рабочей области вынуждает Windows поместить сообщение WM_PAINT в очередь сообщений.

В Windows для каждого окна поддерживается структура информации о рисовании (тип PAINTSTRUCT).

Структура PAINTSTRUCT описана следующим образом:

typedef struct {   

HDC hdc;

BOOL fErase;

RECT rcPaint;

BOOL fRestore;

BOOL fIncUpdate;

BYTE rgbReserved[32]; } PAINTSTRUCT;

Назначение элементов структуры:

- hdc содержит дескриптор контекста устройства.

- rcPaint содержит ко­ординаты прямоугольной области обновления.

- fErase определяет необходимость стирания фона области обновления. Если fErase=TRUE, фон стирается, иначе фон не изменяется.

Остальные поля ис­пользует операционная система, приложение не должно изменять их со­держимое.

 

Функция InvalidateRect() добавляет прямоугольник в область перери­совки окна:

BOOL InvalidateRect( HWND hWnd, CONST RECT *lpRect, BOOL bErase);

Назначение параметров:

- hWnd указывает на обновляемое окно. Если он равен NULL, перерисовывают все окна.

- lpRect указыва­ет на нуждающийся в обновлении прямоугольник в рабочей области. Ес­ли lpRect=NULL, то нужно обновить всю рабочую область окна hWnd.

- bErase определяет, нужно ли перекрасить фон указанной пря­моугольной области. Если bErase=TRUE, фон перекрашивают, иначе фон остается неизменным.

В случае успешного выполнения функция возвращает ненулевое значение (TRUE).

Добавляемые прямоугольники накапливаются до обработки сообщения WM_PAINT. В качестве единой области перерисовки Windows вычисляет один прямоугольник, который охватывает все добавленные прямоугольники.

 

Функция ValidateRect() удаляет прямоугольную область из списка прямоугольников перерисовки:

BOOL ValidateRect( HWND hWnd, CONST RECT lpRect);

Параметр hWnd указывает на окно, из области перерисовки которого исключается прямоугольник. Если этот параметр равен NULL, Windows пере­рисовывает все окна - посылает сообщения WM_ERASEBKGND и WM_NCPAINT функциям всех окон.

Параметр lpRect указывает на прямо­угольник, который будет удален от области перерисовки. Если lpRect=NULL, из области обновления удаляют все прямоугольники.

В случае успешного выполнения функция возвращает ненулевое зна­чение (TRUE).

 

Получение контекста рабочей области окна

Приложения рисуют на устройствах вывода, используя контекст устройства.

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

В приложениях Windows обычно используют два метода получения дескриптора контекста рабочей области окна.

 

Первый метод используется при обработке сообщения WM_PAINT. Применяются две функции: BeginPaint() и EndPaint(). Для этих двух функций в качестве параметров требуются дескриптор окна и адрес переменной типа структуры PAINTSTRUCT.

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

case WM_PAINT:

PAINTSTRUCT ps; // Структура для рисования

// Получение дескрипт. контекста рабоч. области окна

HDC hDC = BeginPaint(hWnd, &ps);

. . . // Рисование в окне с использов. функций GDI

EndPaint(hWnd, &ps); // Освобожд. контекста уст-ва

break;

Вызов BeginPaint() заполняет поля этой структуры, а также возвращает дескриптор контекста рабочей области окна, который должен запоминаться в переменной типа HDC. Вызов функции EndPaint() освобождает дескриптор контекста рабочей области окна.

При обработке в оконной процедуре сообщения WM_PAINT вызовы функций BeginPaint() и EndPaint() должны обязательно производиться парой.

 

Второй метод используется, если необходимо рисовать в рабочей области окна при обработке отличных от WM_PAINT сообщений или для получения информации о самом контексте.

Для получения дескриптора контекста устройства в этих случаях необходимо вызвать функцию GetDC(), а для его освобождения – функцию ReleaseDC():

case СообщениеОтличноеОтWM_PAINT:

// Получ. дескриптора контекста рабочей области окна

HDC hDC = GetDC(hWnd);

. . . // Рисование в окне с использованием функций GDI

ReleaseDC(hWnd, hDC); // Освобожд. контекста уст-ва

break;

 

Функции GetDC() и ReleaseDC() также следует вызывать парой. Как правило, эти функции вызываются при обработке сообщений от клавиатуры или от манипулятора мышь, что позволяет обновлять рабочую область непосредственно в ответ на пользовательский ввод информации.

 

Виды контекстов устройств

Существуют следующие виды контекстов устройств:

- общий;

- для класса окон;

- личный;

- родительский;

- для окна;

- другие виды контекста.

 

Общий контекст (контекст рабочей области окна)

Этот контекст используется наиболее часто. Для получения общего контекста приложение должно вызывать функцию BeginPaint() или GetDC(). При этом при регистрации класса окна в поле стиля класса не должны использоваться значения CS_OWNDC, CS_PARENTDC, CS_CLASSDC.

Освобождение такого контекста производится при помощи функций BeginPaint() и ReleaseDC(), соответственно.

Каждый раз, когда приложение получает общий контекст, его атрибуты принимают значения по умолчанию. Поэтому для контекста такого типа настройку атрибутов нужно выполнять каждый раз после его получения.

 

Контекст класса окон

Такой контекст может использоваться всеми окнами, созданными на базе класса окна. При регистрации такого класса окна нужно указать стиль CS_CLASSDC.

В отличие от общего контекста приложение, однажды получив контекст для класса окна, может не освобождать его.

Контекст для класса окна можно использовать в тех случаях, когда нежелательно выполнять настройку многочисленных атрибутов после каждого вызова функции BeginPaint() (GetDC()). Эту настройку можно выполнить только один раз.

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

Личный контекст

Если в стиле класса окна указано значение CS_OWNDC, то для каждого окна, созданного на базе этого класса, Windows создаст отдельную структуру контекста.

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

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

 

Родительский контекст

Родительский контекст используется для дочерних окон. Он позволяет дочерним окнам “унаследовать” атрибуты контекста у родительского окна, что во многих случаях упрощает процедуру настройки этих атрибутов.

Для использования родительского контекста в классе, на базе которого создается дочернее окно, перед регистрацией необходимо указать стиль CS_PARENTDC.

 

Контекст окна

Все описанные выше контексты позволяют рисовать только во внутренней области окна.

С помощью функции GetWindowDC() приложение может получить контекст для окна, позволяющий рисовать в любом месте окна приложения. Приложение обязано освобождать этот контекст сразу же после использования, вызывая функцию ReleaseDC().

Особенностью данного контекста является то, что в нем выбрана система координат, начало которой находится в левом верхнем углу окна (не его внутренней области).

 

Кроме рассмотренных контекстов устройств есть ещё и другие, а именно:

- информационный;

- для памяти;

- метафайла;

- физического устройства;

- устройства DISPLAY.

Подробнее эти контексты описаны в литературе.

 

 

ТЕМА: Функции GDI для вывода текста в окно

Вывод текста

Функция TextOut() выводит символьную строку в указанной позиции окна, соблюдая выбранные атрибуты контекста устройства:

BOOL TextOut(HDC hdc, int nXStart, int nYStart, LPCSTR lpString, int cbString );

Параметры функции:

- hdc является дескриптором контекста окна, в котором будет выведена строка;

- nXStart и nYStart задают логические X и Y-координаты операции вывода;

- lpString указывает на строку, которая будет выведена;

- cbString равен количеству символов в выводимой строке.

Функция TextOut() не имеет параметров, определяющих шрифт, размер букв, цвет фона, цвет букв и т.д. Все эти характеристики текста задаются в структуре контекста устройства.

 


Дата добавления: 2019-09-13; просмотров: 690; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!