Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Книга о KOL.doc
Скачиваний:
29
Добавлен:
30.04.2019
Размер:
1.77 Mб
Скачать

2.23.9. Диспетчеризация сообщений в kol

Основной цикл обработки сообщений находится в процедуре Run, которая запускается сразу после создания указанных форм и апплета. Эту процедуру можно легко заменить своей (например, чтобы обеспечить больший или меньший приоритет для некоторых видов сообщений). В случае проекта MCK, для этого достаточно поместить свою процедуру Run прямо в основном файле проекта DPR, до директив INCLUDE, включающих сгенерированный код старта приложения. В случае программирования без MCK, вызов процедуры Run вы пишете вообще сами: можете вызвать не ее, а написать свой собственный цикл обработки сообщений.

Диспетчеризация заключается в том, что для каждого выбранного из очереди сообщения вызывается TranslateMessage и DispatchMessage. Это функции API, которые занимаются направлением сообщений указанным окнам. После чего, сообщения поступают в глобальную процедуру WndFunc*. Именно здесь в KOL и находится основной диспетчер сообщений. Его главная задача – это поиск объекта, соответствующего окну, указанному в сообщении (поле hwnd). Раньше для сопоставления окну визуального объекта в KOL применялась API функция GetProp, но совсем недавно было решено, что так называемое «пользовательское» поле атрибутов окна обычно все-таки не задействуется, а его использование дает чуть более быстрый и короткий код. В итоге, в KOL привязка окна к объекту может осуществляться либо тем, либо другим способом, в зависимости от значения опции USE_PROP.

Когда (и если) процедура WndFunc получила адрес объекта (это обязан быть объект TControl), она уже может вызывать его методы. Здесь как раз и вызывается метод WndProc, осуществляющий дальнейшую обработку оконных сообщений. Но если адрес объекта не удалось получить, то есть сообщение предназначено окну, не имеющему привязанного к нему объекта TControl, то в этом случае вызывается метод WndProc объекта Applet, а если он не присвоен, то тогда сообщение передается обработчику системы по умолчанию – процедуре DefWindowProc.

Окно может быть не сопоставлено конкретному объекту TControl в нескольких случаях. Это может быть подчиненное служебное окно для некоторого оконного объекта (например, выпадающий список и само поле ввода для комбинированного списка организованы в системе как окна, дочерние по отношению к самому комбинированному списку – combobox). Это может быть окно, которое вы создали, не используя средства TControl, свои кодом. Или окно еще только создается, и привязка к объекту еще не выполнена.

У всех объектов TControl процедура WndProc одна и та же, и в нее помещена обработка только самых общих сообщений. Самое главное то, что до того как начать обрабатывать полученное сообщение, этот метод сначала пытается от него «откреститься», если только это возможно. А именно, алгоритм следующий.

Во-первых, если переменная Applet существует, и для нее назначен обработчик события OnMessage, то в первую очередь вызывается этот (ваш) обработчик. Если обработчик события OnMessage вернет FALSE, то сообщение считается полностью обработанным, и больше оно уже никак не обрабатывается, в том числе процедурами системы обработки сообщений по умолчанию.

Во-вторых, если назначен обработчик события OnMessage самого объекта TControl, получившего сообщение, то вызывается этот (ваш) обработчик. И снова, если обработчик события возвращает FALSE, то сообщение считается полностью обработанным, и вся обработка данного сообщения завершается.

Р

азумеется, возврат значения TRUE процедуре WndProc из обработчика события OnMessage (и других обработчиков) не означает, что система обязательно согласится с таким вашим указанием. Если не выполнены какие-либо требования по обработке сообщения, то есть вероятность, что система пошлет это сообщение еще и еще раз, пока не получит желаемое. Например, если в ответ на сообщение WM_PAINT системе не будет возвращено значение 0 (параметр Rslt), то система будет считать, что приложение по каким-либо причинам не желает выполнить заказ немедленно, и хочет отложить его на некоторое время. И пришлет сообщение еще, и еще раз. Есть вероятность, что неверно написанный обработчик сообщения сможет серьезно затормозить работу приложения, с написанием кода события OnMessage необходимо быть внимательным.

В-третьих, и это самый важный пункт, вызывается исполнитель динамически присоединенных (методами AttachProc, AttachProcEx) к объекту обработчиков сообщений. Такие обработчики предназначены в основном для внутреннего использования в самой библиотеке KOL, для добавления требуемой функциональности по обработке сообщений для конкретных разновидностей оконных объектов. Но они могут использоваться и программистами, точно так же, как и фиксированный пользовательский обработчик OnMessage. Если такие динамические обработчики присоединены (а это верно практически для всех оконных объектов), то начинает работать функция EnumDynHandlers. Ее задача – просмотреть все динамические обработчики (от последнего присоединенного к первому), вызывая их один за другим, по крайней мере, пока очередной обработчик в цепочке не «скажет», что дальше продолжать обработку сообщения не следует (возвратив FALSE).

На прилагаемом выше рисунке я попробовал изобразить процесс диспетчеризации сообщений. И только если специфицированные обработки сообщений не найдены или позволили сообщению обрабатываться дальше, метод TControl.WndProc выполнит обработку самых общих сообщений. А именно: WM_CLOSE, WM_SIZE, WM_SYSCOMMAND, WM_SETFOCUS, WM_SETCURSOR, WM_CTLCOLORxxxx, WM_COMMAND, WM_KEYxxxx. И для всех прочих сообщений вызовет системный обработчик по умолчанию.