ПРИЛОЖЕНИЕ 2.
Основные типы сообщений Windows
В настоящее время в системе Windows имеется более 900 стандартных сообщений. К счастью, нет необходимости знакомиться со всеми, поскольку большинство из них используются очень редко. Например, большое количество сообщений характерно для одного типа окна. Другие сообщения играют особую роль в совместном использовании данных или реализации стандарта многодокументного интерфейса (MDI). Третьи проходят по нашему циклу сообщений, но никогда не используются. Это внутренние сообщения, которые Windows создает для своих собственных целей. Все сообщения имеют имена, которые определены в файле <winuser.h> следующим образом:
#define WM_COMMAND 0x0lll
ИЛИ
#define WM_PAINT 0x000F
Префикс WM_ говорит о том, что речь идет об "оконном сообщении" (от Window Message). Эти символические имена обозначают числовые значения. Кроме WM_ широко используются и другие префиксы: ЕМ_ (Edit Message) — для сообщений элемента управления Edit, BM_ (Button Message) — для сообщений элемента управления Button, LM_ (Listbox Message) — для сообщений элемента управления Listbox и т. д. Помимо этого, вы можете создавать и собственные сообщения.
Чтобы как-то систематизировать такое огромное количество сообщений, я разделил их на следующие категории:
Аппаратные
Входные данные от мыши и клавиатуры
Организация окна
Уведомление, требование действия, запрос
Организация интерфейса пользователя
Меню, указатель мыши, линейка прокрутки, пользователя блоки диалога, MDI.
Завершение работы
Закрытие прикладной программы или системы
Частные
Элементы управления: кнопка, редактор и т. д.
Уведомление о системном ресурсе
Изменение цвета, шрифтов, буферизация печати, ресурсе режимы работы устройства
Обмен данными
Буфер обмена и динамический обмен данными
Внутрисистемные
Недокументированные сообщения
Оконная процедура получает сообщения, инициируемые тремя частями аппаратного обеспечения: клавиатурой, мышью и системным таймером. Все они генерируют аппаратные прерывания. Поскольку диспетчеризация Windows не действует в режиме прерываний, аппаратные события должны быть буферизованы. Это обеспечивает обработку событий в порядке их поступления. Например, когда вы нажимаете клавишу <К>, прерывание уведомляет систему о том, что приготовлены данные от клавиатуры. Драйвер клавиатуры отыскивает эти данные и создает элемент в первичной очереди, откуда система их передает в очередь приложения, а точнее, конкретного потока. Когда наступает его очередь, сообщения, содержащие информацию о клавише <К>, направляются в соответствующую оконную процедуру. Сообщения от мыши и системного таймера обрабатываются аналогично. В табл. П2.1— П2.4 представлены основные сообщения, которые формируются в ответ на работу аппаратного обеспечения.
Таблица П2.1. Сообщения от мыши в клиентской области окна
WM_LBUTTONDBLCLK WM_LBUTTONDOWN WM_LBUTTONUP WM_MBUTTONDBLCLK WM_MBUTTONDOWN WM_MBUTTONUP WM_MOUSEMOVE WM_RBUTTONDBLCLK WM_RBUTTONDOWN WM_RBUTTONUP |
Двойное нажатие левой кнопки Нажатие левой кнопки Отпускание левой кнопки Двойное нажатие средней кнопки Нажатие средней кнопки Отпускание средней кнопки Перемещение мыши Двойное нажатие правой кнопки Нажатие правой кнопки Отпускание правой кнопки |
Таблица П2.2. Сообщения от мыши в неклиентской области окна
WM_NCLBUTTONDBLCLK WM_NCLBUTTONDOWN |
Двойное нажатие левой кнопки Нажатие левой кнопки |
WM_NCLBUTTONUP WM_NCMBUTTONDBLCLK WM_NCMBUTTONDOWN WM_NCMBUTTONUP WM_NCMOUSEMOVE WM_NCRBUTTONDBLCLK WM_NCRBUTTONDOWN WM_NCRBUTTONUP |
Отпускание левой кнопки Двойное нажатие средней кнопки Нажатие средней кнопки Отпускание средней кнопки Перемещение мыши Двойное нажатие правой кнопки Нажатие правой кнопки Отпускание правой кнопки |
Таблица П2.3. Сообщения от клавиатуры
WM_CHAR WM_DEADCHAR WM_KEYDOWN WM_KEYUP WM_SYSCHAR WM_SYSDEADCHAR WM_SYSKEYDOWN WM_SYSKEYUP |
Ввод символа Диакритический знак (умляут, ударение и т. д.) Была нажата клавиша Была отпущена клавиша Ввод специального символа Специальный диакритический знак Была нажата специальная клавиша Была отпущена специальная клавиша |
Таблица П2.4. Сообщения от таймера
WMJTIMER |
Истекло заданное время |
Сообщения от таймера помешаются в очередь так же, как и сообщения от мыши и клавиатуры (т. е. таймеры в системе Windows не являются точными).
Сообщение WM_MOUSEMOVE заслуживает особого упоминания, т. к. обрабатывается особым образом, чтобы избежать переполнения очереди аппаратных событий. Дело в том, что при быстром перемещении мыши могут произойти сотни прерываний. Во избежание переполнения очереди система Windows хранит только одно сообщение о перемещении мыши в каждый момент времени. Когда приходит новое сообщение, Windows проверяет, есть ли уже подобное. Если оно есть, то в нем обновляется информация о положении. Новое сообщение помешается в очередь сообщений только в том случае, если сообщения о перемещении мыши еще не было.
Сообщения от клавиатуры делятся на два основных типа: обычные и системные. Обычно системные сообщения от клавиатуры (начинающиеся на WM_SYS...) игнорируются, т. к. оконная процедура, устанавливаемая по умолчанию, превращает их в соответствующую системную команду.
Здесь собраны наиболее часто используемые сообщения, и вам следует хорошенько разобраться с каждым из них. К сожалению, имена не окажут вам большой помощи. Начнем с того, что сообщения этой группы можно разбить на три части: уведомление, требование действия и запрос (табл. П2.5— П2.7).
Таблица П2.5. Оконные сообщения: уведомление
WM_ACTIVATE WM_ACTIVATEAPP WMJDREATE WM_DESTROY WM_ENABLE WM_KILLFOCUS WM_MOUSEACTIVATE WM_MOVE WM_SETFOCUS WM_S1ZE |
Окно активно Приложение активно Окно было создано Окно было уничтожено Был разрешен ввод в окно Окно потеряло фокус ввода от клавиатуры Окно станет активным после нажатия кнопки мыши Окно было перемещено Окно получило фокус ввода от клавиатуры Окно изменило размер |
Таблица П2.6. Оконные сообщения; требование действия
WM_CLOSE WM_ERASEBKGND WMJCONERASEBKGND WM_NCACTIVATE WM_NCCREATE WM_NCDESTROY WM_NCPAINT |
Закрыть (уничтожить) окно Удалить фон Удалить фон окна, показываемого в виде пиктограммы Изменить заголовок окна для показа активного состояния Создать неклиентскую область окна Уничтожить неклиентскую область окна Перерисовать неклиентскую область |
WM_PAINT WM_PAINTICON WM_SETREDRAW WM_SETTEXT WM_SHOWWINDOW |
Перерисовать клиентскую область Перерисовать клиентскую область окна, показываемого в виде пиктограммы Запретить перерисовку окна Изменить текст окна Изменить режим отображения окна |
Таблица П2.7. Оконные сообщения: запросы
WM_GETMINMAXINFO
WM_GETTEXT
WM_GETTEXTLINGTH WM_NCCALCSIZE WM_QUERYNEWPALETTE WM_QUERYOPEN |
Запрос информации о минимальном/максимальном размере окна Запрос текста заголовка окна, а для окон, не имеющих заголовка (например, для кнопок) — текста, размещенного в окне Запрос длины текста окна Запрос размеров клиентской области Запрос существования новой палитры Запрос возможности открытия окна, отображаемого в виде пиктограммы |
Сообщение-уведомление говорит оконной процедуре о том, что состояние окна было изменено. При этом оконная процедура вовсе не должна выполнять действие, обозначенное именем сообщения. Например, сообщение WM_MOVE не является запросом на некоторое перемещение. Наоборот, оно является "сообщением после действия" и напоминает, что окно уже было перемещено. Обратите внимание, что из сообщения не ясно, каким образом произошло перемещение. Это могло быть результатом действий пользователя, равно как и другой программы. В любом случае сообщения-уведомления представляют собой одностороннюю связь с оконной процедурой.
Сообщение-требование действия говорит само за себя, т. к. отсутствие необходимого действия вызывает ошибку в интерфейсе пользователя. Например, сообщение WM_PAINT посылается оконной процедуре, если окно необходимо перерисовать (обновить) из-за изменения данных, связанных с окном, или в результате активизации и перевода окна на передний план из-за другого окна. Если оконная процедура не перерисует окно, то его "видимое" содержимое не будет актуальным. Обычно устанавливаемая по умолчанию оконная процедура обеспечивает некоторые необходимые минимальные действия, однако зачастую следует перехватывать и обрабатывать такого
рода сообщения самому, как в случае с сообщением WM_PAINT. При этом нередко нужно воспроизвести все действия обработчика, устанавливаемого по умолчанию.
Сообщения-запросы требуют ответа. Они используются для двусторонней связи между Windows и вашей программой. Подобно сообщениям-требованиям действия, оконная процедура, устанавливаемая по умолчанию, даст приемлемый ответ в большинстве случаев. Сообщения-запросы следует перехватывать, если вы хотите изменить ответ по умолчанию. Например, сообщение WM_QUERYOPEN вы получите, когда пользователь попытается открыть минимизированное окно. Если вы хотите, чтобы программа выполнялась только тогда, когда окно отображается в виде пиктограммы, то нужно просто ответить FALSE вместо TRUE, установленного по умолчанию.
Сообщения об организации интерфейса пользователя
Эта группа содержит сообщения для других объектов пользовательского интерфейса, включающих меню прикладной программы, указатель мыши, линейки прокрутки, блоки диалога и их элементы управления, а также сообщения, используемые для поддержки многодокументного интерфейса (MDI). Основные сообщения приводятся в табл. П2.8—П2.13.
Таблица П2.8. Сообщения от меню
WM_COMMAND WMJNITMENU WM_INITMENUPOPUP
WM_MENUCHAR WM_MENUSELECT |
Был выбран пункт меню Уведомление о возможности изменить меню перед его активизацией Уведомление о возможности изменить пункты всплывающего меню перед его отображением на экране Для выбора меню использована мнемоническая клавиша Пользователь просматривает меню |
Таблица П2.9. Системные команды
WM_SYSCOMMAND |
Была выбрана системная команда |
Таблица П2.10. Сообщения от указателя мыши
WM_NCHITTEST WM_SETCURSOR |
Передача в окно текущего положения указателя мыши Уведомление окну при перемещении мыши с возможностью изменить курсор в зависимости от положения указателя |
Таблица П2.11. Сообщения линейки прокрутки
WMJHSCROLL WM_VSCROLL |
Была нажата горизонтальная линейка прокрутки Была нажата вертикальная линейка прокрутки |
Таблица П2.12. Сообщения блока диалога и его элементов управления
WM_COMMAND WM_COMPAREITEM WM_CTLCOLOR WM_DELETEITEM
WM_DRAWITEM WM_GETDLGCODE
WM_GETFONT WM_INITDIALOG WM_MEASUREITEM WM_SETFONT |
Управляющая связь с блоком диалога Посылается родителю с запросом на сравнение двух элементов для сортировки Управляющий запрос на установку цветов Уведомление, направляемое элементам управления Listbox и Combobox.o том, что удален элемент Запрос родителю пользовательских элемента управления и меню на рисование Запрос оконной процедуре, какие типы сообщений будут ею впоследствии обрабатываться Запрос дескриптора основного шрифта отображения Запрос на инициализацию диалогового окна Запрос родителю элемента управления на обеспечение его размеров при прорисовке Требование к элементу управления: использовать данный шрифт |
Таблица П2.13. Сообщения многодокументного интерфейса (MDI)
WM_CHILDACTIVATE WM_MDIACTIVATE WM_MDICASCADE WM_MDICREATE WM_MDIGETACTIVE WM_MDIICONARRANGE |
Объявляет порождающему окну об активизации дочернего окна Объявляет дочернему окну MDI, что оно получает или теряет активизацию Требование оформить дочерние окна MDI в каскадной (ступенчатой) форме Требование окну клиента MDI создать дочернее окно Запрос окна клиента MDI о текущем активном дочернем окне Требование упорядочить расположение дочерних окон MDI, отображаемых в виде пиктограмм |
WM_MDIMAXIMIZE WM_MDINEXT WM_MDIRESTORE WM_MDISETMENU WM_MDITITLE |
Требование максимизировать дочерние окна MDI Требование активизировать следующее дочернее окно MDI Требование восстановить дочернее окно MDI в его предыдущем состоянии Настраивает меню для текущего дочернего окна MDI Требование оформить дочерние окна MDI в форме черепичного (без перекрытий) расположения |
Эта группа сообщений самая малочисленная, но все они очень важны, т. к. используются для управления завершением приложений (табл. П2.14)
Таблица П2.14. Завершение работы приложения и системы
WM_QUIT WM_QUERYENDSESSION WM_ENDSESSION
|
Требование на завершение приложения Запрос готовности приложения к завершению работы всей системы Уведомление о результатах запроса на завершение работы системы |
Очень просто определить собственные сообщения и использовать их для связи между различными окнами, которые вы создаете. При определении частного сообщения необходимо использовать область значений, начинающуюся с WM_USER, которая определена в <winuser.h> следующим образом:
#define WM_USER 0x0400
Например, если мы хотим работать с окнами, которые показывают числа, то могли бы контролировать появление чисел различных систем счисления с помощью следующих частных сообщений (РМ_ — префикс "частного сообщения" от Private Message):
#define PM_DECIMAL WM__USER + 0
#define PM_BINARY WM_USER + 1
#define PM_HEX WM_USER + 2
#define PM_OCTAL WMJJSER + 3
Кроме того, есть несколько частных системных сообщений (табл. П2.15).
Таблица П2.15. Частные системные сообщения
WM_CANCELMODE WM_ENTERIDLE |
Требование системы отменить режим, например, захват мыши Сообщает, что система находится в режиме ожидания |
Информационные сообщения системных ресурсов
Имеется всего восемь сообщений с уведомлением об изменении некоторых системных ресурсов (табл. П2.16). Они посылаются окну верхнего уровня каждой программы при изменении системного ресурса. Например, когда добавляются или удаляются шрифты в системе, распространяется сообщение WM_FONTCHANGE. А когда пользователь изменяет системные цвета или системное время, отправляются сообщения WM_SYSCOLORCHANGE или WM_TIMECHANGE, соответственно. Типичной реакцией на часть такого рода сообщений является немедленная запись произведенных изменений, т. е. сохранение выполненной работы. Судите сами.
Таблица П2.16. Сообщения с уведомлением об изменениях системных ресурсов
WM_COMPACTING WM_DEVMODECHANGE WM_FONTCHANGE WM_PALETTECHANGED WM_SPOOLERSTATUS WM_SYSCOLORCHANGE WM_TIMECHANGE WM_WININICHANGE |
Недостаточно системной памяти Изменилась настройка принтера Изменились установленные в системе шрифты Палитра аппаратных цветов изменена Задание было удалено из очереди буфера печати Один или более системных цветов изменены Изменилось системное время Изменился файл инициализации <win.ini> |
Не всякое изменение представляет интерес для каждой программы. Например, программа, использующая таймер, вероятно, будет проверять новое значение времени при получении сообщения WM_TIMECHANGE. Но если она не работает со шрифтами, то, скорей всего, сообщение WM_FONTCHANGE будет проигнорировано. Поскольку большинство программ использует системные цвета, то они будут реагировать на сообщение WM_SYSCOLORCHANGE, организуя перерисовывание новыми цветами.
Сообщения о совместном использовании данных
В Windows есть сообщения, которые посылаются при совместном использовании данных для поддержки механизмов работы с буфером обмена (clipboard) и динамического обмена данными (DDE), которые определены в файлах <winuser.h> и <dde.h>, соответственно. И хотя полное обсуждение этого вопроса выходит за рамки книги, мы приведем список сообщений этой группы (табл. П2.17—П2.18).
Таблица П2.17. Сообщения от буфера обмена
WM_ASKCBFORMATNAME WM_CNANGECBCHAIN WM_DESTRIYCLIPBOARD WM_DRAWCLIPBOARD WM_HSCROLLCLIPBOARD WM_PAINTCLIPBOARD WM_RENDERALLFORMATS WM_RENDERFORMAT WM_SIZECLIPBOARD WM_VSCROLLCLIPBOARD |
Запрашивает имя формата буфера обмена Уведомление об изменении цепочки просмотра Содержимое буфера обмена уничтожено Содержимое буфера обмена изменено Горизонтальная прокрутка буфера обмена Запрашивает рисование буфера обмена Запрашивает данные для всех ранее объявленных форматов буфера обмена Запрашивает данные для ранее объявленного формата буфера обмена Размер буфера обмена изменен Вертикальная прокрутка буфера обмена |
Таблица П2.18. Сообщения DDE
WM_DDE_ACK WM_DDE_ADVISE WM_DDE_DATA WM_DDE_EXECUTE WM_DDE_INITIATE |
Подтверждение приема Запрос от пользователя DDE об установлении постоянного канала передачи данных Направляет элемент данных от DDE-сервера клиенту DDE Дает указание DDE-серверу выполнить серию команд Вход в DDE-сервер |
WM_DDE_POKE WM_DDE_REQUEST WM_DDE_TERMINATE WM_DDE_INADVISE |
Запрос пользователя серверу об обновлении определенного элемента данных Однократный запрос пользователя на информацию
Выход из DDE-сервера Завершить постоянный канал передачи данных, инициализированный сообщением WM_DDE_ADVISE |
Помимо перечисленных, имеется большая группа сообщений, не описанных ни в какой документации. ,Это внутренние системные сообщения, которые Windows использует в своих собственных целях. Эти сообщения передаются оконной процедуре, и если она их не обработает, то направляются обработчику сообщений, устанавливаемому по умолчанию.
В принципе ничто не мешает вам использовать эти сообщения в собственных целях. Но будьте осторожны! В будущих версиях Windows может измениться способ использования этих сообщений, а некоторые могут быть вообще удалены. Исходя из своего опыта, могу сказать, что недокументированные возможности интересно изучать, но опасно использовать в программных продуктах, предназначенных для широкого распространения.