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 EBXend;
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);