В классе TWinControl
метод DefaultHandler
также переопределен. Помимо передачи некоторых сообщений дочерним окнам (об этом мы будем подробнее говорить чуть позже) и обработки некоторых внутренних сообщений он вызывает оконную процедуру, адрес которой хранится в свойстве DefWndProc
. Это свойство содержит адрес, который был присвоен полю WindowClass.lpfnWndProc
структуры TCreateParams
в методе CreateParams
. По умолчанию это поле содержит адрес стандартной оконной процедуры DefWindowProc
. Как было сказано ранее, обработка сообщений при использовании API обычно завершается вызовом этой процедуры. В классе TCustomForm
метод DefaultHandler
также переопределен, если форма является MDI-формой, сообщения, присланные ей, передаются в процедуру DefFrameProc
(за исключением WM_SIZE
, которое передается в DefWindowProc
) независимо от того, какое значение имеет свойство DefWindowProc
. Для всех остальных типов форм вызывается унаследованный от TWinControl DefaultHandler
.
Повторим еще раз всю цепочку обработки сообщений оконными компонентами VCL (рис. 1.7). Для каждого компонента создается уникальная оконная процедура, которая передает управление методу MainWndProc
. MainWndProc
передает управление методу, указатель на который хранится в свойстве WindowProc
. По умолчанию это метод компонента WndProc
. Он осуществляет обработку некоторых сообщений, но в большинстве случаев передает управление методу Dispatch
, который ищет среди методов компонента или его предков обработчик данного сообщения. Если обработчик не найден, управление получает метод DefaultHandler
(он может также получить управление и в том случае, если обработчик найден, но он вызывает inherited
). DefaultHandler
самостоятельно обрабатывает некоторые сообщения, но большинство из них передаётся оконной процедуре, адрес хранится в свойстве DefWndProc
(по умолчанию это стандартная функция Windows API DefWindowProc
).
Рис. 1.7. Блок-схема оконной процедуры оконных компонентов VCL
Класс TControl
имеет метод Perform
, с помощи которого можно заставить визуальный компонент выполнить обработку конкретного сообщения в обход оконной процедуры и системного механизма передачи сообщений. Perform
приводит к непосредственному вызову метода, указатель на который хранится в свойстве WindowProc
. Дальше цепочка обработки сообщений такая же, как и при получении сообщения через оконную процедуру. Для оконных компонентов вызов Perform
по своим последствиям практически эквивалентен передаче сообщения с помощью SendMessage
с двумя исключениями. Во-первых, при использовании SendMessage
система обеспечивает переключение между нитями, и сообщение будет выполнено в той нити, которая создала окно, a Perform
никакого переключения не производит, и обработка сообщения будет выполнена той нитью, которая вызвала Perform
. Поэтому Perform
, в отличие от SendMessage
, можно использовать только в главной нити (напомним, что VCL — принципиально однонитевая библиотека, и создание форм вне главной нити с ее помощью недопустимо). Во-вторых, Perform
выполняется чуть быстрее, т. к. оконная процедура и метод MainWndProc
исключаются из цепочки обработки сообщения.
Но основное преимущество Perform
перед SendMessage
заключается в том, что Perform
пригоден для работы со всеми визуальными компонентами, а не только с оконными. Неоконные визуальные компоненты не могут иметь оконной процедуры, но цепочка обработки сообщений у них есть. В ней отсутствует оконная процедура и метол MainWndProc
, a DefaultHandler
не вызывает никаких стандартных оконных процедур, но во всем остальном эта цепочка полностью эквивалентна цепочке оконных компонентов. Таким образом, цепочка обработки сообщений оконных компонентов имеет две точки входа: оконную процедуру и метод Perform
, а цепочка неоконных компонентов — только метод Perform
. Следовательно, метод Perform
универсален: он одинаково хорошо подходит как для оконных, так и для неоконных компонентов. Он широко применяется в VCL, т. к. позволяет единообразно работать с любыми визуальными компонентами.
Неоконным визуальным компонентам сообщения посылает их родительское окно. Например, как мы уже говорили, обработка сообщений, связанных с мышью, в классе TWinControl
включает в себя, не попадают ли координаты курсора в область какого-либо из дочерних неоконных компонентов. И если попадает, оконный компонент не обрабатывает это сообщение самостоятельно, а транслирует его соответствующему неоконному компоненту с помощью Perform
. Эта трансляция и обеспечивает получение сообщений неоконными компонентами.