47816 (597361), страница 6

Файл №597361 47816 (Ознакомление с приложениями Windows) 6 страница47816 (597361) страница 62016-07-30СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 6)

Рисунок 4. Обработка посланных сообщений в Windows

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

Этот процесс называется посылкой (post) сообщений, так как посылка сообщения напоминает посылку письма: посылающий сообщение указывает адресата, отправляет сообщение и больше о нем не беспокоится. Отправитель не знает, когда точно его сообщение получит адресат. Такой способ обработки сообщений часто называется асинхронным.

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

  • сообщение выбирается из очереди с помощью функции GetMessage или PeekMessage

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

  • и только после этого оно направляется окну с помощью функции DispatchMessage (это называется диспетчеризацией)

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

MSG msg;

while ( GetMessage( &msg, NULL, NULL, NULL ) ) {
TranslateMessage( &msg );
DispatchMessage( &msg );
}

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

BOOL GetMessage( lpMsg, hWnd, uMsgFilterMin, uMsgFilterMax );

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

Какие же данные передаются одним сообщением?

typedef struct tagMSG {
HWND hwnd; // хендл окна-получателя
UINT message; // номер сообщения WM_...
WPARAM wParam; // параметр сообщения
LPARAM lParam; // параметр сообщения
DWORD time; // время поступления сообщения
POINT pt; // координаты сообщения (для сообщений мыши)
} MSG;

Поле message структуры MSG задает номер сообщения, посланного системой. Интерпретация параметров сообщения wParam и lParam зависит от самого сообщения. Для этого надо смотреть описание конкретного сообщения и обрабатывать параметры соответствующим образом. Так как в системе определено огромное количество разных сообщений, то для простоты использования применяются символические имена сообщений, задаваемыми с помощью #define в заголовочном файле. В качестве примера можно привести сообщения WM_CREATE, WM_PAINT, WM_QUIT.

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

uMsgFilterMin и uMsgFilterMax обычно установлены в NULL. Вообще они задают фильтр для сообщений. GetMessage выбирает из очереди сообщения, номера (имена) которых лежат в интервале от uMsgFilterMin до uMsgFilterMax. Нулевые значения исключают фильтрацию.

Функция GetMessage возвращает во всех случаях, кроме одного, ненулевое значение, указывающее, что цикл надо продолжать. Только в одном случае эта функция возвратит 0 — если она извлечет из очереди сообщение WM_QUIT. Это сообщение посылается только при окончании работы приложения.

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

И остается еще одно дело: так как WinMain возвращает результат, то мы должны вернуть какое–либо значение. В Windows принято, что возвращаемое значение является параметром wParam сообщения WM_QUIT, завершившего цикл обработки сообщений. Таким образом мы пишем:

return msg.wParam;

Оконная процедура

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

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

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

LRESULT WINAPI _export proc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
// ...
}

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

LRESULT WINAPI _export proc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
// описание внутренних переменных

switch ( uMsg ) {
case WM_...:
// обработка нужного сообщения
break;

// обработка других сообщений...

default:
return DefWindowProc( hWnd, uMsg, wParam, lParam );
}
return 0L;
}

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

Для упрощения написания оконной функции Windows предлагает специальную функцию

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

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

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

Сообщение WM_CREATE

Самым первым мы рассмотрим сообщение WM_CREATE. Это сообщение посылается окну в тот момент, когда оно создается. Реальным созданием окна ведает функция CreateWindow, а не обработчик сообщения WM_CREATE. Вы в этот момент должны инициализировать свои переменные, выполнить необходимые настройки, создать требуемые объекты и прочее. При создании окно еще невидимо — поэтому Вы можете менять его размеры, устанавливать в нужное положение, менять цвета не опасаясь мелькания на экране. Часто здесь создаются необходимые структуры и выделяются требуемые окном ресурсы.

Стандартная обработка этого сообщения необязательна — функция DefWindowProc просто возвращает 0 в ответ на это сообщение.

Параметр wParam не используется, а параметр lParam содержит указатель11 на структуру CREATESTRUCT. В этой структуре передается основная информация о создаваемом окне.

typedef struct tagCREATESTRUCT {
void FAR* lpCreateParams; // указатель на дополнительные данные,
// переданный как параметр lpParam в вызове
// функции CreateWindow или CreateWindowEx
HINSTANCE hInstance; // хендл копии приложения, создавшей окно
HMENU hMenu; // хендл меню (или NULL, если нет)
HWND hwndParent; // хендл родительского окна (или NULL)
int cy, cx; // размеры окна
int y, x; // положение окна
LONG style; // стили окна
LPCSTR lpszName; // заголовок окна
LPCSTR lpszClass; // имя класса, к которому принадлежит окно
DWORD dwExStyle; // расширенные стили окна (см. CreateWindowEx)
} CREATESTRUCT;

