Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2005.07.18;
Скачать: [xml.tar.bz2];

Вниз

Список полей класса. Можно как то получить в 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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.57 MB
Время: 0.055 c
1-1119957354
olevacho_
2005-06-28 15:15
2005.07.18
шифрация данных в текстовом файле


1-1120134586
Apachi
2005-06-30 16:29
2005.07.18
TreeView Как задать картинки


1-1120149189
Бу
2005-06-30 20:33
2005.07.18
Графика


3-1118300903
Антоныч
2005-06-09 11:08
2005.07.18
Запрос в БД Access, защищенную паролем


14-1118869482
Soft
2005-06-16 01:04
2005.07.18
Я сегодня окончательно убедился во влиянии звезд на судьбу.





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский