Простейший цикл обработки сообщений состоит из вызовов двух функций - GetMessage и DispatchMessage.

Абстракция данных

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

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

Пользователь не может использовать закрытые данные и методы. Реализуется с помощью ключевых слов: private, protected, internal.

Наследование

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

Полиморфизм (множественное наследование)

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

Инициализация (англ. initialization) — присвоение начальных значений полям объекта.

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

Обработка сообщений

Сообщение-это способ передачи информации приложению.

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

Контекст устройства

В программах Windows, прежде чем вывести что-либо на экран, необходимо получить контекст устройства, и весь вывод производить через него. Например, в Windows нет совершенно никакой возможности выводить точки прямо на экран, как это делалось в DOS. Контекст устройства - это достаточно условное название (даже для английского языка, device context), не отражающее сути понятия. На самом деле, это структура данных, обеспечивающая связь графических функций с драйвером конкретного устройства. Эта структура определяет состояние драйвера, и способ вывода графики.

Сообщение WM_PAINT

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

Сообщение WM_TIMER

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

Сообщение WM_DESTROY

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

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

WM_ACTIVATE - посылается, когда окно переводится в активное или неактивное состояние. Сначала сообщение посылается окну, переходящему в неактивное состояние, а потом - активируемому. Это сообщение имеет дополнительные параметры:

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

WM_COPYDATA - посылается, когда одно приложение передает данные другому приложению.

Посылка сообщений

Функция SendMessage посылает указанное в ней сообщение окну или множеству окон и не возвращается, пока это сообщение обрабатывается. Этим она отличается от функции PostMessage, которая возвращается сразу после передачи сообщения.

Обработка сообщений:

Откуда берутся сообщения?

Большинство сообщений создают драйверы устройств ввода/вывода, таких, как клавиатура, мышь или таймер. Драйверы создают сообщения при поступлении аппаратных прерываний. Например, когда вы нажимаете и затем отпускаете клавишу, драйвер обрабатывает прерывания от клавиатуры и создает несколько сообщений. Аналогично сообщения создаются при перемещении мыши или в том случае, когда вы нажимаете кнопки на корпусе мыши. Можно сказать, что драйверы устройств ввода/вывода транслируют аппаратные прерывания в сообщения.

Куда направляются сообщения, созданные драйверами?

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

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

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

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

Простейший цикл обработки сообщений состоит из вызовов двух функций - GetMessage и DispatchMessage.

Функция GetMessage предназначена для выборки сообщения из очереди приложения. Сообщение выбирается из очереди и записывается в область данных, принадлежащую приложению.

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

Вот как выглядит простейший вариант цикла обработки сообщений:

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

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

На нашем рисунке для простоты показано только одно приложение, в котором определена только одна функция окна. Реально же существует много приложений, и каждое приложение имеет несколько функций окна. Каждое приложение вызывает в цикле обработки сообщений функцию GetMessage, выбирая сообщения из своей очереди. Затем каждое приложение распределяет выбранное сообщение одной из своих функций окна, для чего используется функция DispatchMessage.

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

Сообщение с кодом WM_CREATE передается функции окна в момент создания окна. Функция окна при обработке этого сообщения выполняет инициализирующие действия (аналогично конструктору класса в языке C++). Коды сообщений определены в файле windows.h, включаемом в исходные тексты любых приложений Windows.

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

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

5) Дестру́ктор — специальный метод класса, служащий для деинициализации объекта (например освобождения памяти).

6) Конструктор класса— специальный блок инструкций, вызываемый при создании объекта

7) Программирование на С++

На С++ можно создавать приложения как для MS DOS, так и для Windows. Главное отличие языка С от С++ состоит в том, что С – процедурный, а С++ – объектно-ориентированный. Процедурное программирование – последовательный вызов команд-процедур обработки данных, а объектно-ориентированное программирование (ООП) – взаимодействие объектов.

Для Windows можно разрабатывать 16-ти и 32-разрядные приложения (программы).. Приложение пишется, затем компилируется компилятором (компиляция – получение исполняемого файла с расширением exe )

Общие положения программирования в среде Windows

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

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

Второй параметр (тип HINSTANCE, локальная переменная hPrevInstance) является дескриптором предыдущего экземпляра этого же приложения и используется только тогда, когда приложение запускается в нескольких экземплярах. Анализ этой переменной позволяет определить, является ли данный экземпляр приложения единственным.

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

Четвертый параметр (тип int, локальная переменная nCmdShow) характеризует режим запуска приложения (свернуто в иконку, имеет нормальный размер, развернуто на весь зкран).

В типичном Windows-приложении главная функция должна выполнять по меньшей мере три важнейших процедуры:

1. Зарегистрировать в системе Windows класс главного окна. Если помимо главного окна будут выводиться на экран внутренние, порожденные окна, то их классы тоже необходимо зарегистрировать. Windows выводит на экран и обслуживает только зарегистрированные окна.

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

3. Организовать цикл обработки сообщений, поступающих в приложение. Вся дальнейшая работа приложения будет состоять в бесконечном выполнении этого цикла и в обработке поступающих в приложение сообщений до тех пор, пока пользователь не подаст команду его завершения с помощью системного меню или вводом <Alt> + <F4>. Это приводит к завершению работы главной функции и удалению приложения из списка действующих задач Windows.

8) Для обработки других сообщений Windows (от мыши, пунктов меню, таймера и т.д.) в программе не­обходимо предусмотреть следующие элементы:

А)Объявление в классе главного окна таблицы откликов (макрос DECLARE_RESPONSE_TABLE)

Б)Саму таблицу откликов (макросы DEFINE_RESPONSE_TABLE1 и END_RESPONSE_TABLE, a
также помещаемые между ними макросы, определяющие конкретные сообщения)

В)Набор функций, обрабатывающих по заданным алгоритмам описанные в таблице откликов сооб­
щения Windows

9) Макросы - это препроцессорные "функции" , т.е. лексемы, созданные с помощью директивы #define, которые принимают параметры подобно функциям. После директивы #define указывается имя макроса, за которым в скобках (без пробелов) параметры, отделенные запятыми и определение макроса, отделенное пробелом.

10) Оператор new - позволяет вашим программам выделять память динамически во время выполнения.

При использовании оператора new программы указывают количество требуемой памяти. Если оператор new может успешно выделить требуемый объем памяти, он возвращает указатель на начало области выделенной памяти. Чтобы позже освободить память, распределенную с помощью оператора new, ваши программы должны использовать оператор C++ delete. Если вашей программе больше не нужна выделенная память, она должна ее освободить, используя оператор delete.

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

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

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

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

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

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

Наши рекомендации