Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.07.18;
Скачать: CL | DM;

Вниз

Список полей класса. Можно как то получить в runtime?   Найти похожие ветки 

 
DiamondShark ©   (2005-06-27 21:48) [40]


> и покопать в сторону PFieldTable

А в Д5 такой нет. :(
Я из анализа FieldAddress вытаскивал.

Как она выглядит?


 
default ©   (2005-06-27 22:44) [41]

но это только для классовых и интерфейсных полей
в [0] требовались и другие типы
понятно что можно использовать приведение, но это всё неудобно...


 
default ©   (2005-06-27 22:47) [42]

вообщем бесполезно всё это


 
Юрий Зотов ©   (2005-06-27 22:47) [43]

> DiamondShark ©   (27.06.05 21:48) [40]

В D7 объявлено в implementation (причем TTypeInfo отличается от ее же декларации в TypInfo только словом packed):

type
 PPTypeInfo = ^PTypeInfo;
 PTypeInfo = ^TTypeInfo;
 TTypeInfo = packed record
   Kind: Byte;
   Name: ShortString;
  {TypeData: TTypeData}
 end;

 TFieldInfo = packed record
   TypeInfo: PPTypeInfo;
   Offset: Cardinal;
 end;

 PFieldTable = ^TFieldTable;
 TFieldTable = packed record
   X: Word;
   Size: Cardinal;
   Count: Cardinal;
   Fields: array [0..0] of TFieldInfo;
 end;


Но окно CPU показывает, что что-то тут не так (эта структура не соответствует расположенной адресу, хранящемуся в VMT по смещению vmtFieldTable). Надо копать.


 
Юрий Зотов ©   (2005-06-27 23:02) [44]

Посмотрел System.pas повнимательнее. Увы, тип TFieldInfo используется только в процедурах инициализации и финализации записей и массивов - поэтому похоже, что к сабжу он отношения не имеет. Поэтому и структура данных не совпадает.

Остается способ, код которого уже приводился. Вот бы еще узнать, что же хранится в таинственном поле TFieldRec.XXX


 
DiamondShark ©   (2005-06-27 23:47) [45]

Мда...
Теперь понятно, почему там нет типа.

Published поля не объектного типа даже компилятор не пропускает.

Хитрые разработчики Дельфи сделали только минимум, необходимый для работы IDE.


 
Просто Джо ©   (2005-06-28 00:05) [46]


> Published поля не объектного типа даже компилятор не пропускает.

Ну, если быть точным, пропускает еще интерфейсного типа (помимо объектного).


 
DiamondShark ©   (2005-06-28 00:09) [47]


> Ну, если быть точным, пропускает еще интерфейсного типа
> (помимо объектного).

Пропускает. Но в таблицу не записывает.


 
Ученик   (2005-06-28 00:17) [48]

>Юрий Зотов ©   (27.06.05 23:02) [44]

TFieldRec.XXX - индекс в FieldTable.FieldClassTable


 
Юрий Зотов ©   (2005-06-28 00:24) [49]

Итак: все эти списки основаны на RTTI, а она генерится только для published и только для свойств и объектных полей.

Гы...
:о)


 
Юрий Зотов ©   (2005-06-28 04:19) [50]

Наверное, подводя итоги...

Накидал я тут по материалам этой ветки модулек, который может быть полезен. Экспортируются несколько типов и 2 функции. Одна дает адрес таблицы полей, другая перечисляет эти поля, вызывая callback (перечисление заканчивается, если callback вернет False). В итоге для любого класса можем получить все сведения о его published-полях, которые ссылаются на потомки TPersistent (имя, класс, смещение). Делал и тестировал в D7, но похоже, что код должен работать в любой версии Delphi.

unit FldInfo;

interface

uses
 Classes;

type
 PFieldClassTable = ^TFieldClassTable;
 TFieldClassTable = packed record
   Count: SmallInt;
   Classes: packed array[0..8191] of ^TPersistentClass;
 end;

 PFieldRec = ^TFieldRec;
 TFieldRec = packed record
   Offset: integer;
   ClassIndex: SmallInt;
   Name: ShortString
 end;

 PFieldTable = ^TFieldTable;
 TFieldTable = packed record
   Count: SmallInt;
   ClassTable: PFieldClassTable;
   Fields: packed array[0..0] of TFieldRec
 end;

 PFieldInfo = ^TFieldInfo;
 TFieldInfo = packed record
   FieldName: ShortString;
   FieldClass: TPersistentClass;
   FieldOffset: integer
 end;

 TEnumFieldsProc = function(const FieldInfo: TFieldInfo; Data: Pointer): boolean; // False = stop

function GetFieldTable(AClass: TClass): PFieldTable;
procedure EnumFields(AClass: TClass; Data: Pointer; Proc: TEnumFieldsProc);

