Главная » Delphi » Получение информации о типах указателей на методы

0

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

Листинг 10.4. Получение информации  RTTI для методов

unit MainFrm;

interface uses

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

Dialogs, StdCtrls, ExtCtrls, DBClient, MidasCon, MConnect;

type

TMainForm = class(TForm) lbSampMethods: TListBox; lbMethodInfo: TMemo; lblBasicMethodInfo: TLabel;

procedure FormCreate(Sender: TObject);

procedure lbSampMethodsClick(Sender: TObject);private

{ Закрытые объявления }

public

{ Открытые объявления }

end;

var

MainForm: TMainForm;

implementation

uses TypInfo, DBTables, Provider;

{$R *.DFM}

type

// Необходимо переопределить эту запись, так как в typinfo.pas

// она закомментирована.

PParamRecord = ^TParamRecord; TParamRecord = record

Flags: TParamFlags; ParamName: ShortString; TypeName: ShortString;

end;

procedure GetBaseMethodInfo(ATypeInfo: PTypeInfo; AStrings: TStrings);

{ Этот метод получает часть основных данных RTTI из структуры TTypeInfo и добавляет их в параметр AStrings. }

var

MethodTypeData: PTypeData;

EnumName: String;

begin

MethodTypeData := GetTypeData(ATypeInfo);

with AStrings do begin

Add(Format(‘Class Name:    %s’, [ATypeInfo^.Name]));

EnumName := GetEnumName(TypeInfo(TTypeKind),

Integer(ATypeInfo^.Kind));

Add(Format(‘Kind:          %s’, [EnumName]));

Add(Format(‘Num Parameters: %d’,[MethodTypeData.ParamCount]));

end;

end;

procedure GetMethodDefinition(ATypeInfo: PTypeInfo; AStrings: TStrings);

{ Этот метод позволяет получить информацию об указателе метода.

Используем эту информацию для реконструкции определения метода.}

var

MethodTypeData: PTypeData;

MethodDefine:        String;

ParamRecord:         PParamRecord;

TypeStr:             ^ShortString;

ReturnStr:  ^ShortString;i: integer;

begin

MethodTypeData := GetTypeData(ATypeInfo);

// Определение типа метода

case MethodTypeData.MethodKind of

mkProcedure:            MethodDefine := ‘procedure ‘;

mkFunction:             MethodDefine := ‘function ‘;

mkConstructor:          MethodDefine := ‘constructor ‘;

mkDestructor:           MethodDefine := ‘destructor ‘;

mkClassProcedure: MethodDefine := ‘class procedure ‘;

mkClassFunction:        MethodDefine := ‘class function ‘;

end;

// Указатель на первый параметр

ParamRecord         := @MethodTypeData.ParamList;

i := 1; // первый параметр

// Перебрать параметры метода и, если они определены правильно,

// добавить их в список строк.

while i <= MethodTypeData.ParamCount do begin

if i = 1 then

MethodDefine := MethodDefine+'(‘;

if pfVar in ParamRecord.Flags then

MethodDefine := MethodDefine+(‘var ‘);

if pfconst in ParamRecord.Flags then

MethodDefine := MethodDefine+(‘const ‘);

if pfArray in ParamRecord.Flags then

MethodDefine := MethodDefine+(‘array of ‘);

// Не будем изменять pfAddress, а лишь убедимся в том, что

// параметр Self передается с установленным флагом.

{

if pfAddress in ParamRecord.Flags then

MethodDefine := MethodDefine+(‘*address* ‘);

}

if pfout in ParamRecord.Flags then

MethodDefine := MethodDefine+(‘out ‘);

// Использовать арифметику указателей для получения строки

// типа параметра.

TypeStr := Pointer(Integer(@ParamRecord^.ParamName) +

Length(ParamRecord^.ParamName)+1);

MethodDefine := Format(‘%s%s: %s’, [MethodDefine, ParamRecord^.ParamName, TypeStr^]);

inc(i); // Увеличить счетчик.

// Переход к следующему параметру. Обратите внимание на

// использование арифметических операций над указателями для

// расчета положения следующего параметра.

ParamRecord := PParamRecord(Integer(ParamRecord) +

SizeOf(TParamFlags) +(Length(ParamRecord^.ParamName) + 1) + (Length(TypeStr^)+1));

// Если параметры все еще есть, то продолжать

if i <= MethodTypeData.ParamCount then begin

MethodDefine := MethodDefine + ‘; ‘;

end else

MethodDefine := MethodDefine + ‘)';

end;

// Если метод является функцией, то он должен возвращать

// значение, которое также помещается в строку определения

// метода. Возвращаемое значение следует за последним

// параметром.

if MethodTypeData.MethodKind = mkFunction then begin

ReturnStr := Pointer(ParamRecord);

MethodDefine := Format(‘%s: %s;’, [MethodDefine, ReturnStr^])

end else

MethodDefine := MethodDefine+';';

// И, наконец, добавить строку в список. with AStrings do begin

Add(MethodDefine)

end;

end;

procedure TMainForm.FormCreate(Sender: TObject);

begin

{ Добавить ряд типов методов в список, а также сохранить

указатель на данные RTTI в массиве списка Objects }

with lbSampMethods.Items do begin

AddObject(‘TNotifyEvent’, TypeInfo(TNotifyEvent));

AddObject(‘TMouseEvent’, TypeInfo(TMouseEvent));

AddObject(‘TBDECallBackEvent’, TypeInfo(TBDECallBackEvent));

AddObject(‘TDataRequestEvent’, TypeInfo(TDataRequestEvent));

AddObject(‘TGetModuleProc’, TypeInfo(TGetModuleProc));

AddObject(‘TReaderError’, TypeInfo(TReaderError));

end;

end;

procedure TMainForm.lbSampMethodsClick(Sender: TObject);

begin

lbMethodInfo.Lines.Clear;

with lbSampMethods do begin

GetBaseMethodInfo(PTypeInfo(Items.Objects[ItemIndex]),

lbMethodInfo.Lines);

GetMethodDefinition(PTypeInfo(Items.Objects[ItemIndex]),

lbMethodInfo.Lines);

end;

end;

end.

Как видно  из листинга 10.4, в список  lbSampMethods помещены имена  методов ис пользованного объекта. Указатели на RTTI  этих  методов находятся в массиве  списка Objects. Они получены с помощью функции TypeInfo(), предназначенной для поис ка указателя  на информацию о типах  времени выполнения для заданного идентифика тора  типа.  Если пользователь выбирает один из этих методов, данные RTTI из массива Objects используются для реконструкции определения метода.  Более  подробная ин формация по этой теме приведена в комментариях листинга.

CОВЕТ

Для получения указателя на генерируемую компилятором информацию RTTI для оп- ределенного идентификатора типа применяйте функцию TypeInfo(). Например, сле- дующая строка позволяет получить указатель на информацию RTTI для типа TButton:

TypeInfoPointer := TypeInfo(TButton);

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

По теме:

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