{ This file is part of the Free Pascal run time library. Copyright (c) 1999-2000 by Florian Klaempfl member of the Free Pascal development team See the file COPYING.FPC, included in this distribution, for details about the copyright. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. **********************************************************************} { This unit provides the same Functionality as the TypInfo Unit } { of Delphi } unit typinfo; interface {$MODE objfpc} {$h+} uses SysUtils; // temporary types: type {$ifndef HASVARIANT} Variant = Pointer; {$endif} {$MINENUMSIZE 1 this saves a lot of memory } // if you change one of the following enumeration types // you have also to change the compiler in an appropriate way ! TTypeKind = (tkUnknown,tkInteger,tkChar,tkEnumeration, tkFloat,tkSet,tkMethod,tkSString,tkLString,tkAString, tkWString,tkVariant,tkArray,tkRecord,tkInterface, tkClass,tkObject,tkWChar,tkBool,tkInt64,tkQWord, tkDynArray,tkInterfaceRaw); TOrdType = (otSByte,otUByte,otSWord,otUWord,otSLong,otULong); TFloatType = (ftSingle,ftDouble,ftExtended,ftComp,ftCurr); TMethodKind = (mkProcedure,mkFunction,mkConstructor,mkDestructor, mkClassProcedure, mkClassFunction); TParamFlags = set of (pfVar,pfConst,pfArray,pfAddress,pfReference,pfOut); TIntfFlag = (ifHasGuid,ifDispInterface,ifDispatch); TIntfFlags = set of TIntfFlag; TIntfFlagsBase = set of TIntfFlag; {$MINENUMSIZE DEFAULT} const ptField = 0; ptStatic = 1; ptVirtual = 2; ptConst = 3; tkString = tkSString; type TTypeKinds = set of TTypeKind; {$PACKRECORDS 1} TTypeInfo = record Kind : TTypeKind; Name : ShortString; // here the type data follows as TTypeData record end; PTypeInfo = ^TTypeInfo; PPTypeInfo = ^PTypeInfo; {$PACKRECORDS C} PTypeData = ^TTypeData; TTypeData = {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT} packed {$endif FPC_REQUIRES_PROPER_ALIGNMENT} record case TTypeKind of tkUnKnown,tkLString,tkWString,tkAString,tkVariant: (); tkInteger,tkChar,tkEnumeration,tkWChar: (OrdType : TOrdType; case TTypeKind of tkInteger,tkChar,tkEnumeration,tkBool,tkWChar : ( MinValue,MaxValue : Longint; case TTypeKind of tkEnumeration: ( BaseType : PTypeInfo; NameList : ShortString) ); tkSet: (CompType : PTypeInfo) ); tkFloat: (FloatType : TFloatType); tkSString: (MaxLength : Byte); tkClass: (ClassType : TClass; ParentInfo : PTypeInfo; PropCount : SmallInt; UnitName : ShortString // here the properties follow as array of TPropInfo ); tkMethod: (MethodKind : TMethodKind; ParamCount : Byte; ParamList : array[0..1023] of Char {in reality ParamList is a array[1..ParamCount] of: record Flags : TParamFlags; ParamName : ShortString; TypeName : ShortString; end; followed by ResultType : ShortString} ); tkInt64: (MinInt64Value, MaxInt64Value: Int64); tkQWord: (MinQWordValue, MaxQWordValue: QWord); tkInterface, tkInterfaceRaw: ( IntfParent: PPTypeInfo; IID: PGUID; IIDStr: ShortString; IntfUnit: ShortString; ); end; // unsed, just for completeness TPropData = {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT} packed {$endif FPC_REQUIRES_PROPER_ALIGNMENT} record PropCount : Word; PropList : record _alignmentdummy : ptrint; end; end; {$PACKRECORDS 1} PPropInfo = ^TPropInfo; TPropInfo = packed record PropType : PTypeInfo; GetProc : Pointer; SetProc : Pointer; StoredProc : Pointer; Index : Integer; Default : Longint; NameIndex : SmallInt; // contains the type of the Get/Set/Storedproc, see also ptxxx // bit 0..1 GetProc // 2..3 SetProc // 4..5 StoredProc // 6 : true, constant index property PropProcs : Byte; Name : ShortString; end; TProcInfoProc = Procedure(PropInfo : PPropInfo) of object; PPropList = ^TPropList; TPropList = array[0..65535] of PPropInfo; const tkAny = [Low(TTypeKind)..High(TTypeKind)]; tkMethods = [tkMethod]; tkProperties = tkAny-tkMethods-[tkUnknown]; // general property handling Function GetTypeData(TypeInfo : PTypeInfo) : PTypeData; Function GetPropInfo(TypeInfo : PTypeInfo;const PropName : string) : PPropInfo; Function GetPropInfo(TypeInfo : PTypeInfo;const PropName : string; AKinds : TTypeKinds) : PPropInfo; Function GetPropInfo(Instance: TObject; const PropName: string; AKinds: TTypeKinds) : PPropInfo; Function GetPropInfo(Instance: TObject; const PropName: string): PPropInfo; Function GetPropInfo(AClass: TClass; const PropName: string; AKinds: TTypeKinds) : PPropInfo; Function GetPropInfo(AClass: TClass; const PropName: string): PPropInfo; Function FindPropInfo(Instance: TObject; const PropName: string): PPropInfo; Function FindPropInfo(AClass:TClass;const PropName: string): PPropInfo; Procedure GetPropInfos(TypeInfo : PTypeInfo;PropList : PPropList); Function GetPropList(TypeInfo : PTypeInfo;TypeKinds : TTypeKinds; PropList : PPropList;Sorted : boolean = true):longint; Function GetPropList(TypeInfo: PTypeInfo; out PropList: PPropList): SizeInt; // Property information routines. Function IsStoredProp(Instance: TObject;PropInfo : PPropInfo) : Boolean; Function IsStoredProp(Instance: TObject; const PropName: string): Boolean; Function IsPublishedProp(Instance: TObject; const PropName: string): Boolean; Function IsPublishedProp(AClass: TClass; const PropName: string): Boolean; Function PropType(Instance: TObject; const PropName: string): TTypeKind; Function PropType(AClass: TClass; const PropName: string): TTypeKind; Function PropIsType(Instance: TObject; const PropName: string; TypeKind: TTypeKind): Boolean; Function PropIsType(AClass: TClass; const PropName: string; TypeKind: TTypeKind): Boolean; // subroutines to read/write properties Function GetOrdProp(Instance: TObject; PropInfo : PPropInfo) : Int64; Function GetOrdProp(Instance: TObject; const PropName: string): Int64; Procedure SetOrdProp(Instance: TObject; PropInfo : PPropInfo; Value : Int64); Procedure SetOrdProp(Instance: TObject; const PropName: string; Value: Int64); Function GetEnumProp(Instance: TObject; const PropName: string): string; Function GetEnumProp(Instance: TObject; const PropInfo: PPropInfo): string; Procedure SetEnumProp(Instance: TObject; const PropName: string;const Value: string); Procedure SetEnumProp(Instance: TObject; const PropInfo: PPropInfo;const Value: string); Function GetSetProp(Instance: TObject; const PropName: string): string; Function GetSetProp(Instance: TObject; const PropName: string; Brackets: Boolean): string; Function GetSetProp(Instance: TObject; const PropInfo: PPropInfo; Brackets: Boolean): string; Procedure SetSetProp(Instance: TObject; const PropName: string; const Value: string); Procedure SetSetProp(Instance: TObject; const PropInfo: PPropInfo; const Value: string); Function GetStrProp(Instance: TObject; PropInfo : PPropInfo) : Ansistring; Function GetStrProp(Instance: TObject; const PropName: string): string; Procedure SetStrProp(Instance: TObject; const PropName: string; const Value: AnsiString); Procedure SetStrProp(Instance: TObject; PropInfo : PPropInfo; const Value : Ansistring); {$ifdef HASWIDESTRING} Function GetWideStrProp(Instance: TObject; PropInfo: PPropInfo): WideString; Function GetWideStrProp(Instance: TObject; const PropName: string): WideString; Procedure SetWideStrProp(Instance: TObject; const PropName: string; const Value: WideString); Procedure SetWideStrProp(Instance: TObject; PropInfo: PPropInfo; const Value: WideString); {$endif HASWIDESTRING} Function GetFloatProp(Instance: TObject; PropInfo : PPropInfo) : Extended; Function GetFloatProp(Instance: TObject; const PropName: string): Extended; Procedure SetFloatProp(Instance: TObject; const PropName: string; Value: Extended); Procedure SetFloatProp(Instance: TObject; PropInfo : PPropInfo; Value : Extended); Function GetObjectProp(Instance: TObject; const PropName: string): TObject; Function GetObjectProp(Instance: TObject; const PropName: string; MinClass: TClass): TObject; Function GetObjectProp(Instance: TObject; PropInfo: PPropInfo): TObject; Function GetObjectProp(Instance: TObject; PropInfo: PPropInfo; MinClass: TClass): TObject; Procedure SetObjectProp(Instance: TObject; const PropName: string; Value: TObject); Procedure SetObjectProp(Instance: TObject; PropInfo: PPropInfo; Value: TObject); Function GetObjectPropClass(Instance: TObject; const PropName: string): TClass; Function GetMethodProp(Instance: TObject; PropInfo: PPropInfo) : TMethod; Function GetMethodProp(Instance: TObject; const PropName: string): TMethod; Procedure SetMethodProp(Instance: TObject; PropInfo: PPropInfo; const Value : TMethod); Procedure SetMethodProp(Instance: TObject; const PropName: string; const Value: TMethod); Function GetInt64Prop(Instance: TObject; PropInfo: PPropInfo): Int64; Function GetInt64Prop(Instance: TObject; const PropName: string): Int64; Procedure SetInt64Prop(Instance: TObject; PropInfo: PPropInfo; const Value: Int64); Procedure SetInt64Prop(Instance: TObject; const PropName: string; const Value: Int64); Function GetPropValue(Instance: TObject; const PropName: string): Variant; Function GetPropValue(Instance: TObject; const PropName: string; PreferStrings: Boolean): Variant; Procedure SetPropValue(Instance: TObject; const PropName: string; const Value: Variant); Function GetVariantProp(Instance: TObject; PropInfo : PPropInfo): Variant; Function GetVariantProp(Instance: TObject; const PropName: string): Variant; Procedure SetVariantProp(Instance: TObject; const PropName: string; const Value: Variant); Procedure SetVariantProp(Instance: TObject; PropInfo : PPropInfo; const Value: Variant); // Auxiliary routines, which may be useful Function GetEnumName(TypeInfo : PTypeInfo;Value : Integer) : string; Function GetEnumValue(TypeInfo : PTypeInfo;const Name : string) : Integer; function SetToString(PropInfo: PPropInfo; Value: Integer; Brackets: Boolean) : String; function SetToString(PropInfo: PPropInfo; Value: Integer) : String; function StringToSet(PropInfo: PPropInfo; const Value: string): Integer; const BooleanIdents: array[Boolean] of String = ('False', 'True'); DotSep: String = '.'; Type EPropertyError = Class(Exception); TGetPropValue = Function (Instance: TObject; const PropName: string; PreferStrings: Boolean) : Variant; TSetPropValue = Procedure (Instance: TObject; const PropName: string; const Value: Variant); TGetVariantProp = Function (Instance: TObject; PropInfo : PPropInfo): Variant; TSetVariantProp = Procedure (Instance: TObject; PropInfo : PPropInfo; const Value: Variant); Const OnGetPropValue : TGetPropValue = Nil; OnSetPropValue : TSetPropValue = Nil; OnGetVariantprop : TGetVariantProp = Nil; OnSetVariantprop : TSetVariantProp = Nil; Implementation uses rtlconsts; type PMethod = ^TMethod; { --------------------------------------------------------------------- Auxiliary methods ---------------------------------------------------------------------} function aligntoptr(p : pointer) : pointer; begin {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT} if (ptrint(p) mod sizeof(ptrint))<>0 then inc(ptrint(p),sizeof(ptrint)-ptrint(p) mod sizeof(ptrint)); {$endif FPC_REQUIRES_PROPER_ALIGNMENT} result:=p; end; Function GetEnumName(TypeInfo : PTypeInfo;Value : Integer) : string; Var PS : PShortString; PT : PTypeData; begin PT:=GetTypeData(TypeInfo); // ^.BaseType); // If PT^.MinValue<0 then Value:=Ord(Value<>0); {map to 0/1} PS:=@PT^.NameList; While Value>0 Do begin PS:=PShortString(pointer(PS)+PByte(PS)^+1); Dec(Value); end; Result:=PS^; end; Function GetEnumValue(TypeInfo : PTypeInfo;const Name : string) : Integer; Var PS : PShortString; PT : PTypeData; Count : longint; begin If Length(Name)=0 then exit(-1); PT:=GetTypeData(TypeInfo); Count:=0; Result:=-1; PS:=@PT^.NameList; While (Result=-1) and (PByte(PS)^<>0) do begin If CompareText(PS^, Name) = 0 then Result:=Count; PS:=PShortString(pointer(PS)+PByte(PS)^+1); Inc(Count); end; end; Function SetToString(PropInfo: PPropInfo; Value: Integer; Brackets: Boolean) : String; Var I : Integer; PTI : PTypeInfo; begin PTI:=GetTypeData(PropInfo^.PropType)^.CompType; Result:=''; For I:=0 to SizeOf(Integer)*8-1 do begin if ((Value and 1)<>0) then begin If Result='' then Result:=GetEnumName(PTI,i) else Result:=Result+','+GetEnumName(PTI,I); end; Value:=Value shr 1; end; if Brackets then Result:='['+Result+']'; end; Function SetToString(PropInfo: PPropInfo; Value: Integer) : String; begin Result:=SetToString(PropInfo,Value,False); end; Const SetDelim = ['[',']',',',' ']; Function GetNextElement(Var S : String) : String; Var J : Integer; begin J:=1; Result:=''; If Length(S)>0 then begin While (J<=Length(S)) and Not (S[j] in SetDelim) do Inc(j); Result:=Copy(S,1,j-1); Delete(S,1,j); end; end; Function StringToSet(PropInfo: PPropInfo; const Value: string): Integer; Var S,T : String; I : Integer; PTI : PTypeInfo; begin Result:=0; PTI:=GetTypeData(PropInfo^.PropType)^.Comptype; S:=Value; I:=1; If Length(S)>0 then begin While (I<=Length(S)) and (S[i] in SetDelim) do Inc(I); Delete(S,1,i-1); end; While (S<>'') do begin T:=GetNextElement(S); if T<>'' then begin I:=GetEnumValue(PTI,T); if (I<0) then raise EPropertyError.CreateFmt(SErrUnknownEnumValue, [T]); Result:=Result or (1 shl i); end; end; end; Function GetTypeData(TypeInfo : PTypeInfo) : PTypeData; begin GetTypeData:=PTypeData(aligntoptr(PTypeData(pointer(TypeInfo)+2+PByte(pointer(TypeInfo)+1)^))); end; { --------------------------------------------------------------------- Basic Type information functions. ---------------------------------------------------------------------} Function GetPropInfo(TypeInfo : PTypeInfo;const PropName : string) : PPropInfo; var hp : PTypeData; i : longint; p : string; pd : ^TPropData; begin P:=UpCase(PropName); while Assigned(TypeInfo) do begin // skip the name hp:=GetTypeData(Typeinfo); // the class info rtti the property rtti follows immediatly pd:=aligntoptr(pointer(pointer(@hp^.UnitName)+Length(hp^.UnitName)+1)); Result:=@pd^.PropList; for i:=1 to pd^.PropCount do begin // found a property of that name ? if Upcase(Result^.Name)=P then exit; // skip to next property Result:=PPropInfo(aligntoptr(pointer(@Result^.Name)+byte(Result^.Name[0])+1)); end; // parent class Typeinfo:=hp^.ParentInfo; end; Result:=Nil; end; Function GetPropInfo(TypeInfo : PTypeInfo;const PropName : string; Akinds : TTypeKinds) : PPropInfo; begin Result:=GetPropInfo(TypeInfo,PropName); If (Akinds<>[]) then If (Result<>Nil) then If Not (Result^.PropType^.Kind in AKinds) then Result:=Nil; end; Function GetPropInfo(AClass: TClass; const PropName: string; AKinds: TTypeKinds) : PPropInfo; begin Result:=GetPropInfo(PTypeInfo(AClass.ClassInfo),PropName,AKinds); end; Function GetPropInfo(Instance: TObject; const PropName: string; AKinds: TTypeKinds) : PPropInfo; begin Result:=GetPropInfo(Instance.ClassType,PropName,AKinds); end; Function GetPropInfo(Instance: TObject; const PropName: string): PPropInfo; begin Result:=GetPropInfo(Instance,PropName,[]); end; Function GetPropInfo(AClass: TClass; const PropName: string): PPropInfo; begin Result:=GetPropInfo(AClass,PropName,[]); end; Function FindPropInfo(Instance: TObject; const PropName: string): PPropInfo; begin result:=GetPropInfo(Instance, PropName); if Result=nil then Raise EPropertyError.CreateFmt(SErrPropertyNotFound, [PropName]); end; Function FindPropInfo(AClass:TClass;const PropName: string): PPropInfo; begin result:=GetPropInfo(AClass,PropName); if result=nil then Raise EPropertyError.CreateFmt(SErrPropertyNotFound, [PropName]); end; Function IsStoredProp(Instance : TObject;PropInfo : PPropInfo) : Boolean; type TBooleanFunc=function:boolean of object; var AMethod : TMethod; begin case (PropInfo^.PropProcs shr 4) and 3 of ptfield: Result:=PBoolean(Pointer(Instance)+Longint(PropInfo^.StoredProc))^; ptconst: Result:=LongBool(PropInfo^.StoredProc); ptstatic, ptvirtual: begin if (PropInfo^.PropProcs shr 4) and 3=ptstatic then AMethod.Code:=PropInfo^.StoredProc else AMethod.Code:=ppointer(Pointer(Instance.ClassType)+Longint(PropInfo^.StoredProc))^; AMethod.Data:=Instance; Result:=TBooleanFunc(AMethod)(); end; end; end; Procedure GetPropInfos(TypeInfo : PTypeInfo;PropList : PPropList); { Store Pointers to property information in the list pointed to by proplist. PRopList must contain enough space to hold ALL properties. } Var TD : PTypeData; TP : PPropInfo; Count : Longint; begin TD:=GetTypeData(TypeInfo); // Get this objects TOTAL published properties count TP:=aligntoptr(PPropInfo(aligntoptr((@TD^.UnitName+Length(TD^.UnitName)+1)))); Count:=PWord(TP)^; // Now point TP to first propinfo record. Inc(Pointer(TP),SizeOF(Word)); tp:=aligntoptr(tp); While Count>0 do begin PropList^[0]:=TP; Inc(Pointer(PropList),SizeOf(Pointer)); // Point to TP next propinfo record. // Located at Name[Length(Name)+1] ! TP:=aligntoptr(PPropInfo(pointer(@TP^.Name)+PByte(@TP^.Name)^+1)); Dec(Count); end; // recursive call for parent info. If TD^.Parentinfo<>Nil then GetPropInfos (TD^.ParentInfo,PropList); end; Procedure InsertProp (PL : PProplist;PI : PPropInfo; Count : longint); Var I : Longint; begin I:=0; While (IPL^[I]^.Name) do Inc(I); If I0 then begin GetMem(TempList,Count*SizeOf(Pointer)); Try GetPropInfos(TypeInfo,TempList); For I:=0 to Count-1 do begin PropInfo:=TempList^[i]; If PropInfo^.PropType^.Kind in TypeKinds then begin If (PropList<>Nil) then DoInsertProp(PropList,PropInfo,Result); Inc(Result); end; end; finally FreeMem(TempList,Count*SizeOf(Pointer)); end; end; end; Function GetPropList(TypeInfo: PTypeInfo; out PropList: PPropList): SizeInt; begin result:=GetTypeData(TypeInfo)^.Propcount; if result>0 then begin getmem(PropList,result*sizeof(pointer)); GetPropInfos(TypeInfo,PropList); end; end; { --------------------------------------------------------------------- Property access functions ---------------------------------------------------------------------} { --------------------------------------------------------------------- Ordinal properties ---------------------------------------------------------------------} Function GetOrdProp(Instance : TObject;PropInfo : PPropInfo) : Int64; type TGetInt64ProcIndex=function(index:longint):Int64 of object; TGetInt64Proc=function():Int64 of object; TGetIntegerProcIndex=function(index:longint):longint of object; TGetIntegerProc=function:longint of object; TGetWordProcIndex=function(index:longint):word of object; TGetWordProc=function:word of object; TGetByteProcIndex=function(index:longint):Byte of object; TGetByteProc=function:Byte of object; var TypeInfo: PTypeInfo; AMethod : TMethod; DataSize: Integer; OrdType: TOrdType; Signed: Boolean; begin Result:=0; TypeInfo := PropInfo^.PropType; Signed := false; DataSize := 4; case TypeInfo^.Kind of tkChar, tkBool: DataSize:=1; tkWChar: DataSize:=2; tkEnumeration, tkInteger: begin OrdType:=GetTypeData(TypeInfo)^.OrdType; case OrdType of otSByte,otUByte: DataSize := 1; otSWord,otUWord: DataSize := 2; end; Signed := OrdType in [otSByte,otSWord,otSLong]; end; tkInt64 : begin DataSize:=8; Signed:=true; end; tkQword : begin DataSize:=8; Signed:=false; end; end; case (PropInfo^.PropProcs) and 3 of ptfield: if Signed then begin case DataSize of 1: Result:=PShortInt(Pointer(Instance)+Ptrint(PropInfo^.GetProc))^; 2: Result:=PSmallInt(Pointer(Instance)+Ptrint(PropInfo^.GetProc))^; 4: Result:=PLongint(Pointer(Instance)+Ptrint(PropInfo^.GetProc))^; 8: Result:=PInt64(Pointer(Instance)+Ptrint(PropInfo^.GetProc))^; end; end else begin case DataSize of 1: Result:=PByte(Pointer(Instance)+Ptrint(PropInfo^.GetProc))^; 2: Result:=PWord(Pointer(Instance)+Ptrint(PropInfo^.GetProc))^; 4: Result:=PLongint(Pointer(Instance)+Ptrint(PropInfo^.GetProc))^; 8: Result:=PInt64(Pointer(Instance)+Ptrint(PropInfo^.GetProc))^; end; end; ptstatic, ptvirtual : begin if (PropInfo^.PropProcs and 3)=ptStatic then AMethod.Code:=PropInfo^.GetProc else AMethod.Code:=PPointer(Pointer(Instance.ClassType)+Ptrint(PropInfo^.GetProc))^; AMethod.Data:=Instance; if ((PropInfo^.PropProcs shr 6) and 1)<>0 then begin case DataSize of 1: Result:=TGetByteProcIndex(AMethod)(PropInfo^.Index); 2: Result:=TGetWordProcIndex(AMethod)(PropInfo^.Index); 4: Result:=TGetIntegerProcIndex(AMethod)(PropInfo^.Index); 8: result:=TGetInt64ProcIndex(AMethod)(PropInfo^.Index) end; end else begin case DataSize of 1: Result:=TGetByteProc(AMethod)(); 2: Result:=TGetWordProc(AMethod)(); 4: Result:=TGetIntegerProc(AMethod)(); 8: result:=TGetInt64Proc(AMethod)(); end; end; if Signed then begin case DataSize of 1: Result:=ShortInt(Result); 2: Result:=SmallInt(Result); end; end; end; end; end; Procedure SetOrdProp(Instance : TObject;PropInfo : PPropInfo;Value : Int64); type TSetInt64ProcIndex=procedure(index:longint;i:Int64) of object; TSetInt64Proc=procedure(i:Int64) of object; TSetIntegerProcIndex=procedure(index,i:longint) of object; TSetIntegerProc=procedure(i:longint) of object; var DataSize: Integer; AMethod : TMethod; begin if PropInfo^.PropType^.Kind in [tkInt64,tkQword] then DataSize := 8 else DataSize := 4; if PropInfo^.PropType^.Kind <> tkClass then begin { cut off unnecessary stuff } case GetTypeData(PropInfo^.PropType)^.OrdType of otSWord,otUWord: begin Value:=Value and $ffff; DataSize := 2; end; otSByte,otUByte: begin Value:=Value and $ff; DataSize := 1; end; end; end; case (PropInfo^.PropProcs shr 2) and 3 of ptfield: case DataSize of 1: PByte(Pointer(Instance)+Ptrint(PropInfo^.SetProc))^:=Byte(Value); 2: PWord(Pointer(Instance)+Ptrint(PropInfo^.SetProc))^:=Word(Value); 4:PLongint(Pointer(Instance)+Ptrint(PropInfo^.SetProc))^:=Longint(Value); 8: PInt64(Pointer(Instance)+Ptrint(PropInfo^.SetProc))^:=Value; end; ptstatic, ptvirtual : begin if ((PropInfo^.PropProcs shr 2) and 3)=ptStatic then AMethod.Code:=PropInfo^.SetProc else AMethod.Code:=PPointer(Pointer(Instance.ClassType)+Ptrint(PropInfo^.SetProc))^; AMethod.Data:=Instance; if datasize=8 then begin if ((PropInfo^.PropProcs shr 6) and 1)<>0 then TSetInt64ProcIndex(AMethod)(PropInfo^.Index,Value) else TSetInt64Proc(AMethod)(Value); end else begin if ((PropInfo^.PropProcs shr 6) and 1)<>0 then TSetIntegerProcIndex(AMethod)(PropInfo^.Index,Value) else TSetIntegerProc(AMethod)(Value); end; end; end; end; Function GetOrdProp(Instance: TObject; const PropName: string): Int64; begin Result:=GetOrdProp(Instance,FindPropInfo(Instance,PropName)); end; Procedure SetOrdProp(Instance: TObject; const PropName: string; Value: Int64); begin SetOrdProp(Instance,FindPropInfo(Instance,PropName),Value); end; Function GetEnumProp(Instance: TObject; Const PropInfo: PPropInfo): string; begin Result:=GetEnumName(PropInfo^.PropType, GetOrdProp(Instance, PropInfo)); end; Function GetEnumProp(Instance: TObject; const PropName: string): string; begin Result:=GetEnumProp(Instance,FindPropInfo(Instance,PropName)); end; Procedure SetEnumProp(Instance: TObject; const PropName: string; const Value: string); begin SetEnumProp(Instance,FindPropInfo(Instance,PropName),Value); end; Procedure SetEnumProp(Instance: TObject; Const PropInfo : PPropInfo; const Value: string); Var PV : Longint; begin If PropInfo<>Nil then begin PV:=GetEnumValue(PropInfo^.PropType, Value); if (PV<0) then raise EPropertyError.CreateFmt(SErrUnknownEnumValue, [Value]); SetOrdProp(Instance, PropInfo,PV); end; end; { --------------------------------------------------------------------- Int64 wrappers ---------------------------------------------------------------------} Function GetInt64Prop(Instance: TObject; PropInfo: PPropInfo): Int64; begin Result:=GetOrdProp(Instance,PropInfo); end; procedure SetInt64Prop(Instance: TObject; PropInfo: PPropInfo; const Value: Int64); begin SetOrdProp(Instance,PropInfo,Value); end; Function GetInt64Prop(Instance: TObject; const PropName: string): Int64; begin Result:=GetInt64Prop(Instance,FindPropInfo(Instance,PropName)); end; Procedure SetInt64Prop(Instance: TObject; const PropName: string; const Value: Int64); begin SetInt64Prop(Instance,FindPropInfo(Instance,PropName),Value); end; { --------------------------------------------------------------------- Set properties ---------------------------------------------------------------------} Function GetSetProp(Instance: TObject; const PropName: string): string; begin Result:=GetSetProp(Instance,PropName,False); end; Function GetSetProp(Instance: TObject; const PropName: string; Brackets: Boolean): string; begin Result:=GetSetProp(Instance,FindPropInfo(Instance,PropName),Brackets); end; Function GetSetProp(Instance: TObject; const PropInfo: PPropInfo; Brackets: Boolean): string; begin Result:=SetToString(PropInfo,GetOrdProp(Instance,PropInfo),Brackets); end; Procedure SetSetProp(Instance: TObject; const PropName: string; const Value: string); begin SetSetProp(Instance,FindPropInfo(Instance,PropName),Value); end; Procedure SetSetProp(Instance: TObject; const PropInfo: PPropInfo; const Value: string); begin SetOrdProp(Instance,PropInfo,StringToSet(PropInfo,Value)); end; { --------------------------------------------------------------------- Object properties ---------------------------------------------------------------------} Function GetObjectProp(Instance: TObject; const PropName: string): TObject; begin Result:=GetObjectProp(Instance,PropName,Nil); end; Function GetObjectProp(Instance: TObject; const PropName: string; MinClass: TClass): TObject; begin Result:=GetObjectProp(Instance,FindPropInfo(Instance,PropName),MinClass); end; Function GetObjectProp(Instance: TObject; PropInfo : PPropInfo): TObject; begin Result:=GetObjectProp(Instance,PropInfo,Nil); end; Function GetObjectProp(Instance: TObject; PropInfo : PPropInfo; MinClass: TClass): TObject; begin {$ifdef cpu64} Result:=TObject(GetInt64Prop(Instance,PropInfo)); {$else cpu64} Result:=TObject(PtrInt(GetOrdProp(Instance,PropInfo))); {$endif cpu64} If (MinClass<>Nil) and (Result<>Nil) Then If Not Result.InheritsFrom(MinClass) then Result:=Nil; end; Procedure SetObjectProp(Instance: TObject; const PropName: string; Value: TObject); begin SetObjectProp(Instance,FindPropInfo(Instance,PropName),Value); end; Procedure SetObjectProp(Instance: TObject; PropInfo : PPropInfo; Value: TObject); begin {$ifdef cpu64} SetInt64Prop(Instance,PropInfo,Int64(Value)); {$else cpu64} SetOrdProp(Instance,PropInfo,Integer(Value)); {$endif cpu64} end; Function GetObjectPropClass(Instance: TObject; const PropName: string): TClass; begin Result:=GetTypeData(FindPropInfo(Instance,PropName)^.PropType)^.ClassType; end; { --------------------------------------------------------------------- String properties ---------------------------------------------------------------------} Function GetStrProp(Instance: TObject; PropInfo: PPropInfo): AnsiString; type TGetShortStrProcIndex=function(index:longint):ShortString of object; TGetShortStrProc=function():ShortString of object; TGetAnsiStrProcIndex=function(index:longint):AnsiString of object; TGetAnsiStrProc=function():AnsiString of object; var AMethod : TMethod; begin Result:=''; case Propinfo^.PropType^.Kind of {$ifdef HASWIDESTRING} tkWString: Result:=GetWideStrProp(Instance,PropInfo); {$endif HASWIDESTRING} tkSString: begin case (PropInfo^.PropProcs) and 3 of ptField: Result := PShortString(Pointer(Instance) + LongWord(PropInfo^.GetProc))^; ptstatic, ptvirtual : begin if (PropInfo^.PropProcs and 3)=ptStatic then AMethod.Code:=PropInfo^.GetProc else AMethod.Code:=PPointer(Pointer(Instance.ClassType)+Ptrint(PropInfo^.GetProc))^; AMethod.Data:=Instance; if ((PropInfo^.PropProcs shr 6) and 1)<>0 then Result:=TGetShortStrProcIndex(AMethod)(PropInfo^.Index) else Result:=TGetShortStrProc(AMethod)(); end; end; end; tkAString: begin case (PropInfo^.PropProcs) and 3 of ptField: Result := PAnsiString(Pointer(Instance) + LongWord(PropInfo^.GetProc))^; ptstatic, ptvirtual : begin if (PropInfo^.PropProcs and 3)=ptStatic then AMethod.Code:=PropInfo^.GetProc else AMethod.Code:=PPointer(Pointer(Instance.ClassType)+Ptrint(PropInfo^.GetProc))^; AMethod.Data:=Instance; if ((PropInfo^.PropProcs shr 6) and 1)<>0 then Result:=TGetAnsiStrProcIndex(AMethod)(PropInfo^.Index) else Result:=TGetAnsiStrProc(AMethod)(); end; end; end; end; end; Procedure SetStrProp(Instance : TObject;PropInfo : PPropInfo; const Value : AnsiString); type TSetShortStrProcIndex=procedure(index:longint;const s:ShortString) of object; TSetShortStrProc=procedure(const s:ShortString) of object; TSetAnsiStrProcIndex=procedure(index:longint;s:AnsiString) of object; TSetAnsiStrProc=procedure(s:AnsiString) of object; var AMethod : TMethod; begin case Propinfo^.PropType^.Kind of {$ifdef HASWIDESTRING} tkWString: SetWideStrProp(Instance,PropInfo,Value); {$endif HASWIDESTRING} tkSString: begin case (PropInfo^.PropProcs shr 2) and 3 of ptField: PShortString(Pointer(Instance) + LongWord(PropInfo^.SetProc))^:=Value; ptstatic, ptvirtual : begin if (PropInfo^.PropProcs and 3)=ptStatic then AMethod.Code:=PropInfo^.SetProc else AMethod.Code:=PPointer(Pointer(Instance.ClassType)+Ptrint(PropInfo^.SetProc))^; AMethod.Data:=Instance; if ((PropInfo^.PropProcs shr 6) and 1)<>0 then TSetShortStrProcIndex(AMethod)(PropInfo^.Index,Value) else TSetShortStrProc(AMethod)(Value); end; end; end; tkAString: begin case (PropInfo^.PropProcs shr 2) and 3 of ptField: PAnsiString(Pointer(Instance) + LongWord(PropInfo^.SetProc))^:=Value; ptstatic, ptvirtual : begin if ((PropInfo^.PropProcs shr 2) and 3)=ptStatic then AMethod.Code:=PropInfo^.SetProc else AMethod.Code:=PPointer(Pointer(Instance.ClassType)+Ptrint(PropInfo^.SetProc))^; AMethod.Data:=Instance; if ((PropInfo^.PropProcs shr 6) and 1)<>0 then TSetAnsiStrProcIndex(AMethod)(PropInfo^.Index,Value) else TSetAnsiStrProc(AMethod)(Value); end; end; end; end; end; Function GetStrProp(Instance: TObject; const PropName: string): string; begin Result:=GetStrProp(Instance,FindPropInfo(Instance,PropName)); end; Procedure SetStrProp(Instance: TObject; const PropName: string; const Value: AnsiString); begin SetStrProp(Instance,FindPropInfo(Instance,PropName),Value); end; {$ifdef HASWIDESTRING} Function GetWideStrProp(Instance: TObject; const PropName: string): WideString; begin Result:=GetWideStrProp(Instance, FindPropInfo(Instance, PropName)); end; procedure SetWideStrProp(Instance: TObject; const PropName: string; const Value: WideString); begin SetWideStrProp(Instance,FindPropInfo(Instance,PropName),Value); end; Function GetWideStrProp(Instance: TObject; PropInfo: PPropInfo): WideString; type TGetWideStrProcIndex=function(index:longint):WideString of object; TGetWideStrProc=function():WideString of object; var AMethod : TMethod; begin Result:=''; case Propinfo^.PropType^.Kind of tkSString,tkAString: Result:=GetStrProp(Instance,PropInfo); tkWString: begin case (PropInfo^.PropProcs) and 3 of ptField: Result := PWideString(Pointer(Instance)+PtrUInt(PropInfo^.GetProc))^; ptstatic, ptvirtual : begin if (PropInfo^.PropProcs and 3)=ptStatic then AMethod.Code:=PropInfo^.GetProc else AMethod.Code:=PPointer(Pointer(Instance.ClassType)+PtrUInt(PropInfo^.GetProc))^; AMethod.Data:=Instance; if ((PropInfo^.PropProcs shr 6) and 1)<>0 then Result:=TGetWideStrProcIndex(AMethod)(PropInfo^.Index) else Result:=TGetWideStrProc(AMethod)(); end; end; end; end; end; Procedure SetWideStrProp(Instance: TObject; PropInfo: PPropInfo; const Value: WideString); type TSetWideStrProcIndex=procedure(index:longint;s:WideString) of object; TSetWideStrProc=procedure(s:WideString) of object; var AMethod : TMethod; begin case Propinfo^.PropType^.Kind of tkSString,tkAString: SetStrProp(Instance,PropInfo,Value); tkWString: begin case (PropInfo^.PropProcs shr 2) and 3 of ptField: PWideString(Pointer(Instance)+PtrUInt(PropInfo^.SetProc))^:=Value; ptstatic, ptvirtual : begin if ((PropInfo^.PropProcs shr 2) and 3)=ptStatic then AMethod.Code:=PropInfo^.SetProc else AMethod.Code:=PPointer(Pointer(Instance.ClassType)+PtrUInt(PropInfo^.SetProc))^; AMethod.Data:=Instance; if ((PropInfo^.PropProcs shr 6) and 1)<>0 then TSetWideStrProcIndex(AMethod)(PropInfo^.Index,Value) else TSetWideStrProc(AMethod)(Value); end; end; end; end; end; {$endif HASWIDESTRING} { --------------------------------------------------------------------- Float properties ---------------------------------------------------------------------} function GetFloatProp(Instance : TObject;PropInfo : PPropInfo) : Extended; type TGetExtendedProc = function:Extended of object; TGetExtendedProcIndex = function(Index: integer): Extended of object; TGetDoubleProc = function:Double of object; TGetDoubleProcIndex = function(Index: integer): Double of object; TGetSingleProc = function:Single of object; TGetSingleProcIndex = function(Index: integer):Single of object; {$ifdef HASCURRENCY} TGetCurrencyProc = function : Currency of object; TGetCurrencyProcIndex = function(Index: integer) : Currency of object; {$endif HASCURRENCY} var AMethod : TMethod; begin Result:=0.0; case PropInfo^.PropProcs and 3 of ptField: Case GetTypeData(PropInfo^.PropType)^.FloatType of ftSingle: Result:=PSingle(Pointer(Instance)+Ptrint(PropInfo^.GetProc))^; ftDouble: Result:=PDouble(Pointer(Instance)+Ptrint(PropInfo^.GetProc))^; ftExtended: Result:=PExtended(Pointer(Instance)+Ptrint(PropInfo^.GetProc))^; ftcomp: Result:=PComp(Pointer(Instance)+Ptrint(PropInfo^.GetProc))^; {$ifdef HASCURRENCY} ftcurr: Result:=PCurrency(Pointer(Instance)+Ptrint(PropInfo^.GetProc))^; {$endif HASCURRENCY} end; ptStatic, ptVirtual: begin if (PropInfo^.PropProcs and 3)=ptStatic then AMethod.Code:=PropInfo^.GetProc else AMethod.Code:=PPointer(Pointer(Instance.ClassType)+Ptrint(PropInfo^.GetProc))^; AMethod.Data:=Instance; Case GetTypeData(PropInfo^.PropType)^.FloatType of ftSingle: if ((PropInfo^.PropProcs shr 6) and 1)<>0 then Result:=TGetSingleProc(AMethod)() else Result:=TGetSingleProcIndex(AMethod)(PropInfo^.Index); ftDouble: if ((PropInfo^.PropProcs shr 6) and 1)<>0 then Result:=TGetDoubleProc(AMethod)() else Result:=TGetDoubleProcIndex(AMethod)(PropInfo^.Index); ftExtended: if ((PropInfo^.PropProcs shr 6) and 1)<>0 then Result:=TGetExtendedProc(AMethod)() else Result:=TGetExtendedProcIndex(AMethod)(PropInfo^.Index); {$ifdef HASCURRENCY} ftCurr: if ((PropInfo^.PropProcs shr 6) and 1)<>0 then Result:=TGetCurrencyProc(AMethod)() else Result:=TGetCurrencyProcIndex(AMethod)(PropInfo^.Index); {$endif HASCURRENCY} end; end; end; end; Procedure SetFloatProp(Instance : TObject;PropInfo : PPropInfo; Value : Extended); type TSetExtendedProc = procedure(const AValue: Extended) of object; TSetExtendedProcIndex = procedure(Index: integer; const AValue: Extended) of object; TSetDoubleProc = procedure(const AValue: Double) of object; TSetDoubleProcIndex = procedure(Index: integer; const AValue: Double) of object; TSetSingleProc = procedure(const AValue: Single) of object; TSetSingleProcIndex = procedure(Index: integer; const AValue: Single) of object; {$ifdef HASCURRENCY} TSetCurrencyProc = procedure(const AValue: Currency) of object; TSetCurrencyProcIndex = procedure(Index: integer; const AValue: Currency) of object; {$endif HASCURRENCY} Var AMethod : TMethod; begin case (PropInfo^.PropProcs shr 2) and 3 of ptfield: Case GetTypeData(PropInfo^.PropType)^.FloatType of ftSingle: PSingle(Pointer(Instance)+Ptrint(PropInfo^.SetProc))^:=Value; ftDouble: PDouble(Pointer(Instance)+Ptrint(PropInfo^.SetProc))^:=Value; ftExtended: PExtended(Pointer(Instance)+Ptrint(PropInfo^.SetProc))^:=Value; {$ifdef FPC_COMP_IS_INT64} ftComp: PComp(Pointer(Instance)+PtrUInt(PropInfo^.SetProc))^:=trunc(Value); {$else FPC_COMP_IS_INT64} ftComp: PComp(Pointer(Instance)+PtrUInt(PropInfo^.SetProc))^:=Value; {$endif FPC_COMP_IS_INT64} {$ifdef HASCURRENCY} ftCurr: PCurrency(Pointer(Instance)+PtrUInt(PropInfo^.SetProc))^:=Value; {$endif HASCURRENCY} end; ptStatic, ptVirtual: begin if ((PropInfo^.PropProcs shr 2) and 3)=ptStatic then AMethod.Code:=PropInfo^.SetProc else AMethod.Code:=PPointer(Pointer(Instance.ClassType)+Ptrint(PropInfo^.SetProc))^; AMethod.Data:=Instance; Case GetTypeData(PropInfo^.PropType)^.FloatType of ftSingle: if ((PropInfo^.PropProcs shr 6) and 1)<>0 then TSetSingleProc(AMethod)(Value) else TSetSingleProcIndex(AMethod)(PropInfo^.Index,Value); ftDouble: if ((PropInfo^.PropProcs shr 6) and 1)<>0 then TSetDoubleProc(AMethod)(Value) else TSetDoubleProcIndex(AMethod)(PropInfo^.Index,Value); ftExtended: if ((PropInfo^.PropProcs shr 6) and 1)<>0 then TSetExtendedProc(AMethod)(Value) else TSetExtendedProcIndex(AMethod)(PropInfo^.Index,Value); {$ifdef HASCURRENCY} ftCurr: if ((PropInfo^.PropProcs shr 6) and 1)<>0 then TSetCurrencyProc(AMethod)(Value) else TSetCurrencyProcIndex(AMethod)(PropInfo^.Index,Value); {$endif HASCURRENCY} end; end; end; end; function GetFloatProp(Instance: TObject; const PropName: string): Extended; begin Result:=GetFloatProp(Instance,FindPropInfo(Instance,PropName)) end; Procedure SetFloatProp(Instance: TObject; const PropName: string; Value: Extended); begin SetFloatProp(Instance,FindPropInfo(Instance,PropName),Value); end; { --------------------------------------------------------------------- Method properties ---------------------------------------------------------------------} Function GetMethodProp(Instance : TObject;PropInfo : PPropInfo) : TMethod; type TGetMethodProcIndex=function(Index: Longint): TMethod of object; TGetMethodProc=function(): TMethod of object; var value: PMethod; AMethod : TMethod; begin Result.Code:=nil; Result.Data:=nil; case (PropInfo^.PropProcs) and 3 of ptfield: begin Value:=PMethod(Pointer(Instance)+Ptrint(PropInfo^.GetProc)); if Value<>nil then Result:=Value^; end; ptstatic, ptvirtual : begin if (PropInfo^.PropProcs and 3)=ptStatic then AMethod.Code:=PropInfo^.GetProc else AMethod.Code:=PPointer(Pointer(Instance.ClassType)+Ptrint(PropInfo^.GetProc))^; AMethod.Data:=Instance; if ((PropInfo^.PropProcs shr 6) and 1)<>0 then Result:=TGetMethodProcIndex(AMethod)(PropInfo^.Index) else Result:=TGetMethodProc(AMethod)(); end; end; end; Procedure SetMethodProp(Instance : TObject;PropInfo : PPropInfo; const Value : TMethod); type TSetMethodProcIndex=procedure(index:longint;p:PMethod) of object; TSetMethodProc=procedure(p:PMethod) of object; var AMethod : TMethod; begin case (PropInfo^.PropProcs shr 2) and 3 of ptfield: PMethod(Pointer(Instance)+Ptrint(PropInfo^.SetProc))^ := Value; ptstatic, ptvirtual : begin if ((PropInfo^.PropProcs shr 2) and 3)=ptStatic then AMethod.Code:=PropInfo^.SetProc else AMethod.Code:=PPointer(Pointer(Instance.ClassType)+Ptrint(PropInfo^.SetProc))^; AMethod.Data:=Instance; if ((PropInfo^.PropProcs shr 6) and 1)<>0 then TSetMethodProcIndex(AMethod)(PropInfo^.Index,@Value) else TSetMethodProc(AMethod)(@Value); end; end; end; Function GetMethodProp(Instance: TObject; const PropName: string): TMethod; begin Result:=GetMethodProp(Instance,FindPropInfo(Instance,PropName)); end; Procedure SetMethodProp(Instance: TObject; const PropName: string; const Value: TMethod); begin SetMethodProp(Instance,FindPropInfo(Instance,PropName),Value); end; { --------------------------------------------------------------------- Variant properties ---------------------------------------------------------------------} Procedure CheckVariantEvent(P : Pointer); begin If (P=Nil) then Raise Exception.Create(SErrNoVariantSupport); end; Function GetVariantProp(Instance : TObject;PropInfo : PPropInfo): Variant; begin CheckVariantEvent(Pointer(OnGetVariantProp)); Result:=OnGetVariantProp(Instance,PropInfo); end; Procedure SetVariantProp(Instance : TObject;PropInfo : PPropInfo; const Value: Variant); begin CheckVariantEvent(Pointer(OnSetVariantProp)); OnSetVariantProp(Instance,PropInfo,Value); end; Function GetVariantProp(Instance: TObject; const PropName: string): Variant; begin Result:=GetVariantProp(Instance,FindPropInfo(Instance,PropName)); end; Procedure SetVariantProp(Instance: TObject; const PropName: string; const Value: Variant); begin SetVariantprop(instance,FindpropInfo(Instance,PropName),Value); end; { --------------------------------------------------------------------- All properties through variant. ---------------------------------------------------------------------} Function GetPropValue(Instance: TObject; const PropName: string): Variant; begin Result:=GetPropValue(Instance,PropName,True); end; Function GetPropValue(Instance: TObject; const PropName: string; PreferStrings: Boolean): Variant; begin CheckVariantEvent(Pointer(OnGetPropValue)); Result:=OnGetPropValue(Instance,PropName,PreferStrings) end; Procedure SetPropValue(Instance: TObject; const PropName: string; const Value: Variant); begin CheckVariantEvent(Pointer(OnSetPropValue)); OnSetPropValue(Instance,PropName,Value); end; { --------------------------------------------------------------------- Easy access methods that appeared in Delphi 5 ---------------------------------------------------------------------} Function IsPublishedProp(Instance: TObject; const PropName: string): Boolean; begin Result:=GetPropInfo(Instance,PropName)<>Nil; end; Function IsPublishedProp(AClass: TClass; const PropName: string): Boolean; begin Result:=GetPropInfo(AClass,PropName)<>Nil; end; Function PropIsType(Instance: TObject; const PropName: string; TypeKind: TTypeKind): Boolean; begin Result:=FindPropInfo(Instance,PropName)^.PropType^.Kind=TypeKind end; Function PropIsType(AClass: TClass; const PropName: string; TypeKind: TTypeKind): Boolean; begin Result:=PropType(AClass,PropName)=TypeKind end; Function PropType(Instance: TObject; const PropName: string): TTypeKind; begin Result:=FindPropInfo(Instance,PropName)^.PropType^.Kind; end; Function PropType(AClass: TClass; const PropName: string): TTypeKind; begin Result:=FindPropInfo(AClass,PropName)^.PropType^.Kind; end; Function IsStoredProp(Instance: TObject; const PropName: string): Boolean; begin Result:=IsStoredProp(instance,FindPropInfo(Instance,PropName)); end; end.