Поля x, y, cx и cy в момент обработки сообщения WM_CREATE могут быть еще не определены. При необходимости получить информацию о размере или положении окна надо пользоваться функциями GetWindowRect или GetClientRect, которые возвращают корректный результат

Возвращаемое обработчиком значение:

не 0 — возникла ошибка, окно надо уничтожить (далее, при уничтожении, будет получено сообщение WM_DESTROY), функция CreateWindow или CreateWindowEx вернет NULL.

0 — окно успешно создано; функция CreateWindow или CreateWindowEx вернет хендл окна.

Сообщения WM_DESTROY и WM_QUIT

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

Как и WM_CREATE сообщение WM_DESTROY является информационным — реальное уничтожение окна осуществляется функцией DestroyWindow, а не обработчиком сообщения WM_DESTROY. Независимо от способа обработки этого сообщения окно будет уничтожено.

Если ваша оконная функция обслуживает главное окно приложения, то в момент уничтожения окна вы должны принять меры для завершения работы всего приложения в целом. Для этого вы должны послать сообщение WM_QUIT, при извлечении которого из очереди закончится цикл обработки сообщений. Если этого сообщения не послать, то цикл обработки сообщений продолжит работу дальше после закрытия всех имеющихся окон. На практике это означает что приложение вообще перестанет получать сообщения и “зависнет” на функции GetMessage, которая будет ждать, пока не придет новое сообщение. В случае Windows 3.x есть единственный способ удалить такое приложение — перезапуск всего Windows (в Windows–95 или Windows NT такое приложение можно снять самому с помощью менеджера задач). Сообщение WM_QUIT посылается с помощью функции:

void PostQuitMessage( nExitCode );

Параметр nExitCode будет передан как wParam сообщения WM_QUIT и позже возвращен функцией WinMain в качестве параметра завершения.

Обработчиков для сообщения WM_QUIT писать не надо, так как:

Во–первых, функция GetMessage, получив это сообщение просто вернет FALSE, так что цикл обработки сообщений будет закончен без трансляции и диспетчеризации этого сообщения.

Во–вторых, это сообщение адресовано не окну, а приложению. То есть, даже если воспользоваться функцией PeekMessage для извлечения сообщения WM_QUIT из очереди (в отличие от GetMessage это получится), оно не будет отправлено никакому окну, так как хендл окна–получателя равен NULL.


Сообщение WM_PAINT

Последнее рассматриваемое нами сообщение — WM_PAINT. Оба параметра сообщения WM_PAINT не используются. С этим сообщением нам придется разбираться подробнее. Раньше, когда мы обсуждали разделение экрана между разными задачами, говорилось о том, что в Windows невозможно полностью виртуализовать всю работу с экраном — то есть содержимое невидимой в данной момент части окна для Windows остается неизвестным.

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

Для этого вводится специальное сообщение WM_PAINT, которое посылается окну тогда, когда часть окна (или все окно) нуждается в перерисовке. Часто перерисовка окна занимает значительное время, а обработку сообщений рекомендуется выполнять как можно быстрее; поэтому Windows особым образом обрабатывает WM_PAINT, что бы задержки в обработке этого сообщения не оказывали такого влияния на работу системы.

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

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


Основы рисования в окне

Еще раз вспомним, каким образом появляется сообщение WM_PAINT: это происходит когда все окно, или только его часть становятся видимыми. Та часть окна, которая нуждается в перерисовке, является неверной — ее содержимое не соответствует требуемому. Эта часть получила название неверный прямоугольник (invalid rectangle).

Соответственно, после перерисовки она перестает быть неверной — то есть становится верным прямоугольником (valid rectangle).

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

Характеристики

Тип файла
Документ
Размер
2,36 Mb
Тип материала
Учебное заведение
Неизвестно

Список файлов книги

Свежие статьи
Популярно сейчас
Как Вы думаете, сколько людей до Вас делали точно такое же задание? 99% студентов выполняют точно такие же задания, как и их предшественники год назад. Найдите нужный учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
7029
Авторов
на СтудИзбе
260
Средний доход
с одного платного файла
Обучение Подробнее