RTTI jak widać daje duże możliwości, związane z dynamiką programu. Co do odpalania metody zapraszam do artykułów, gdzie pokazałem przykład takiego użycia (pod warunkiem znajomości nazwy metody danej klasy). Znalazłem taki przykład programu na wyciąganie listy metod (może się przyda):
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
{ Private declarations }
public
{ Public declarations }
end;
var
MainForm: TMainForm;
implementation
uses TypInfo, DBTables, Provider;
{$R *.DFM}
type
// konieczna jest redefinicja poniższej struktury - jest ona
// wykomentowana w typinfo.pas
PParamRecord = ^TParamRecord;
TParamRecord = record
Flags: TParamFlags;
ParamName: ShortString;
TypeName: ShortString;
end;
procedure GetBaseMethodInfo(ATypeInfo: PTypeInfo; AStrings: TStrings);
{
Niniejsza metoda pobiera kilka informacji o typie i wpisuje je
na podaną listę łańcuchów
}
var
MethodTypeData: PTypeData;
EnumName: String;
begin
MethodTypeData := GetTypeData(ATypeInfo);
with AStrings do
begin
Add(Format('Nazwa metody: %s', [ATypeInfo^.Name]));
EnumName := GetEnumName(TypeInfo(TTypeKind), Integer(ATypeInfo^.Kind));
Add(Format('Typ: %s', [EnumName]));
Add(Format('Liczba parametrów: %d',[MethodTypeData.ParamCount]));
end;
end;
procedure GetMethodDefinition(ATypeInfo: PTypeInfo; AStrings: TStrings);
{
Niniejsza metoda pobiera informację o definicji metody i wpisuje ją
na podaną listę łańcuchów
}
var
MethodTypeData: PTypeData;
MethodDefine: String;
ParamRecord: PParamRecord;
TypeStr: ^ShortString;
ReturnStr: ^ShortString;
i: integer;
begin
MethodTypeData := GetTypeData(ATypeInfo);
// Określ typ metody
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;
// wskaźnik do pierwszego parametru
ParamRecord := @MethodTypeData.ParamList;
i := 1; // pierwszy parametr
// pobieraj kolejno informację o kolejnych parametrach,
// tworząc deklarację metody
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 ');
// ustawiona flaga pfAddress oznacza NIEJAWNY parametr Self, którego
// nie wykazujemy w informacji o metodzie
{
if pfAddress in ParamRecord.Flags then
MethodDefine := MethodDefine+('*address* ');
}
if pfout in ParamRecord.Flags then
MethodDefine := MethodDefine+('out ');
// użyj "arytmetyki na wskaźnikach" do otrzymania nazwy typu parametru:
TypeStr := Pointer(Integer(@ParamRecord^.ParamName) +
Length(ParamRecord^.ParamName)+1);
MethodDefine := Format('%s%s: %s', [MethodDefine, ParamRecord^.ParamName,
TypeStr^]);
inc(i); // zwiększ numer parametru
// przejdź do następnego parametru; zwróć uwagę na "arytmetykę
// na wskaźnikach"
ParamRecord := PParamRecord(Integer(ParamRecord) + SizeOf(TParamFlags) +
(Length(ParamRecord^.ParamName) + 1) + (Length(TypeStr^)+1));
// jeżeli wyczerpano zestaw parametrów, zamknij nawias
if i <= MethodTypeData.ParamCount then
begin
MethodDefine := MethodDefine + '; ';
end
else
MethodDefine := MethodDefine + ')';
end;
// jeżeli metoda jest FUNKCJĄ, RTTI zawiera informację o typie
// jej wyniku; znajduje się ona bezpośrednio po informacji
// o ostatnim parametrze
if MethodTypeData.MethodKind = mkFunction then
begin
ReturnStr := Pointer(ParamRecord);
MethodDefine := Format('%s: %s;', [MethodDefine, ReturnStr^])
end
else
MethodDefine := MethodDefine+';';
// dodaj kompletny łańcuch do listy
with AStrings do
begin
Add(MethodDefine)
end;
end;
procedure TMainForm.FormCreate(Sender: TObject);
begin
// wypełnij listę kilkoma przykładowymi nazwami metod
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.
Metody zostaną wyświetlone na ListBoxie, po kliknięciu na metodę do memo załadują się dokładniejsze informacje.