При показе VCL-формы в модальном режиме выборка сообщений из очереди осуществляется особым образом. Модальные окна в VCL — это не то же самое, что модальные диалоги с точки зрения API. Диалог может быть создан только на основе шаблона, и его модальность обеспечивается самой операционной системой, a VCL допускает модальность для любой формы, позволяя разработчику не быть ограниченным возможностями предусмотренного системой шаблона. Достигается это следующим образом: при вызове метода ShowModal
Внутри ShowModal
Application.HandleMessage
до тех пор, пока не будет установлено свойство ModalResult
или не придет сообщение WM_QUIT
. После завершения этой петли вновь разрешаются все окна, которые были разрешены до вызова ShowModal
, а "модальная" форма закрывается. В отличие от системных модальных диалогов модальная форма VCL во время своей активности не посылает родительскому окну сообщение WM_ENTERIDLE
, но благодаря тому, что "модальная" петля сообщений использует HandleMessage
, будет вызываться Idle
, а значит, будет возникать событие Application.OnIdle
, которое позволит выполнять фоновые действия.Теперь рассмотрим, как VCL обрабатывает извлеченные из очереди сообщения. Как уже было сказано ранее, для каждого класса формы VCL регистрирует одноименный оконный класс, а все окна, принадлежащие одному оконному классу, имеют общую оконную процедуру. С другой стороны, логика работы VCL требует, чтобы события обрабатывались тем экземпляром oбъекта, который инкапсулирует окно-адресат. Таким образом, возникает вопрос о том, как передать сообщение заданному экземпляру класса VCL. VCL решает эту задачу следующим образом. Модуль Classes
MakeObjectInstance
, описанную так:type TWndMethod = procedure(var Message: TMessage) of object;
function MakeObjectInstance(Method: TWndMethod): Pointer;
Тип TMessage
Функция MakeObjectInstance
MakeObjectInstance
(таким образом, различные оконные процедуры, сформированные этой функцией, отличаются только тем, метод MainWndProc
какого экземпляра класса они вызывают).Каждый экземпляр оконного компонента создает свою оконную процедуру, которая передает обработку сообщения его методу MainWndProc
FObjectInstance
. Как мы уже говорили в предыдущем разделе, при регистрации оконного класса в качестве оконной процедуры указывается InitWndProc
, которая при получении первого сообщения создает подкласс, и оконной процедурой назначается та, указатель на которую хранится в поле FObjectInstance
, т. е. функция, созданная с помощью MakeObjectInstance
(см. листинг 1.12). Таким образом, каждый экземпляр получает свою оконную процедуру, а обработку сообщения начинает метод MainWndProc
.MainWndProc
WindowProc
. Это свойство имеет тип TWndMethod
и по умолчанию указывает на виртуальный метод WndProc
. Таким образом, если разработчик не изменял значения свойства WindowProc
, обработкой сообщения занимается WndProc
.