RTTI(四)相关函数2【转自大富翁】

GetOrdProp 函数详解

SetOrdProp 函数

GetEnumProp / SetEnumProp 函数

GetSetProp / SetSetProp 函数
GetObjectProp / SetObjectProp 函数

GetStrProp / SetStrProp 函数

⊙ GetOrdProp 函数详解

GetOrdProp 是 Delphi RTTI 中使用频繁的函数。GetOrdProp 根据对象句柄和对象属性的 TPropInfo 指针获得对象的属性值。它的返回值是 Longint,需要强制转换成相应的属性类型才能使用。

function GetOrdProp(Instance: TObject; PropInfo: PPropInfo): Longint;

GetOrdProp 调用 TPropInfo.GetProc 函数指针得到属性的返回值。它的工作过程是:

如果该属性的类型是 class 类型,那么返回值是 4 个字节(对象句柄)。

否则通过 TTypeData.OrdType 得到返回值的类型,存储在 BL 中。

{ TOrdType = (otSByte, otUByte, otSWord, otUWord, otSLong, otULong); }

检查 TPropInfo.GetProc 的第一个字节(注意是 GetProc 指针的第一个字节):

如果 GetProc[0] = $FF,说明 GetProc 是 field offset;
如果 GetProc[0] = $FE,说明 GetProc 是 virtual method offset;
如果 GetProc[0] < $FE,说明 GetProc 是 static method;

然后根据不同的 GetProc 类型解析后,调用 GetProc。
根据 BL 中存储的类型符号信息修正返回值(EAX)的符号信息。
根据 BL 中存储的类型的大小裁剪返回值 EAX 为 EAX/AX/AL。
EAX(AX/AL) 即是返回的属性值。

GetOrdProp 的汇编代码及注释如下:

function GetOrdProp(Instance: TObject; PropInfo: PPropInfo): Longint;

asm

  PUSH  EBX

  PUSH  EDI

  MOV  EDI,[EDX].TPropInfo.PropType  ; EDI <- PPTypeInfo

  MOV  EDI,[EDI]  ; EDI <- PTypeInfo

  MOV  BL,otSLong  ; BL  <- otSLong

  CMP  [EDI].TTypeInfo.Kind,tkClass  ; if Prop is Class

  JE  @@isClass  ; jmp @@isClass

  XOR  ECX,ECX  ; ECX <- 0

  MOV  CL,[EDI].TTypeInfo.Name.Byte[0]  ; CL  <- Name StrLength

  MOV  BL,[EDI].TTypeInfo.Name[ECX+1].TTypeData.OrdType

  ; BL  <- Prop OrdType

  @@isClass:

  MOV  ECX,[EDX].TPropInfo.GetProc  ; ECX <- GetProc Addr

  CMP  [EDX].TPropInfo.GetProc.Byte[3],$FE ; cmp HiByte(GetProc), $FE

  MOV  EDX,[EDX].TPropInfo.Index  ; EDX <- Prop Index

  JB  @@isStaticMethod  ; if below $FE

  JA  @@isField  ; if is $FF

  {  the GetProc is a virtual method }  ; if is $FE

  MOVSX  ECX,CX  { sign extend slot offs }

  ADD  ECX,[EAX]  { vmt  + slotoffs  }

  CALL  dword ptr [ECX]  { call vmt[slot]  }

  JMP  @@final

  @@isStaticMethod:

  CALL  ECX  ; call GetProc directly

  JMP  @@final

  @@isField:

  AND  ECX,$00FFFFFF  ; clear HiByte(GetProc)

  ADD  ECX,EAX  ; ECX <- Field Addr

  MOV  AL,[ECX]  ; AL  <- Field Addr[0]

  CMP  BL,otSWord  ; if OrdType < otSWord

  JB  @@final  ; Exit

  MOV  AX,[ECX]  ; else AX <- Field[0..1]

  CMP  BL,otSLong  ; if OrdType < otSLong

  JB  @@final  ; Exit

  MOV  EAX,[ECX]  ; else EAX <- Field[0..3]

  @@final:

  CMP  BL,otSLong  ; if OrdType >= otSLong

  JAE  @@exit  ; Exit

  CMP  BL,otSWord  ; if OrdType >= otSWord

  JAE  @@word  ; jmp @@word

  CMP  BL,otSByte  ; if OrdType = otSByte

  MOVSX  EAX,AL  ; AL <- Sign(EAX)

  JE  @@exit  ; Exit

  AND  EAX,$FF  ; clear HiWord(EAX)

  JMP  @@exit  ; Exit

  @@word:

  MOVSX  EAX,AX  ; AX <= Sign(EAX)

  JE  @@exit  ; if OrdType = otSWord then Exit

  AND  EAX,$FFFF  ; clear HiWord(EAX)

  @@exit:

  POP  EDI

  POP  EBX

end;

TypInfo.pas 中重载了 GetOrdProp 函数,将 PPropInfo 参数替换为 PropName,方便程序员调用,它其实也是调用了上面介绍的 GetOrdProp 函数。

function GetOrdProp(Instance: TObject; const PropName: string): Longint;

begin

  Result := GetOrdProp(Instance, FindPropInfo(Instance, PropName));

end;

下面是使用 GetOrdProp 的例子:

