begin
{ что-то делаем}
end;
...............
var
MyPointer: Pointer;
...............
EnumWindows(@MyCallbackFunction, LongInt(MyPointer));
Что бы мы ни делали с типом второго параметра функции обратного вызова, тип соответствующего параметра EnumWindows
не меняется. Поэтому необходимо явное приведение передаваемого параметра к типу LongInt
. Обратное преобразование типов при вызове MyCallbackFunction
, осуществляется автоматически.
Использование EnumWindows
и функций обратного вызова демонстрируется примером EnumWnd
.
Отметим, что функции обратного вызова будут вызываться до того, как завершит работу функция EnumWindows
. Однако это не является распараллеливанием работы. Чтобы проиллюстрировать это, рассмотрим ситуацию, когда программа вызывает некоторую функцию А, которая, в свою очередь, вызывает функцию В. Функция В, очевидно, начнет свою работу до того, как завершит работу функция А. То же самое произойдет и с функцией обратного вызова, переданной в EnumWindows
: она будет вызываться из кода EnumWindows
так же, как и функция В из кода функции А. Поэтому код функции обратного вызова получит управление (и не один раз, т.к. EnumWindows
будет вызывать эту функцию в цикле) до завершения работы EnumWindows
.
Однако это правило действует не во всех ситуациях. В некоторых случаях система запоминает адрес переданной ей функции обратного вызова, чтобы использовать ее потом. Примером такой функции является оконная процедура: ее адрес передается системе один раз при регистрации класса, и затем система многократно вызывает эту функцию при необходимости.
В 16-разрядных версиях Windows вызов функций обратного вызова осложнялся тем, что для них необходим был специальный код. называемый прологом. Пролог создавался с помощью функции MakeProcInstance
, удалялся после завершения с помощью FreeProcInstance
. Таким образом, вызов EnumWindows
должен был бы выглядеть так. как показано в листинге 1.4.
Листинг 1.4. Вызов функции EnumWindows
в 16-разрядных версиях Windows
var
MyProcInstanсe: TFarProc;
...............
MyProcInstance := MakeProcInstance(@MyCallBackFunction, HInstance);
EnumWindows(MyProcInstance, LongInt(MyPointer));
FreeProcInstance(MyProcInstance);
В Delphi этот код будет работоспособным, т.к. для совместимости MakeProcInstance
и FreeProcInstance
оставлены. Но они ничего не делают (в чем легко убедиться, просмотрев исходный файл Windows.pas), поэтому можно обойтись и без них. Тем не менее эти функции иногда до сих пор используются, видимо, просто в силу привычки. Другой способ, с помощью которого и 16-разрядных версиях можно сделать пролог — описать функцию с директивой export
. Эта директива сохранена для совместимости и в Delphi, но в 32-разрядных версиях она также ничего не делает (несмотря на то, что справка, например, по Delphi 3 утверждает обратное; в справке по Delphi 4 этой ошибки уже нет).
Человеку, знакомому с Delphi, должна быть ясна схема событийного управления. Программист пишет только методы реакции на различные события, а затем этот код получает управление тогда, когда соответствующее событие произойдет. Простые программы в Delphi состоят исключительно из методов реакции на события (например, OnCreate
, OnClick
, OnCloseQuery
). Причем событием называется не только событие в обычном смысле этого слова, т.е. когда происходит что-то внешнее, но и ситуация, когда событие используется просто для передачи управления коду, написанному разработчиком программы, в тех случаях, когда VCL не может сама справиться с какой-то задачей. Пример такого события — TListBox.OnDrawItem
. Устанавливая стиль списка в lbOwnerDrawFixed
или lbOwnerDrawVariable
, программист указывает, что ему требуется нестандартный вид элементов списка, поэтому их рисование он берет на себя. И каждый раз, когда возникает необходимость в рисовании элемента, VCL передает управление специально написанному коду. На самом деле разница между двумя типами событий весьма условна. Можно сказать, что когда пользователь нажимает клавишу, VCL не "знает", что делать, и поэтому передает управление обработчику OnKeyPress
.
Событийное управление не есть изобретение авторов Delphi. Такой подход заложен в самой системе Windows. Только здесь события называются сообщениями (message), что иногда даже лучше отражает ситуацию. Windows посылает программе сообщения, связанные либо с тем, что произошло внешнее событие (нажатие кнопки мыши, клавиши на клавиатуре и т.п.), либо с тем, что самой системе потребовались от программы какие-то действия. Самое распространенное действие — предоставление информации. Например, при необходимости узнать текст заголовка окна Windows посылает этому окну специальное сообщение, в ответ на которое окно должно сообщить системе свой заголовок. Еще бывают сообщения, которые просто уведомляют программу о начале какого-то действия (например, о начале перетаскивания окна) и предоставляют возможность вмешаться. Но это вмешательство необязательно.
Читать дальше
Конец ознакомительного отрывка
Купить книгу