Author: Boris Benjamin Wittfoth
How to get the published properties of an persistent object / Using the
pPropInfo-Pointer and the RTTI of Delphi
Answer:
The TypeInfo unit of Delphi declares several types and functions that gives you
easy access to the puplished properties of an object and other informations.
You can obtain a list of the published properties of a class and get the name an
type of each property.
The TypeInfo funtion returns a pointer to a type information record. The TypInfo
unit declares a real type, that is, a pointer to a TTypeInfo record :
1 PTypeInfo = ^TTypeInfo;
2 TTypeInfo = record
3 Kind: TTypeKind;
4 Name: ShortString;
5 end;
The TTypeKind datatype describes the Datatype , returned by the GetTypeData
function.
TTypeKind = (tkUnknown, tkInteger, tkChar, tkEnumeration, tkFloat,
tkString, tkSet, tkClass, tkMethod, tkWChar, tkLString, tkWString,
tkVariant, tkArray, tkRecord, tkInterface, tkInt64, tkDynArray);
TTypeKinds = set of TTypeKind;
Well ... for our first step to access the objects published properties we need to
use the PPropInfo-pointer.
6 PPropInfo = ^TPropInfo;
7 TPropInfo = packed record
8 PropType: PPTypeInfo;
9 GetProc: Pointer;
10 SetProc: Pointer;
11 StoredProc: Pointer;
12 Index: Integer;
13 default: Longint;
14 NameIndex: SmallInt;
15 Name: ShortString;
16 end;
17
18 //To clarify it, please take a look at this example :
19
20 function GetFontSize(Obj: TPersistent): Integer;
21 {
22 in this Procedure we want to get the pPropInfo-pointer - pointing
23 on the Font-Property from an arbitrary TPersistent-Class.
24 The return-value in this instance will be the font-size ( if the font
25 property exists , if not -> the return value will be -1 )
26 }
27 var
28 PropInfo: PPropInfo;
29 begin
30 RESULT := -1;
31 // Get the PPropInfo-Pointer for Font of the TPersistent obj
32 PropInfo := GetPropInfo(Obj, 'Font');
33 // At first we will find out if the property FONT exists
34 if PropInfo = nil then
35 EXIT; // The Property doesn't exists
36 {
37 TFont is not an ordinal-Type - therefore will have to control if
38 Typekind of the TypeInfo-Class is set to tkClass
39 }
40 if PropInfo.PropType^.Kind <> tkClass then
41 EXIT; // property isn't a tkClass type
42 {
43 now, we now that the TypeKind of die PropInfo-pointer is a class .
44 last but not least we will use the GetObjectProp, the return-value
45 of this function is a TObject. Subsequently, we will use this object as
46 a TFont to get the Size value.
47 }
48 RESULT := ((GetObjectProp(Obj, PropInfo)) as TFont).Size;
49 end;
50
51 But to get the complete list of all properties of a TPersistent-class we will need
52 the pPropList-type . This type is a simple pointer-array and the magic key to all
53 property-Informations and their structures.
54
55 Take a look at this :
56
57 procedure TForm1.Button1Click(Sender: TObject);
58
59 const
60 tkOrdinal = [tkEnumeration, tkInteger, tkChar, tkSet, tkWChar]; //Filter
61
62 begin
63 {
64 in this method of the mainform-class we are seeking for all ordinal-type
65 properties of the edit1-component. The from the GetPropertyList method
66 returned list of all properties will be written into the Listbox1. You can
67 replace the obj parameter with an arbitrary TObject ( but usually TPersistent
68 objects ).
69 For another filter please take a look at the TTypeKinds-set.
70 }
71 GetPropertyList(Edit1, ListBox1.Items, tkOrdinal);
72 end;
73
74 procedure GetPropertyList(Obj: TObject; List: TStrings; Filter: TTypeKinds);
75 var
76 PropList: pPropList;
77 count, i: Integer;
78 begin
79 List.Clear;
80 // Here we'll get the count of the given properties, ...
81 Count := GetPropList(Obj.ClassInfo, Filter, nil);
82 // ...and create room for the PropList,...
83 GetMem(PropList, Count * SizeOf(PPropInfo));
84 // ...get the Proplist-Data,...
85 GetPropList(Obj.ClassInfo, Filter, PropList);
86 // ...and write the property-names into the StringList
87 for i := 0 to Count - 1 do
88 List.Add(Proplist[i].Name);
89 end;
|