Self.Width := Self.Width - GetOrdProp(Self, 'Height');

上面的语句相当于:

Self.Width := Self.Width - Self.Height;

* 后文介绍的 Get___Prop 系列函数或者调用本函数,或者它的实现方法与本函数类似。

SetOrdProp 函数

SetOrdProp 函数是 GetOrdProp 的逆过程,它调用 TPropInfo.SetProc 函数指针设置对象的属性值。SetProc 指针的第一个字节的意义同 GetProc 一样,也是表示该 SetProc 是字段偏移、虚方法偏移和静态方法。

procedure SetOrdProp(Instance: TObject; PropInfo: PPropInfo; Value: Longint);

SetOrdProc 也根据属性名称重载了:

procedure SetOrdProp(Instance: TObject; const PropName: string; Value: Longint);

由于 SetOrdProp 的汇编代码与 GetOrdProp 的几乎一样,在此就不再列出。作为练习,试用一下:

SetOrdProp(Self, 'Height', Self.Height + 10);

该语句的功能相当于:

Self.Height := Self.Height + 10;

* 后文介绍的 Set___Prop 系列函数或者调用本函数,或者它的实现方法与本函数类似。

GetEnumProp / SetEnumProp 函数

GetEnumProp 函数获取枚举类型属性的枚举字符串,它调用 GetEnumName 转换 GetOrdProp 的返回值。

function GetEnumProp(Instance: TObject; PropInfo: PPropInfo): string;
function GetEnumProp(Instance: TObject; const PropName: string): string;

SetEnumProp 函数使用枚举字符串设置枚举类型属性值,它调用 GetEnumValue 转换枚举字符串后再调用 SetOrdProp 设置属性值。

procedure SetEnumProp(Instance: TObject; PropInfo: PPropInfo;
const Value: string);
procedure SetEnumProp(Instance: TObject; const PropName: string;
const Value: string);

GetSetProp / SetSetProp 函数

GetSetProp 函数用于获取集合类型属性的字符串值,它也是调用 GetOrdProp 获得属性值,然后调用 SetToString 函数把数值转换成字符串。

注意:GetOrdProp 函数返回值是 Integer,那么它是如何表示可以存储 256 个元素的集合类型呢?答案是:如果是 published 集合属性,那么该集合最大只能是 4 个字节,也就是最多只能存储 32 个元素。

function GetSetProp(Instance: TObject; PropInfo: PPropInfo;
Brackets: Boolean): string;
function GetSetProp(Instance: TObject; const PropName: string;
Brackets: Boolean = False): string;

SetSetProp 函数用于通过字符串设置集合类型属性的值。它先调用 StringToSet 函数把字符串转换为整数值,然后使用 SetOrdProp 函数设置属性值。

procedure SetSetProp(Instance: TObject; PropInfo: PPropInfo;
const Value: string);
procedure SetSetProp(Instance: TObject; const PropName: string;
const Value: string);

试验:  SetSetProp(Self, 'BorderIcons', '[biSystemMenu]');

GetObjectProp / SetObjectProp 函数

对象实际上是指针,也就是整数值,所以 GetObjectProp 直接调用 GetOrdProp 就可以了。

MinClass 参数指定得到的 Object 必须属于某个 class ,如果不是则返回 nil 。

function GetObjectProp(Instance: TObject; PropInfo: PPropInfo;
MinClass: TClass = nil): TObject;
function GetObjectProp(Instance: TObject; const PropName: string;
MinClass: TClass = nil): TObject;

SetObjectProp 用于设置属性的对象句柄。ValidateClass 参数表示是否需要检查传入的对象类型与属性信息的类信息是否兼容。

procedure SetObjectProp(Instance: TObject; PropInfo: PPropInfo;
Value: TObject; ValidateClass: Boolean = True);
procedure SetObjectProp(Instance: TObject; const PropName: string;
Value: TObject);

例子:

var
MyFont: TFont;
begin
MyFont := TFont.Create;
MyFont.Height :=  20;
SetObjectProp(Self, 'Font', MyFont);
end;

GetStrProp / SetStrProp 函数

GetStrProp 函数用于获得字符串类型的属性值。

function GetStrProp(Instance: TObject; PropInfo: PPropInfo): string;
function GetStrProp(Instance: TObject; const PropName: string): string;

由于 Delphi 支持三种类型的字符串,GetStrProp 根据字符串的类型,分别调用三个获得字符串属性值的函数:

case PropInfo^.PropType^.Kind of
tkString: GetShortStrPropAsLongStr(Instance, PropInfo, Result);
tkLString: GetLongStrProp(Instance, PropInfo, Result);
tkWString: GetWideStrPropAsLongStr(Instance, PropInfo, Result);
end;

其中 GetShortStrPropAsLongStr 又调用了 GetShortStrProp;GetWideStrPropAsLongStr 又调用了 GetWideStrProp,进行字符串间的类型转换。

SetStrProp 函数用于设置字符串类型的属性值。它的实现方法与 GetStrProp 类似。

procedure SetStrProp(Instance: TObject; PropInfo: PPropInfo;
const Value: string);
procedure SetStrProp(Instance: TObject; const PropName: string;
const Value: string);

你可能感兴趣的:(RTTI)