implementation

const
 Delta = SizeOf(integer) + SizeOf(SmallInt) + 1;

function GetFieldTable(AClass: TClass): PFieldTable;
begin
 if AClass <> nil then
   Result := PFieldTable(Pointer(Integer(AClass) + vmtFieldTable)^)
 else
   Result := nil
end;

{$IFOPT R+}
 {$DEFINE FldInfoRPlus}
 {$R-}
{$ENDIF}
procedure EnumFields(AClass: TClass; Data: Pointer; Proc: TEnumFieldsProc);
var
 FieldTable: PFieldTable;
 FieldRec: PFieldRec;
 Info: TFieldInfo;
 i: integer;
begin
 FieldTable := GetFieldTable(AClass);
 if FieldTable <> nil then
   with FieldTable^ do
   begin
     FieldRec := @Fields[0];
     for i := 0 to Count - 1 do
       with FieldRec^, Info do
       begin
         FieldName := Name;
         FieldClass := ClassTable^.Classes[ClassIndex]^;
         FieldOffset := Offset;
         if Proc(Info, Data) then
           FieldRec := PFieldRec(Integer(FieldRec) + Length(Name) + Delta)
         else
           Break
       end
   end
end;
{$IFDEF FldInfoRPlus}
 {$R+}
 {$UNDEF FldInfoRPlus}
{$ENDIF}

end.

Тестирующая программа (на форму кинуть TEdit, TButton, TListBox и назначить форме обработчик двойного клика по ней):

type
 TForm1 = class(TForm)
   Edit1: TEdit;
   Button1: TButton;
   ListBox1: TListBox;
   procedure FormDblClick(Sender: TObject);
 private
   procedure Check;  
 published
   FMyField: TPersistent;
 end;

function EnumFieldsProc(const FieldInfo: TFieldInfo; Data: Pointer): boolean;
begin
 Result := True;
 with FieldInfo, TStrings(Data) do
   AddObject(Format("%s: %s ($%x)", [FieldName, FieldClass.ClassName, FieldOffset]), TObject(FieldOffset))
end;

procedure TForm1.Check;
begin
 with ListBox1 do
 begin
   TEdit(Pointer(Integer(Self) + Integer(Items.Objects[0]))^).Text := "OK";
   TButton(Pointer(Integer(Self) + Integer(Items.Objects[1]))^).Caption := "OK";
   Self.Caption := TObject(Pointer(Integer(Self) + Integer(Items.Objects[2]))^).ClassType.ClassName
 end
end;

procedure TForm1.FormDblClick(Sender: TObject);
begin
 ListBox1.Clear;
 EnumFields(ClassType, ListBox1.Items, EnumFieldsProc);
 Check
end;


 
Просто Джо ©   (2005-06-28 04:56) [51]

Не перевелись хакеры на земле Русской :)


 
evvcom ©   (2005-06-28 08:38) [52]

Во дают! Чего на работу никому не надо?

> Не перевелись хакеры на земле Русской :)

Хакер был, хакер есть, хакер не может не есть! (с) был про Ленина. :)


 
Юрий Зотов ©   (2005-06-28 08:53) [53]

Надо уточнить: кидать на форму TEdit, TButton и TListBox надо строго в этой последовательности - к ней привязан метод Check.


 
default ©   (2005-06-28 08:54) [54]

Юрий Зотов ©   (28.06.05 08:53) [53]
offtopic: программистам была команда "не спать!" ?:)


 
Begin   (2005-06-28 09:28) [55]

О как ветка разраслась то... :)

Спасибо всем огромное, будем пробовать ! :)


 
Erik1 ©   (2005-06-28 15:35) [56]

А теперь по теме вопроса: Наверное тебе стоит переспотреть подход к задаче. Масив с указателями на конструкторы объектов тебе уже предлагали. Необходимо заметить, что такой масив может содержать записи, а в них возможно задать стринговое поле с имененм класса. Возможны и другие варианты, опиши более деталь, что ты хочеш сделать и как это работает. Наверника есть более красивый способ.



Страницы: 1 2 вся ветка

Текущий архив: 2005.07.18;
Скачать: CL | DM;

Наверх




Память: 0.58 MB
Время: 0.045 c
9-1112794393
Кирилл
2005-04-06 17:33
2005.07.18
Effects


1-1119693133
grol
2005-06-25 13:52
2005.07.18
Кнопка-компонент из 3 картинок (image ей)?


4-1117077209
kblc
2005-05-26 07:13
2005.07.18
FreeLibrary


3-1117914399
Inquisitor
2005-06-04 23:46
2005.07.18
как создать поле выбора в таблице


14-1119607278
boriskb
2005-06-24 14:01
2005.07.18
Экономим на зарплатах?