Главная » Delphi » Функции обратного вызова

0

Функция обратного вызова (callback function) — это функция приложения, вызываемая библиотеками  DLL  Win32  или  другими   библиотеками  DLL.  Фактически  в  системе Windows присутствует несколько функций API, которые используют функции обратного вызова. При  вызове таких  функций им передается адрес той функции приложения, ко торую Windows может  вызвать. Если не совсем  понятно, какое  отношение это имеет  к библиотекам DLL, то напомним, что  реально функции  API Win32  экспортируются  из системных библиотек DLL. По сути, при  передаче адреса  функции обратного вызова  в функцию API Win32 происходит передача этой функции в библиотеку DLL.

Одной из таких  функций является функция интерфейса API EnumWindows(), ко торая регистрирует все главные окна. Она передает функциям обратного вызова  при ложений дескрипторы каждого  окна,  объединенные в перечисление. Требуется лишь передать функции EnumWindows() адрес  функции обратного вызова, предваритель но определив ее следующим образом:

function EnumWindowsProc(Hw: HWnd; lp: lParam): Boolean; stdcall;Пример  использования функции  EnumWindows() приводится в  проекте Call- Back.dpr, код которого показан в листинге 6.9.

Листинг 6.9. MainForm.pas — пример функции обратного вызова

unit MainFrm;

interface uses

Windows, Messages, SysUtils, Classes, Graphics, Controls,

Forms, Dialogs, StdCtrls, ComCtrls;

type

{ Определение записи/класса для хранения имени окна и имени класса для каждого окна. Экземпляры этого класса помещаются в список ListBox1 }

TWindowInfo = class

WindowName,                // Имя окна

WindowClass: String; // Имя класса окна

end;

TMainForm = class(TForm) lbWinInfo: TListBox; btnGetWinInfo: TButton; hdWinInfo: THeaderControl;

procedure btnGetWinInfoClick(Sender: TObject);

procedure FormDestroy(Sender: TObject);

procedure lbWinInfoDrawItem(Control: TWinControl;

Index: Integer; Rect: TRect; State: TOwnerDrawState);

procedure hdWinInfoSectionResize(HeaderControl:

THeaderControl; Section: THeaderSection);

end;

var

MainForm: TMainForm;

implementation

{$R *.DFM}

function EnumWindowsProc(Hw: HWnd;

AMainForm: TMainForm): Boolean; stdcall;

{ Эта процедура вызывается библиотекой User32.DLL, поскольку она

регистрирует активные окна в системе. }

var

WinName, CName: array[0..144] of char;

WindowInfo: TWindowInfo;

begin

{ Возвращаемое значение по умолчанию равно true, что означает

незаконченную регистрацию окон. }

Result := True;GetWindowText(Hw, WinName, 144); // Получить текст текущего окна

GetClassName(Hw, CName, 144);        // Получить имя класса окна

{ Создается экземпляр класса TWindowInfo, поля которого

заполняются значениями имен окон и имен классов окон. Затем

этот объект добавляется в массив Objects списка ListBox1.

Позднее эти значения будут отображены в окне списка. }

WindowInfo := TWindowInfo.Create;

with WindowInfo do begin

SetLength(WindowName, strlen(WinName));

SetLength(WindowClass, StrLen(CName));

WindowName := StrPas(WinName);

WindowClass := StrPas(CName);

end;

{ Добавление в массив Objects }

MainForm.lbWinInfo.Items.AddObject(”, WindowInfo);

end;

procedure TMainForm.btnGetWinInfoClick(Sender: TObject);

begin

{ Регистрация всех отображаемых окон верхнего уровня. Передача

адреса функции обратного вызова EnumWindowsProc, которая будет

вызвана для каждого окна. }

EnumWindows(@EnumWindowsProc, 0);

end;

procedure TMainForm.FormDestroy(Sender: TObject);

var

i: integer;

begin

{ Освобождение всех экземпляров класса TWindowInfo }

for i := 0 to lbWinInfo.Items.Count – 1 do

TWindowInfo(lbWinInfo.Items.Objects[i]).Free

end;

procedure TMainForm.lbWinInfoDrawItem(Control: TWinControl;

Index: Integer; Rect: TRect; State: TOwnerDrawState);

begin

{ Сначала очищаем прямоугольник, предназначенный для вывода

информации. }

lbWinInfo.Canvas.FillRect(Rect);

