Сообщения Windows (типы сообщений, принципы работы системы сообщений Windows, система сообщений Delphi, специализированные записи, обработка сообщений)

 

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

Сообщение Windows – это извещение о некотором имевшем место событии, посылаемое Windows в адрес приложения. Любые действия пользователя – щелчок мышью, изменение размеров окна приложения, нажатие клавиши на клавиатуре – вынуждают Windows отправить приложению сообщение, извещающее о том, что же произошло в системе. Сообщение представляет собой запись, объявленную в модуле Windows следующим образом:

type

TMsg = packed record

hwnd: HWND; // дескриптор окна-получателя

message: UINT; // идентификатор сообщения

wParam: WPARAM; // 32 бита дополнительной информации

lParam: LPARAM; // еще 32 бита дополнительной информации

time: DWORD; // время создания сообщения

pt: TPoint; // положение указателя мыши в момент создания сообщения

end;

 

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

Каждому сообщению Windows поставлено в соответствие определенное числовое значение, которое заносится в поле message записи TMsg. В Delphi эти величины, идентифицирующие сообщения определены в модуле Messages. Имя каждой константы начинается с символов WM (Windows Message). Примеры некоторых сообщений приведены в таблице.

Идентификатор сообщения Значение Описание
WM_ACTIVATE $0006 Окно активируется или деактивируется. Что именно происходит, определяется младшим словом wParam (LOWORD(wParam)). Старшее слово содержит значение типа BOOL, которое содержит значение True, если окно минимизируется. Поле lParam содержит дескриптор окна, которое будет деактивировано, когда наше окно активируется или дескриптор окна, которое будет активировано, если наше окно деактивируется
WM KEYDOWN $0100 На клавиатуре была нажата клавиша
WM KEYUP $0101 На клавиатуре была отпущена клавиша
WM PAINT $000F Требуется перерисовать клиентскую часть окна
WM CLOSE $0010 Окно должно быть закрыто
WM_QUIT $0012 Приложение должно быть завершено

Какие для каждого события данные содержатся в wParam и lParam догадаться невозможно и надо узнавать в справочной системе или в литературе.

 

Принципы работы системы сообщений Windows

Система сообщений Windows состоит из трех составляющих:

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

2. Цикл сообщений. Группа операторов, осуществляющая выборку сообщения из очереди и передачу его соответствующему окну для обработки.

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

Цикл сообщений встроен в модуль Forms, благодаря чему прикладному программисту не нужно беспокоиться о выборке сообщений из очереди и передаче их соответствующим процедурам окон. Кроме того, Delphi помещает информацию из записи типа TMsg в собственную запись типа TMessage.

type

TMessage = packed record

Msg: Cardinal;

case Integer of

0: (WParam: Longint;

LParam: Longint;

Result: Longint);

1: (WParamLo: Word;

WParamHi: Word;

LParamLo: Word;

LParamHi: Word;

ResultLo: Word;

ResultHi: Word);

end;

Эта запись содержит меньше информации, чем в исходной записи TMsg. Кроме того, в TMessage содержится поле Result, которое используется для возврата результата обработки сообщения.

 

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

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

Сообщение в Delphi может быть обработано четырьмя способами.

1. С помощью процедуры обработки сообщения.

2. В методе WndProc.

3. В методе Dispatch.

4. С помощью обработки события OnMessage объекта Application.

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

• Должна быть методом.

• Должна иметь один var-параметр типа TMessage или любого специализированного типа.

• В конце объявления содержится ключевое слово message и константа, задающая тип обрабатываемого сообщения.

Пример процедуры, обрабатывающей сообщение WM_PAINT:

procedure WMPaint(var Msg: TWMPaint); message WM_PAINT;

2. В классе TControl имеется виртуальный метод WndProc:

procedure WndProc(var Message: TMessage); virtual;

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

3. У класса TObject существует виртуальный метод Dispatch:

procedure Dispatch(var Message); virtual;

Этот метод также можно перекрыть у класса-потомка, чтобы обработать одно или несколько сообщений.

4. Последний способ – использовать событие OnMessage объекта Application.

// фрагмент модуля Forms:

type

TMessageEvent = procedure (var Msg: TMsg; var Handled: Boolean) of object;

...

TApplication = class(TComponent)

...

property OnMessage: TMessageEvent read FOnMessage write FOnMessage;

...

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

 

Специализированные записи

В дополнение к обычной записи типа TMessage в Delphi определен набор специализированных записей для всех типов сообщений Windows. Они предназначены для работы с дополнительными данными сообщений без необходимости декодировать значения полей wParam и lParam.

Названия этих типов соответствуют типу сообщения, для которого они предназначены (начинаются с буквы T, и в имени нет символа подчеркивания). Для примера ниже приведено определение записи для события WM_ACTIVATE.

// фрагмент модуля Windows:

const

{ WM_ACTIVATE state values }

WA_INACTIVE = 0;

WA_ACTIVE = 1;

WA_CLICKACTIVE = 2;

 

// фрагмент модуля Messages:

type

TWMActivate = packed record

Msg: Cardinal;

Active: Word; // WA_INACTIVE, WA_ACTIVE, WA_CLICKACTIVE

Minimized: WordBool;

ActiveWindow: HWND;

Result: Longint;

end;