{ Теперь выводим строки записи TWindowInfo, хранящейся в списке

под номером Index. Позиции вывода каждой строки определяются

разделами HeaderControl1. }

with TWindowInfo(lbWinInfo.Items.Objects[Index]) do begin

DrawText(lbWinInfo.Canvas.Handle, PChar(WindowName),

Length(WindowName), Rect,dt_Left or dt_VCenter);

{ Смещаем прямоугольник рисования, используя размер разделов

HeaderControl1 для определения позиции вывода следующей

строки. }

Rect.Left := Rect.Left + hdWinInfo.Sections[0].Width;

DrawText(lbWinInfo.Canvas.Handle, PChar(WindowClass),

Length(WindowClass), Rect, dt_Left or dt_VCenter);

end;end;

procedure TMainForm.hdWinInfoSectionResize(HeaderControl: THeaderControl; Section: THeaderSection);

begin

lbWinInfo.Invalidate; // Перерисовка списка ListBox1.

end;

end.

В этом  приложении  функция EnumWindows() используется для  получения  всех имен  окон  верхнего уровня  и названий их классов, помещаемых затем  в нестандарт ный  список  объектов в главной форме. Главная  форма использует этот  нестандарт ный  список  для вывода  имени окна  и имени класса  окна  в виде отдельных столбцов. Но прежде чем разбираться в том, как создаются нестандартные списки  со столбцами, рассмотрим методы  использования функции обратного вызова.

Использование функции обратного вызова

В листинге 6.9 приведено определение процедуры EnumWindowsProc(), которой в качестве первого параметра передается дескриптор окна.  Вторым параметром ука зываются определяемые пользователем данные, что позволяет передавать любые значения, размер которых эквивалентен размеру  целочисленного типа данных.

EnumWindowsProc() — это процедура обратного вызова, адрес  которой передает ся функции интерфейса API Win32 EnumWindows(), поэтому  она должна  быть объяв лена  с директивой StdCall, указывающей на  использование соглашения о вызове, принятого в системе Win32. При  передаче адреса  этой  процедуры в функцию  Enum- Windows() предполагается, что она будет вызвана для каждого  существующего  в дан ный момент  окна верхнего уровня,  дескриптор которого будет указан в качестве пер вого  параметра. Этот  дескриптор окна  используется  для  получения имени окна  и имени  его класса.  Затем  создается экземпляр класса  TWindowInfo, и его поля  запол няются полученной информацией. Созданный экземпляр добавляется в массив lbWinInfo.Objects. Информация,  содержащаяся в объектах этого  массива,  будет выведена в виде списка,  включающего несколько столбцов данных.

Напомним, что  в обработчике события OnDestroy главной формы обязательно должны  освобождаться все созданные экземпляры класса TWindowInfo.

В обработчике события btnGetWinInfoClick() выполняется  вызов   процедуры EnumWindows() с передачей ей в качестве первого параметра адреса процедуры Enum- WindowsProc().

Запустив это приложение и щелкнув на кнопке в его форме, можно увидеть полу

ченную от каждого  окна информацию, представленную в виде списка.

Отображение нестандартного списка

Имена  окон  и имена  классов  всех окон  верхнего уровня  выводятся в виде отдельных столбцов в объекте под именем lbWinInfo. Это — экземпляр класса TListBox, в котором свойству  Style присвоено значение lbOwnerDraw. При  выборе данного стиля  событие TListBox.OnDrawItem генерируется всякий раз, когда в компоненте TListBox необхо димо отобразить очередной элемент данных.  При  этом вся ответственность за отображе ние  данных  возлагается на программиста, что  позволяет ему самостоятельно выбирать способ их представления.

В листинге 6.9 обработчик событий lbWinInfoDrawItem() содержит весь код, осу ществляющий вывод  элементов списка.  В данном  случае  выводятся строки, содержа щиеся в экземплярах класса TWindowInfo, помещенных в массив lbWinInfo.Objects. Эти значения были получены от функции обратного вызова  EnumWindowsProc(). Что бы разобраться в работе подпрограммы обработки данного события, проанализируйте комментарии, помещенные в ее код.

Источник: Тейксейра, Стив, Пачеко, Ксавье.   Borland Delphi 6. Руководство разработчика. : Пер.  с англ. — М. : Издательский дом “Вильямс”, 2002. —  1120 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии