{ This file is part of the Pas2JS run time library. Copyright (c) 2018 by Mattias Gaertner 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. **********************************************************************} unit TypInfo; {$mode objfpc} {$modeswitch externalclass} interface uses SysUtils, Types, RTLConsts, JS; type // TCallConv for compatibility with Delphi/FPC, ignored under pas2js TCallConv = (ccReg, ccCdecl, ccPascal, ccStdCall, ccSafeCall, ccCppdecl, ccFar16, ccOldFPCCall, ccInternProc, ccSysCall, ccSoftFloat, ccMWPascal); { TSectionRTTI } TSectionRTTI = class external name 'rtl.tSectionRTTI'(TJSObject) end; { TTypeInfoModule } TTypeInfoModule = class external name 'pasmodule'(TJSObject) public Name: String external name '$name'; RTTI: TSectionRTTI external name '$rtti'; end; TTypeInfoAttributes = type TJSValueDynArray; { TTypeInfo } TTypeInfo = class external name 'rtl.tTypeInfo' public Name: String external name 'name'; Kind: TTypeKind external name 'kind'; Attributes: TTypeInfoAttributes external name 'attr'; // can be undefined Module: TTypeInfoModule external name '$module'; // can be undefined end; TTypeInfoClassOf = class of TTypeInfo; PTypeInfo = Pointer; // for compatibility with Delphi/FPC, under pas2js it is a TTypeInfo TOrdType = ( otSByte, // 0 otUByte, // 1 otSWord, // 2 otUWord, // 3 otSLong, // 4 otULong, // 5 otSIntDouble, // 6 NativeInt otUIntDouble // 7 NativeUInt ); { TTypeInfoInteger - Kind = tkInteger } TTypeInfoInteger = class external name 'rtl.tTypeInfoInteger'(TTypeInfo) public MinValue: NativeInt external name 'minvalue'; MaxValue: NativeInt external name 'maxvalue'; OrdType : TOrdType external name 'ordtype'; end; { TEnumType } TEnumType = class external name 'anonymous' private function GetIntToName(Index: NativeInt): String; external name '[]'; function GetNameToInt(Name: String): NativeInt; external name '[]'; public property IntToName[Index: NativeInt]: String read GetIntToName; property NameToInt[Name: String]: NativeInt read GetNameToInt; end; { TTypeInfoEnum - Kind = tkEnumeration } TTypeInfoEnum = class external name 'rtl.tTypeInfoEnum'(TTypeInfoInteger) public // not supported: BaseType: TTypeInfo EnumType: TEnumType external name 'enumtype'; end; { TTypeInfoSet - Kind = tkSet } TTypeInfoSet = class external name 'rtl.tTypeInfoSet'(TTypeInfo) public // not supported: BaseType: TTypeInfo CompType: TTypeInfo external name 'comptype'; end; { TTypeInfoStaticArray - Kind = tkArray } TTypeInfoStaticArray = class external name 'rtl.tTypeInfoStaticArray'(TTypeInfo) public Dims: TIntegerDynArray external name 'dims'; ElType: TTypeInfo external name 'eltype'; end; { TTypeInfoDynArray - Kind = tkDynArray } TTypeInfoDynArray = class external name 'rtl.tTypeInfoDynArray'(TTypeInfo) public ElType: TTypeInfo external name 'eltype'; end; TParamFlag = ( pfVar, // 2^0 = 1 pfConst, // 2^1 = 2 pfOut, // 2^2 = 4 pfArray, // 2^3 = 8 pfAddress, // 2^4 = 16 pfReference // 2^5 = 32 ); TParamFlags = set of TParamFlag; { TProcedureParam } TProcedureParam = class external name 'anonymous' public Name: String external name 'name'; TypeInfo: TTypeInfo external name 'typeinfo'; Flags: NativeInt external name 'flags'; // TParamFlags as bit vector end; TProcedureParams = array of TProcedureParam; TProcedureFlag = ( pfStatic, // 2^0 = 1 pfVarargs, // 2^1 = 2 pfExternal, // 2^2 = 4 name may be an expression pfSafeCall, // 2^3 = 8 pfAsync // 2^4 = 16 ); TProcedureFlags = set of TProcedureFlag; { TProcedureSignature } TProcedureSignature = class external name 'anonymous' public Params: TProcedureParams external name 'params'; // can be null ResultType: TTypeInfo external name 'resulttype'; // can be null Flags: NativeInt external name 'flags'; // TProcedureFlags as bit vector end; { TTypeInfoProcVar - Kind = tkProcVar } TTypeInfoProcVar = class external name 'rtl.tTypeInfoProcVar'(TTypeInfo) public ProcSig: TProcedureSignature external name 'procsig'; end; { TTypeInfoRefToProcVar - Kind = tkRefToProcVar } TTypeInfoRefToProcVar = class external name 'rtl.tTypeInfoRefToProcVar'(TTypeInfoProcVar) end; TMethodKind = ( mkProcedure, // 0 default mkFunction, // 1 mkConstructor, // 2 mkDestructor, // 3 mkClassProcedure,// 4 mkClassFunction // 5 //mkClassConstructor,mkClassDestructor,mkOperatorOverload ); TMethodKinds = set of TMethodKind; { TTypeInfoMethodVar - Kind = tkMethod } TTypeInfoMethodVar = class external name 'rtl.tTypeInfoMethodVar'(TTypeInfoProcVar) public MethodKind: TMethodKind external name 'methodkind'; end; TTypeMemberKind = ( tmkUnknown, // 0 tmkField, // 1 tmkMethod, // 2 tmkProperty // 3 ); TTypeMemberKinds = set of TTypeMemberKind; { TTypeMember } TTypeMember = class external name 'rtl.tTypeMember' public Name: String external name 'name'; Kind: TTypeMemberKind external name 'kind'; Attributes: TTypeInfoAttributes external name 'attr'; // can be undefined end; TTypeMemberDynArray = array of TTypeMember; { TTypeMemberField - Kind = tmkField } TTypeMemberField = class external name 'rtl.tTypeMemberField'(TTypeMember) public TypeInfo: TTypeInfo external name 'typeinfo'; end; { TTypeMemberMethod - Kind = tmkMethod } TTypeMemberMethod = class external name 'rtl.tTypeMemberMethod'(TTypeMember) public MethodKind: TMethodKind external name 'methodkind'; ProcSig: TProcedureSignature external name 'procsig'; end; TTypeMemberMethodDynArray = array of TTypeMemberMethod; const pfGetFunction = 1; // getter is a function pfSetProcedure = 2; // setter is a procedure // stored is a 2-bit vector: pfStoredFalse = 4; // stored false, never pfStoredField = 8; // stored field, field name is in Stored pfStoredFunction = 12; // stored function, function name is in Stored pfHasIndex = 16; { if getter is function, append Index as last param if setter is function, append Index as second last param } type { TTypeMemberProperty - Kind = tmkProperty } TTypeMemberProperty = class external name 'rtl.tTypeMemberProperty'(TTypeMember) public TypeInfo: TTypeInfo external name 'typeinfo'; Flags: NativeInt external name 'flags'; // bit vector, see pf constants above Params: TProcedureParams external name 'params'; // can be null or undefined Index: JSValue external name 'index'; // can be undefined Getter: String external name 'getter'; // name of field or function Setter: String external name 'setter'; // name of field or function Stored: String external name 'stored'; // name of field or function, can be undefined Default: JSValue external name 'Default'; // can be undefined end; TTypeMemberPropertyDynArray = array of TTypeMemberProperty; { TTypeMembers } TTypeMembers = class external name 'rtl.tTypeMembers' private function GetItems(Name: String): TTypeMember; external name '[]'; procedure SetItems(Name: String; const AValue: TTypeMember); external name '[]'; public property Members[Name: String]: TTypeMember read GetItems write SetItems; default; end; { TTypeInfoStruct } TTypeInfoStruct = class external name 'rtl.tTypeInfoStruct'(TTypeInfo) private FFieldCount: NativeInt external name 'fields.length'; FMethodCount: NativeInt external name 'methods.length'; FPropCount: NativeInt external name 'properties.length'; public Members: TTypeMembers external name 'members'; Names: TStringDynArray external name 'names'; // all member names with TTypeInfo Fields: TStringDynArray external name 'fields'; Methods: TStringDynArray external name 'methods'; Properties: TStringDynArray external name 'properties'; property FieldCount: NativeInt read FFieldCount; function GetField(Index: NativeInt): TTypeMemberField; external name 'getField'; function AddField(aName: String; aType: TTypeInfo; Options: TJSObject = nil ): TTypeMemberField; external name 'addField'; property MethodCount: NativeInt read FMethodCount; function GetMethod(Index: NativeInt): TTypeMemberMethod; external name 'getMethod'; function AddMethod(aName: String; MethodKind: TMethodKind = mkProcedure; Params: TJSArray = nil; ResultType: TTypeInfo = nil; Options: TJSObject = nil): TTypeMemberMethod; external name 'addMethod'; property PropCount: NativeInt read FPropCount; function GetProp(Index: NativeInt): TTypeMemberProperty; external name 'getProperty'; function AddProperty(aName: String; Flags: NativeInt; ResultType: TTypeInfo; Getter, Setter: String; Options: TJSObject = nil): TTypeMemberProperty; external name 'addProperty'; end; { TTypeInfoRecord - Kind = tkRecord } TTypeInfoRecord = class external name 'rtl.tTypeInfoRecord'(TTypeInfoStruct) public RecordType: TJSObject external name '$record'; // only records with class vars, else jsundefined end; { TTypeInfoClass - Kind = tkClass } TTypeInfoClass = class external name 'rtl.tTypeInfoClass'(TTypeInfoStruct) public ClassType: TClass external name 'class'; Ancestor: TTypeInfoClass external name 'ancestor'; end; { TTypeInfoExtClass - Kind = tkExtClass } TTypeInfoExtClass = class external name 'rtl.tTypeInfoExtClass'(TTypeInfoClass) public JSClassName: String external name 'jsclass'; end; { TTypeInfoClassRef - class-of, Kind = tkClassRef } TTypeInfoClassRef = class external name 'rtl.tTypeInfoClassRef'(TTypeInfo) public InstanceType: TTypeInfo external name 'instancetype'; end; { TTypeInfoPointer - Kind = tkPointer } TTypeInfoPointer = class external name 'rtl.tTypeInfoPointer'(TTypeInfo) public RefType: TTypeInfo external name 'reftype'; // can be null end; { TTypeInfoInterface - Kind = tkInterface } TTypeInfoInterface = class external name 'rtl.tTypeInfoInterface'(TTypeInfoStruct) public InterfaceType: TJSObject external name 'interface'; Ancestor: TTypeInfoInterface external name 'ancestor'; end; { TTypeInfoHelper - Kind = tkHelper } TTypeInfoHelper = class external name 'rtl.tTypeInfoHelper'(TTypeInfoStruct) public HelperType: TJSObject external name 'helper'; Ancestor: TTypeInfoHelper external name 'ancestor'; HelperFor: TTypeInfo external name 'helperfor'; end; EPropertyError = class(Exception); function GetTypeName(TypeInfo: TTypeInfo): string; function GetClassMembers(aTIStruct: TTypeInfoStruct): TTypeMemberDynArray; function GetClassMember(aTIStruct: TTypeInfoStruct; const aName: String): TTypeMember; function GetInstanceMethod(Instance: TObject; const aName: String): Pointer; function GetClassMethods(aTIStruct: TTypeInfoStruct): TTypeMemberMethodDynArray; function CreateMethod(Instance: TObject; FuncName: String): Pointer; external name 'rtl.createCallback'; function GetInterfaceMembers(aTIInterface: TTypeInfoInterface): TTypeMemberDynArray; function GetInterfaceMember(aTIInterface: TTypeInfoInterface; const aName: String): TTypeMember; function GetInterfaceMethods(aTIInterface: TTypeInfoInterface): TTypeMemberMethodDynArray; function GetRTTIAttributes(const Attributes: TTypeInfoAttributes): TCustomAttributeArray; function GetPropInfos(aTIStruct: TTypeInfoStruct): TTypeMemberPropertyDynArray; function GetPropList(aTIStruct: TTypeInfoStruct; TypeKinds: TTypeKinds; Sorted: boolean = true): TTypeMemberPropertyDynArray; function GetPropList(aTIStruct: TTypeInfoStruct): TTypeMemberPropertyDynArray; function GetPropList(AClass: TClass): TTypeMemberPropertyDynArray; function GetPropList(Instance: TObject): TTypeMemberPropertyDynArray; function GetPropInfo(TI: TTypeInfoStruct; const PropName: String): TTypeMemberProperty; function GetPropInfo(TI: TTypeInfoStruct; const PropName: String; const Kinds: TTypeKinds): TTypeMemberProperty; function GetPropInfo(Instance: TObject; const PropName: String): TTypeMemberProperty; function GetPropInfo(Instance: TObject; const PropName: String; const Kinds: TTypeKinds): TTypeMemberProperty; function GetPropInfo(aClass: TClass; const PropName: String): TTypeMemberProperty; function GetPropInfo(aClass: TClass; const PropName: String; const Kinds: TTypeKinds): TTypeMemberProperty; function FindPropInfo(Instance: TObject; const PropName: String): TTypeMemberProperty; function FindPropInfo(Instance: TObject; const PropName: String; const Kinds: TTypeKinds): TTypeMemberProperty; function FindPropInfo(aClass: TClass; const PropName: String): TTypeMemberProperty; function FindPropInfo(aClass: TClass; const PropName: String; const Kinds: TTypeKinds): TTypeMemberProperty; // Property information routines. Function IsStoredProp(Instance: TObject; const PropInfo: TTypeMemberProperty): 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; const TypeKind: TTypeKind): Boolean; function PropIsType(aClass: TClass; const PropName: string; const TypeKind: TTypeKind): Boolean; function GetJSValueProp(Instance: TJSObject; TI: TTypeInfoStruct; const PropName: String): JSValue; function GetJSValueProp(Instance: TJSObject; const PropInfo: TTypeMemberProperty): JSValue; function GetJSValueProp(Instance: TObject; const PropName: String): JSValue; function GetJSValueProp(Instance: TObject; const PropInfo: TTypeMemberProperty): JSValue; procedure SetJSValueProp(Instance: TJSObject; TI: TTypeInfoStruct; const PropName: String; Value: JSValue); procedure SetJSValueProp(Instance: TJSObject; const PropInfo: TTypeMemberProperty; Value: JSValue); procedure SetJSValueProp(Instance: TObject; const PropName: String; Value: JSValue); procedure SetJSValueProp(Instance: TObject; const PropInfo: TTypeMemberProperty; Value: JSValue); function GetNativeIntProp(Instance: TObject; const PropName: String): NativeInt; function GetNativeIntProp(Instance: TObject; const PropInfo: TTypeMemberProperty): NativeInt; procedure SetNativeIntProp(Instance: TObject; const PropName: String; Value: NativeInt); procedure SetNativeIntProp(Instance: TObject; const PropInfo: TTypeMemberProperty; Value: NativeInt); function GetOrdProp(Instance: TObject; const PropName: String): longint; function GetOrdProp(Instance: TObject; const PropInfo: TTypeMemberProperty): longint; procedure SetOrdProp(Instance: TObject; const PropName: String; Value: longint); procedure SetOrdProp(Instance: TObject; const PropInfo: TTypeMemberProperty; Value: longint); function GetEnumProp(Instance: TObject; const PropName: String): String; function GetEnumProp(Instance: TObject; const PropInfo: TTypeMemberProperty): String; procedure SetEnumProp(Instance: TObject; const PropName: String; const Value: String); procedure SetEnumProp(Instance: TObject; const PropInfo: TTypeMemberProperty; const Value: String); // Auxiliary routines, which may be useful function GetEnumName(TypeInfo: TTypeInfoEnum; Value: Integer): String; function GetEnumValue(TypeInfo: TTypeInfoEnum; const Name: string): Longint; function GetEnumNameCount(TypeInfo: TTypeInfoEnum): Longint; function GetSetProp(Instance: TObject; const PropName: String): String; overload; function GetSetProp(Instance: TObject; const PropInfo: TTypeMemberProperty): String; overload; function GetSetPropArray(Instance: TObject; const PropName: String): TIntegerDynArray; overload; function GetSetPropArray(Instance: TObject; const PropInfo: TTypeMemberProperty): TIntegerDynArray; overload; procedure SetSetPropArray(Instance: TObject; const PropName: String; const Arr: TIntegerDynArray); overload; procedure SetSetPropArray(Instance: TObject; const PropInfo: TTypeMemberProperty; const Arr: TIntegerDynArray); overload; function GetBoolProp(Instance: TObject; const PropName: String): boolean; function GetBoolProp(Instance: TObject; const PropInfo: TTypeMemberProperty): boolean; procedure SetBoolProp(Instance: TObject; const PropName: String; Value: boolean); procedure SetBoolProp(Instance: TObject; const PropInfo: TTypeMemberProperty; Value: boolean); function GetStrProp(Instance: TObject; const PropName: String): String; function GetStrProp(Instance: TObject; const PropInfo: TTypeMemberProperty): String; procedure SetStrProp(Instance: TObject; const PropName: String; Value: String); procedure SetStrProp(Instance: TObject; const PropInfo: TTypeMemberProperty; Value: String); function GetStringProp(Instance: TObject; const PropName: String): String; deprecated; // use GetStrProp function GetStringProp(Instance: TObject; const PropInfo: TTypeMemberProperty): String; deprecated; // use GetStrProp procedure SetStringProp(Instance: TObject; const PropName: String; Value: String); deprecated; // use GetStrProp procedure SetStringProp(Instance: TObject; const PropInfo: TTypeMemberProperty; Value: String); deprecated; // use GetStrProp function GetFloatProp(Instance: TObject; const PropName: string): Double; function GetFloatProp(Instance: TObject; PropInfo : TTypeMemberProperty) : Double; procedure SetFloatProp(Instance: TObject; const PropName: string; Value: Double); procedure SetFloatProp(Instance: TObject; PropInfo : TTypeMemberProperty; Value : Double); function GetObjectProp(Instance: TObject; const PropName: String): TObject; function GetObjectProp(Instance: TObject; const PropName: String; MinClass: TClass): TObject; function GetObjectProp(Instance: TObject; const PropInfo: TTypeMemberProperty): TObject; function GetObjectProp(Instance: TObject; const PropInfo: TTypeMemberProperty; MinClass: TClass): TObject; procedure SetObjectProp(Instance: TObject; const PropName: String; Value: TObject) ; procedure SetObjectProp(Instance: TObject; const PropInfo: TTypeMemberProperty; Value: TObject); function GetMethodProp(Instance: TObject; PropInfo: TTypeMemberProperty): TMethod; function GetMethodProp(Instance: TObject; const PropName: string): TMethod; procedure SetMethodProp(Instance: TObject; PropInfo: TTypeMemberProperty; const Value : TMethod); procedure SetMethodProp(Instance: TObject; const PropName: string; const Value: TMethod); function GetInterfaceProp(Instance: TObject; const PropName: string): IInterface; function GetInterfaceProp(Instance: TObject; PropInfo: TTypeMemberProperty): IInterface; procedure SetInterfaceProp(Instance: TObject; const PropName: string; const Value: IInterface); procedure SetInterfaceProp(Instance: TObject; PropInfo: TTypeMemberProperty; const Value: IInterface); function GetRawInterfaceProp(Instance: TObject; const PropName: string): Pointer; function GetRawInterfaceProp(Instance: TObject; PropInfo: TTypeMemberProperty): Pointer; procedure SetRawInterfaceProp(Instance: TObject; const PropName: string; const Value: Pointer); procedure SetRawInterfaceProp(Instance: TObject; PropInfo: TTypeMemberProperty; const Value: Pointer); implementation function GetTypeName(TypeInfo: TTypeInfo): string; begin Result := TypeInfo.Name; end; function GetClassMembers(aTIStruct: TTypeInfoStruct): TTypeMemberDynArray; var C: TTypeInfoStruct; i: Integer; PropName: String; Names: TJSObject; begin Result:=nil; Names:=TJSObject.new; C:=aTIStruct; while C<>nil do begin for i:=0 to length(C.Names)-1 do begin PropName:=C.Names[i]; if Names.hasOwnProperty(PropName) then continue; TJSArray(Result).push(C.Members[PropName]); Names[PropName]:=true; end; if not (C is TTypeInfoClass) then break; C:=TTypeInfoClass(C).Ancestor; end; end; function GetClassMember(aTIStruct: TTypeInfoStruct; const aName: String): TTypeMember; var C: TTypeInfoStruct; i: Integer; begin // quick search: case sensitive C:=aTIStruct; while C<>nil do begin if TJSObject(C.Members).hasOwnProperty(aName) then exit(C.Members[aName]); if not (C is TTypeInfoClass) then break; C:=TTypeInfoClass(C).Ancestor; end; // slow search: case insensitive C:=aTIStruct; while C<>nil do begin for i:=0 to length(C.Names)-1 do if CompareText(C.Names[i],aName)=0 then exit(C.Members[C.Names[i]]); if not (C is TTypeInfoClass) then break; C:=TTypeInfoClass(C).Ancestor; end; Result:=nil; end; function GetInstanceMethod(Instance: TObject; const aName: String): Pointer; var TI: TTypeMember; begin if Instance=nil then exit(nil); TI:=GetClassMember(TypeInfo(Instance),aName); if not (TI is TTypeMemberMethod) then exit(nil); Result:=CreateMethod(Instance,TI.Name); // Note: use TI.Name for the correct case! end; function GetClassMethods(aTIStruct: TTypeInfoStruct): TTypeMemberMethodDynArray; var C: TTypeInfoStruct; i, Cnt, j: Integer; begin Cnt:=0; C:=aTIStruct; while C<>nil do begin inc(Cnt,C.MethodCount); if not (C is TTypeInfoClass) then break; C:=TTypeInfoClass(C).Ancestor; end; SetLength(Result,Cnt); C:=aTIStruct; i:=0; while C<>nil do begin for j:=0 to C.MethodCount-1 do begin Result[i]:=TTypeMemberMethod(C.Members[C.Methods[j]]); inc(i); end; if not (C is TTypeInfoClass) then break; C:=TTypeInfoClass(C).Ancestor; end; end; function GetInterfaceMembers(aTIInterface: TTypeInfoInterface ): TTypeMemberDynArray; var Intf: TTypeInfoInterface; i, Cnt, j: Integer; begin Cnt:=0; Intf:=aTIInterface; while Intf<>nil do begin inc(Cnt,length(Intf.Names)); Intf:=Intf.Ancestor; end; SetLength(Result,Cnt); Intf:=aTIInterface; i:=0; while Intf<>nil do begin for j:=0 to length(Intf.Names)-1 do begin Result[i]:=Intf.Members[Intf.Names[j]]; inc(i); end; Intf:=Intf.Ancestor; end; end; function GetInterfaceMember(aTIInterface: TTypeInfoInterface; const aName: String): TTypeMember; var Intf: TTypeInfoInterface; i: Integer; begin // quick search: case sensitive Intf:=aTIInterface; while Intf<>nil do begin if TJSObject(Intf.Members).hasOwnProperty(aName) then exit(Intf.Members[aName]); Intf:=Intf.Ancestor; end; // slow search: case insensitive Intf:=aTIInterface; while Intf<>nil do begin for i:=0 to length(Intf.Names)-1 do if CompareText(Intf.Names[i],aName)=0 then exit(Intf.Members[Intf.Names[i]]); Intf:=Intf.Ancestor; end; Result:=nil; end; function GetInterfaceMethods(aTIInterface: TTypeInfoInterface ): TTypeMemberMethodDynArray; var Intf: TTypeInfoInterface; i, Cnt, j: Integer; begin Cnt:=0; Intf:=aTIInterface; while Intf<>nil do begin inc(Cnt,Intf.MethodCount); Intf:=Intf.Ancestor; end; SetLength(Result,Cnt); Intf:=aTIInterface; i:=0; while Intf<>nil do begin for j:=0 to Intf.MethodCount-1 do begin Result[i]:=TTypeMemberMethod(Intf.Members[Intf.Methods[j]]); inc(i); end; Intf:=Intf.Ancestor; end; end; type TCreatorAttribute = class external name 'attr' class function Create(const ProcName: string): TCustomAttribute; overload; external name '$create'; class function Create(const ProcName: string; Params: jsvalue): TCustomAttribute; overload; external name '$create'; end; TCreatorAttributeClass = class of TCreatorAttribute; function GetRTTIAttributes(const Attributes: TTypeInfoAttributes ): TCustomAttributeArray; var i, len: Integer; AttrClass: TCreatorAttributeClass; ProcName: String; Attr: TCustomAttribute; begin Result:=nil; if Attributes=Undefined then exit; i:=0; len:=length(Attributes); while inil do begin for i:=0 to C.PropCount-1 do begin PropName:=C.Properties[i]; if Names.hasOwnProperty(PropName) then continue; TJSArray(Result).push(TTypeMemberProperty(C.Members[PropName])); Names[PropName]:=true; end; if not (C is TTypeInfoClass) then break; C:=TTypeInfoClass(C).Ancestor; end; end; function GetPropList(aTIStruct: TTypeInfoStruct; TypeKinds: TTypeKinds; Sorted: boolean): TTypeMemberPropertyDynArray; function NameSort(a,b: JSValue): NativeInt; begin if TTypeMemberProperty(a).NameTTypeMemberProperty(b).Name then Result:=1 else Result:=0; end; var C: TTypeInfoStruct; i: Integer; Names: TJSObject; PropName: String; Prop: TTypeMemberProperty; begin Result:=nil; C:=aTIStruct; Names:=TJSObject.new; while C<>nil do begin for i:=0 to C.PropCount-1 do begin PropName:=C.Properties[i]; if Names.hasOwnProperty(PropName) then continue; Prop:=TTypeMemberProperty(C.Members[PropName]); if not (Prop.TypeInfo.Kind in TypeKinds) then continue; TJSArray(Result).push(Prop); Names[PropName]:=true; end; if not (C is TTypeInfoClass) then break; C:=TTypeInfoClass(C).Ancestor; end; if Sorted then TJSArray(Result).sort(@NameSort); end; function GetPropList(aTIStruct: TTypeInfoStruct): TTypeMemberPropertyDynArray; begin Result:=GetPropInfos(aTIStruct); end; function GetPropList(AClass: TClass): TTypeMemberPropertyDynArray; begin Result:=GetPropInfos(TypeInfo(AClass)); end; function GetPropList(Instance: TObject): TTypeMemberPropertyDynArray; begin Result:=GetPropList(Instance.ClassType); end; function GetPropInfo(TI: TTypeInfoStruct; const PropName: String ): TTypeMemberProperty; var m: TTypeMember; i: Integer; C: TTypeInfoStruct; begin // quick search case sensitive C:=TI; while C<>nil do begin m:=C.Members[PropName]; if m is TTypeMemberProperty then exit(TTypeMemberProperty(m)); if not (C is TTypeInfoClass) then break; C:=TTypeInfoClass(C).Ancestor; end; // slow search case insensitive Result:=nil; repeat for i:=0 to TI.PropCount-1 do if CompareText(PropName,TI.Properties[i])=0 then begin m:=TI.Members[TI.Properties[i]]; if m is TTypeMemberProperty then Result:=TTypeMemberProperty(m); exit; end; if not (TI is TTypeInfoClass) then break; TI:=TTypeInfoClass(TI).Ancestor; until TI=nil; end; function GetPropInfo(TI: TTypeInfoStruct; const PropName: String; const Kinds: TTypeKinds): TTypeMemberProperty; begin Result:=GetPropInfo(TI,PropName); if (Kinds<>[]) and (Result<>nil) and not (Result.TypeInfo.Kind in Kinds) then Result:=nil; end; function GetPropInfo(Instance: TObject; const PropName: String ): TTypeMemberProperty; begin Result:=GetPropInfo(TypeInfo(Instance),PropName,[]); end; function GetPropInfo(Instance: TObject; const PropName: String; const Kinds: TTypeKinds): TTypeMemberProperty; begin Result:=GetPropInfo(TypeInfo(Instance),PropName,Kinds); end; function GetPropInfo(aClass: TClass; const PropName: String ): TTypeMemberProperty; begin Result:=GetPropInfo(TypeInfo(AClass),PropName,[]); end; function GetPropInfo(aClass: TClass; const PropName: String; const Kinds: TTypeKinds): TTypeMemberProperty; begin Result:=GetPropInfo(TypeInfo(AClass),PropName,Kinds); end; function FindPropInfo(Instance: TObject; const PropName: String ): TTypeMemberProperty; begin Result:=GetPropInfo(TypeInfo(Instance), PropName); if Result=nil then raise EPropertyError.CreateFmt(SErrPropertyNotFound, [PropName]); end; function FindPropInfo(Instance: TObject; const PropName: String; const Kinds: TTypeKinds): TTypeMemberProperty; begin Result:=GetPropInfo(TypeInfo(Instance), PropName, Kinds); if Result=nil then raise EPropertyError.CreateFmt(SErrPropertyNotFound, [PropName]); end; function FindPropInfo(aClass: TClass; const PropName: String ): TTypeMemberProperty; begin Result:=GetPropInfo(TypeInfo(aClass), PropName); if Result=nil then raise EPropertyError.CreateFmt(SErrPropertyNotFound, [PropName]); end; function FindPropInfo(aClass: TClass; const PropName: String; const Kinds: TTypeKinds): TTypeMemberProperty; begin Result:=GetPropInfo(TypeInfo(aClass), PropName, Kinds); if Result=nil then raise EPropertyError.CreateFmt(SErrPropertyNotFound, [PropName]); end; function IsStoredProp(Instance: TObject; const PropInfo: TTypeMemberProperty ): Boolean; type TIsStored = function: Boolean of object; begin case PropInfo.Flags and 12 of 0: Result:=true; 4: Result:=false; 8: Result:=Boolean(TJSObject(Instance)[PropInfo.Stored]); else Result:=TIsStored(TJSObject(Instance)[PropInfo.Stored])(); end; end; function IsStoredProp(Instance: TObject; const PropName: string): Boolean; begin Result:=IsStoredProp(Instance,FindPropInfo(Instance,PropName)); end; 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 PropType(Instance: TObject; const PropName: string): TTypeKind; begin Result:=FindPropInfo(Instance,PropName).TypeInfo.Kind; end; function PropType(aClass: TClass; const PropName: string): TTypeKind; begin Result:=FindPropInfo(aClass,PropName).TypeInfo.Kind; end; function PropIsType(Instance: TObject; const PropName: string; const TypeKind: TTypeKind): Boolean; begin Result:=PropType(Instance,PropName)=TypeKind; end; function PropIsType(aClass: TClass; const PropName: string; const TypeKind: TTypeKind): Boolean; begin Result:=PropType(aClass,PropName)=TypeKind; end; type TGetterKind = ( gkNone, gkField, gkFunction, gkFunctionWithParams ); function GetPropGetterKind(const PropInfo: TTypeMemberProperty): TGetterKind; begin if PropInfo.Getter='' then Result:=gkNone else if (pfGetFunction and PropInfo.Flags)>0 then begin if length(PropInfo.Params)>0 then // array property Result:=gkFunctionWithParams else Result:=gkFunction; end else Result:=gkField; end; type TSetterKind = ( skNone, skField, skProcedure, skProcedureWithParams ); function GetPropSetterKind(const PropInfo: TTypeMemberProperty): TSetterKind; begin if PropInfo.Setter='' then Result:=skNone else if (pfSetProcedure and PropInfo.Flags)>0 then begin if length(PropInfo.Params)>0 then // array property Result:=skProcedureWithParams else Result:=skProcedure; end else Result:=skField; end; function GetJSValueProp(Instance: TJSObject; TI: TTypeInfoStruct; const PropName: String): JSValue; var PropInfo: TTypeMemberProperty; begin PropInfo:=GetPropInfo(TI,PropName); if PropInfo=nil then raise EPropertyError.CreateFmt(SErrPropertyNotFound, [PropName]); Result:=GetJSValueProp(Instance,PropInfo); end; function GetJSValueProp(Instance: TJSObject; const PropInfo: TTypeMemberProperty): JSValue; type TGetter = function: JSValue of object; TGetterWithIndex = function(Index: JSValue): JSValue of object; var gk: TGetterKind; begin gk:=GetPropGetterKind(PropInfo); case gk of gkNone: raise EPropertyError.CreateFmt(SCantReadPropertyS, [PropInfo.Name]); gkField: Result:=Instance[PropInfo.Getter]; gkFunction: if (pfHasIndex and PropInfo.Flags)>0 then Result:=TGetterWithIndex(Instance[PropInfo.Getter])(PropInfo.Index) else Result:=TGetter(Instance[PropInfo.Getter])(); gkFunctionWithParams: raise EPropertyError.CreateFmt(SIndexedPropertyNeedsParams, [PropInfo.Name]); end; end; function GetJSValueProp(Instance: TObject; const PropName: String): JSValue; begin Result:=GetJSValueProp(Instance,FindPropInfo(Instance,PropName)); end; function GetJSValueProp(Instance: TObject; const PropInfo: TTypeMemberProperty ): JSValue; begin Result:=GetJSValueProp(TJSObject(Instance),PropInfo); end; procedure SetJSValueProp(Instance: TJSObject; TI: TTypeInfoStruct; const PropName: String; Value: JSValue); var PropInfo: TTypeMemberProperty; begin PropInfo:=GetPropInfo(TI,PropName); if PropInfo=nil then raise EPropertyError.CreateFmt(SErrPropertyNotFound, [PropName]); SetJSValueProp(Instance,PropInfo,Value); end; procedure SetJSValueProp(Instance: TJSObject; const PropInfo: TTypeMemberProperty; Value: JSValue); type TSetter = procedure(Value: JSValue) of object; TSetterWithIndex = procedure(Index, Value: JSValue) of object; var sk: TSetterKind; begin sk:=GetPropSetterKind(PropInfo); case sk of skNone: raise EPropertyError.CreateFmt(SCantWritePropertyS, [PropInfo.Name]); skField: Instance[PropInfo.Setter]:=Value; skProcedure: if (pfHasIndex and PropInfo.Flags)>0 then TSetterWithIndex(Instance[PropInfo.Setter])(PropInfo.Index,Value) else TSetter(Instance[PropInfo.Setter])(Value); skProcedureWithParams: raise EPropertyError.CreateFmt(SIndexedPropertyNeedsParams, [PropInfo.Name]); end; end; procedure SetJSValueProp(Instance: TObject; const PropName: String; Value: JSValue); begin SetJSValueProp(Instance,FindPropInfo(Instance,PropName),Value); end; procedure SetJSValueProp(Instance: TObject; const PropInfo: TTypeMemberProperty; Value: JSValue); begin SetJSValueProp(TJSObject(Instance),PropInfo,Value); end; function GetNativeIntProp(Instance: TObject; const PropName: String): NativeInt; begin Result:=GetNativeIntProp(Instance,FindPropInfo(Instance,PropName)); end; function GetNativeIntProp(Instance: TObject; const PropInfo: TTypeMemberProperty ): NativeInt; begin Result:=NativeInt(GetJSValueProp(Instance,PropInfo)); end; procedure SetNativeIntProp(Instance: TObject; const PropName: String; Value: NativeInt); begin SetJSValueProp(Instance,FindPropInfo(Instance,PropName),Value); end; procedure SetNativeIntProp(Instance: TObject; const PropInfo: TTypeMemberProperty; Value: NativeInt); begin SetJSValueProp(Instance,PropInfo,Value); end; function GetOrdProp(Instance: TObject; const PropName: String): longint; begin Result:=GetOrdProp(Instance,FindPropInfo(Instance,PropName)); end; function GetOrdProp(Instance: TObject; const PropInfo: TTypeMemberProperty ): longint; var o: TJSObject; Key: String; n: NativeInt; begin if PropInfo.TypeInfo.Kind=tkSet then begin // a set is a JS object, with the following property: o[ElementDecimal]=true o:=TJSObject(GetJSValueProp(Instance,PropInfo)); Result:=0; for Key in o do begin n:=parseInt(Key,10); if n<32 then Result:=Result+(1 shl n); end; end else Result:=longint(GetJSValueProp(Instance,PropInfo)); end; procedure SetOrdProp(Instance: TObject; const PropName: String; Value: longint); begin SetOrdProp(Instance,FindPropInfo(Instance,PropName),Value); end; procedure SetOrdProp(Instance: TObject; const PropInfo: TTypeMemberProperty; Value: longint); var o: TJSObject; i: Integer; begin if PropInfo.TypeInfo.Kind=tkSet then begin o:=TJSObject.new; for i:=0 to 31 do if (1 shl i) and Value>0 then o[str(i)]:=true; SetJSValueProp(Instance,PropInfo,o); end else SetJSValueProp(Instance,PropInfo,Value); end; function GetEnumProp(Instance: TObject; const PropName: String): String; begin Result:=GetEnumProp(Instance,FindPropInfo(Instance,PropName)); end; function GetEnumProp(Instance: TObject; const PropInfo: TTypeMemberProperty): String; var n: NativeInt; TIEnum: TTypeInfoEnum; begin TIEnum:=PropInfo.TypeInfo as TTypeInfoEnum; n:=NativeInt(GetJSValueProp(Instance,PropInfo)); if (n>=TIEnum.MinValue) and (n<=TIEnum.MaxValue) then Result:=TIEnum.EnumType.IntToName[n] else Result:=str(n); 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: TTypeMemberProperty; const Value: String); var TIEnum: TTypeInfoEnum; n: NativeInt; begin TIEnum:=PropInfo.TypeInfo as TTypeInfoEnum; n:=TIEnum.EnumType.NameToInt[Value]; if not isUndefined(n) then SetJSValueProp(Instance,PropInfo,n); end; function GetEnumName(TypeInfo: TTypeInfoEnum; Value: Integer): String; begin Result:=TypeInfo.EnumType.IntToName[Value]; end; function GetEnumValue(TypeInfo: TTypeInfoEnum; const Name: string): Longint; begin Result:=TypeInfo.EnumType.NameToInt[Name]; end; function GetEnumNameCount(TypeInfo: TTypeInfoEnum): Longint; var o: TJSObject; l, r: LongInt; begin o:=TJSObject(TypeInfo.EnumType); // as of pas2js 1.0 the RTTI does not contain a min/max value // -> use exponential search // ToDo: adapt this once enums with gaps are supported Result:=1; while o.hasOwnProperty(String(JSValue(Result))) do Result:=Result*2; l:=Result div 2; r:=Result; while l<=r do begin Result:=(l+r) div 2; if o.hasOwnProperty(String(JSValue(Result))) then l:=Result+1 else r:=Result-1; end; if o.hasOwnProperty(String(JSValue(Result))) then inc(Result); end; function GetSetProp(Instance: TObject; const PropName: String): String; begin Result:=GetSetProp(Instance,FindPropInfo(Instance,PropName)); end; function GetSetProp(Instance: TObject; const PropInfo: TTypeMemberProperty ): String; var o: TJSObject; key, Value: String; n: NativeInt; TIEnum: TTypeInfoEnum; TISet: TTypeInfoSet; begin Result:=''; // get enum type if available TISet:=PropInfo.TypeInfo as TTypeInfoSet; TIEnum:=nil; if TISet.CompType is TTypeInfoEnum then TIEnum:=TTypeInfoEnum(TISet.CompType); // read value o:=TJSObject(GetJSValueProp(Instance,PropInfo)); // a set is a JS object, where included element is stored as: o[ElementDecimal]=true for Key in o do begin n:=parseInt(Key,10); if (TIEnum<>nil) and (n>=TIEnum.MinValue) and (n<=TIEnum.MaxValue) then Value:=TIEnum.EnumType.IntToName[n] else Value:=str(n); if Result<>'' then Result:=Result+','; Result:=Result+Value; end; Result:='['+Result+']'; end; function GetSetPropArray(Instance: TObject; const PropName: String ): TIntegerDynArray; begin Result:=GetSetPropArray(Instance,FindPropInfo(Instance,PropName)); end; function GetSetPropArray(Instance: TObject; const PropInfo: TTypeMemberProperty ): TIntegerDynArray; var o: TJSObject; Key: string; begin Result:=[]; // read value o:=TJSObject(GetJSValueProp(Instance,PropInfo)); // a set is a JS object, where included element is stored as: o[ElementDecimal]=true for Key in o do TJSArray(Result).push(parseInt(Key,10)); end; procedure SetSetPropArray(Instance: TObject; const PropName: String; const Arr: TIntegerDynArray); begin SetSetPropArray(Instance,FindPropInfo(Instance,PropName),Arr); end; procedure SetSetPropArray(Instance: TObject; const PropInfo: TTypeMemberProperty; const Arr: TIntegerDynArray); var o: TJSObject; i: integer; begin o:=TJSObject.new; for i in Arr do o[str(i)]:=true; SetJSValueProp(Instance,PropInfo,o); end; function GetStrProp(Instance: TObject; const PropName: String): String; begin Result:=GetStrProp(Instance,FindPropInfo(Instance,PropName)); end; function GetStrProp(Instance: TObject; const PropInfo: TTypeMemberProperty ): String; begin Result:=String(GetJSValueProp(Instance,PropInfo)); end; procedure SetStrProp(Instance: TObject; const PropName: String; Value: String ); begin SetStrProp(Instance,FindPropInfo(Instance,PropName),Value); end; procedure SetStrProp(Instance: TObject; const PropInfo: TTypeMemberProperty; Value: String); begin SetJSValueProp(Instance,PropInfo,Value); end; function GetStringProp(Instance: TObject; const PropName: String): String; begin Result:=GetStrProp(Instance,PropName); end; function GetStringProp(Instance: TObject; const PropInfo: TTypeMemberProperty ): String; begin Result:=GetStrProp(Instance,PropInfo); end; procedure SetStringProp(Instance: TObject; const PropName: String; Value: String ); begin SetStrProp(Instance,PropName,Value); end; procedure SetStringProp(Instance: TObject; const PropInfo: TTypeMemberProperty; Value: String); begin SetStrProp(Instance,PropInfo,Value); end; function GetBoolProp(Instance: TObject; const PropName: String): boolean; begin Result:=GetBoolProp(Instance,FindPropInfo(Instance,PropName)); end; function GetBoolProp(Instance: TObject; const PropInfo: TTypeMemberProperty ): boolean; begin Result:=Boolean(GetJSValueProp(Instance,PropInfo)); end; procedure SetBoolProp(Instance: TObject; const PropName: String; Value: boolean ); begin SetBoolProp(Instance,FindPropInfo(Instance,PropName),Value); end; procedure SetBoolProp(Instance: TObject; const PropInfo: TTypeMemberProperty; Value: boolean); begin SetJSValueProp(Instance,PropInfo,Value); end; function GetObjectProp(Instance: TObject; const PropName: String): TObject; begin Result:=GetObjectProp(Instance,FindPropInfo(Instance,PropName)); end; function GetObjectProp(Instance: TObject; const PropName: String; MinClass : TClass): TObject; begin Result:=GetObjectProp(Instance,FindPropInfo(Instance,PropName)); if (MinClass<>Nil) and (Result<>Nil) Then if not Result.InheritsFrom(MinClass) then Result:=Nil; end; function GetObjectProp(Instance: TObject; const PropInfo: TTypeMemberProperty): TObject; begin Result:=GetObjectProp(Instance,PropInfo,Nil); end; function GetObjectProp(Instance: TObject; const PropInfo: TTypeMemberProperty; MinClass : TClass): TObject; Var O : TObject; begin O:=TObject(GetJSValueProp(Instance,PropInfo)); if (MinClass<>Nil) and not O.InheritsFrom(MinClass) then Result:=Nil else Result:=O; end; procedure SetObjectProp(Instance: TObject; const PropName: String; Value: TObject) ; begin SetObjectProp(Instance,FindPropInfo(Instance,PropName),Value); end; procedure SetObjectProp(Instance: TObject; const PropInfo: TTypeMemberProperty; Value: TObject); begin SetJSValueProp(Instance,PropInfo,Value); end; function GetMethodProp(Instance: TObject; PropInfo: TTypeMemberProperty ): TMethod; var v, fn: JSValue; begin Result.Code:=nil; Result.Data:=nil; v:=GetJSValueProp(Instance,PropInfo); if not isFunction(v) then exit; Result.Data:=Pointer(TJSObject(v)['scope']); fn:=TJSObject(v)['fn']; if isString(fn) then begin if Result.Data<>nil then // named callback Result.Code:=CodePointer(TJSObject(Result.Data)[String(fn)]) else // this is not an rtl callback, return the value Result.Code:=CodePointer(v); end else // anonymous callback Result.Code:=CodePointer(fn); end; function GetMethodProp(Instance: TObject; const PropName: string): TMethod; begin Result:=GetMethodProp(Instance,FindPropInfo(Instance,PropName)); end; function createCallbackPtr(scope: Pointer; fn: CodePointer): TJSFunction; external name 'rtl.createCallback'; function createCallbackStr(scope: Pointer; fn: string): TJSFunction; external name 'rtl.createCallback'; procedure SetMethodProp(Instance: TObject; PropInfo: TTypeMemberProperty; const Value: TMethod); var cb: TJSFunction; Code: Pointer; begin // Note: Value.Data=nil is allowed and can be used by designer code Code:=Value.Code; if Code=nil then cb:=nil else if isFunction(Code) then begin if (TJSObject(Code)['scope']=Value.Data) and (isFunction(TJSObject(Code)['fn']) or isString(TJSObject(Code)['fn'])) then begin // Value.Code is already the needed callback cb:=TJSFunction(Code); end else if isString(TJSObject(Code)['fn']) then // named callback, different scope cb:=createCallbackStr(Value.Data,string(TJSObject(Code)['fn'])) else // normal function cb:=createCallbackPtr(Value.Data,Code); end else // not a valid value -> for compatibility set it anyway cb:=createCallbackPtr(Value.Data,Code); SetJSValueProp(Instance,PropInfo,cb); end; procedure SetMethodProp(Instance: TObject; const PropName: string; const Value: TMethod); begin SetMethodProp(Instance,FindPropInfo(Instance,PropName),Value); end; function GetInterfaceProp(Instance: TObject; const PropName: string ): IInterface; begin Result:=GetInterfaceProp(Instance,FindPropInfo(Instance,PropName)); end; function GetInterfaceProp(Instance: TObject; PropInfo: TTypeMemberProperty ): IInterface; type TGetter = function: IInterface of object; TGetterWithIndex = function(Index: JSValue): IInterface of object; var gk: TGetterKind; begin if Propinfo.TypeInfo.Kind<>tkInterface then raise Exception.Create('Cannot get RAW interface from IInterface interface'); gk:=GetPropGetterKind(PropInfo); case gk of gkNone: raise EPropertyError.CreateFmt(SCantReadPropertyS, [PropInfo.Name]); gkField: Result:=IInterface(TJSObject(Instance)[PropInfo.Getter]); gkFunction: if (pfHasIndex and PropInfo.Flags)>0 then Result:=TGetterWithIndex(TJSObject(Instance)[PropInfo.Getter])(PropInfo.Index) else Result:=TGetter(TJSObject(Instance)[PropInfo.Getter])(); gkFunctionWithParams: raise EPropertyError.CreateFmt(SIndexedPropertyNeedsParams, [PropInfo.Name]); end; end; procedure SetInterfaceProp(Instance: TObject; const PropName: string; const Value: IInterface); begin SetInterfaceProp(Instance,FindPropInfo(Instance,PropName),Value); end; procedure SetInterfaceProp(Instance: TObject; PropInfo: TTypeMemberProperty; const Value: IInterface); type TSetter = procedure(Value: IInterface) of object; TSetterWithIndex = procedure(Index: JSValue; Value: IInterface) of object; procedure setIntfP(Instance: TObject; const PropName: string; value: jsvalue); external name 'rtl.setIntfP'; var sk: TSetterKind; Setter: String; begin if Propinfo.TypeInfo.Kind<>tkInterface then raise Exception.Create('Cannot set RAW interface from IInterface interface'); sk:=GetPropSetterKind(PropInfo); Setter:=PropInfo.Setter; case sk of skNone: raise EPropertyError.CreateFmt(SCantWritePropertyS, [PropInfo.Name]); skField: setIntfP(Instance,Setter,Value); skProcedure: if (pfHasIndex and PropInfo.Flags)>0 then TSetterWithIndex(TJSObject(Instance)[Setter])(PropInfo.Index,Value) else TSetter(TJSObject(Instance)[Setter])(Value); skProcedureWithParams: raise EPropertyError.CreateFmt(SIndexedPropertyNeedsParams, [PropInfo.Name]); end; end; function GetRawInterfaceProp(Instance: TObject; const PropName: string ): Pointer; begin Result:=GetRawInterfaceProp(Instance,FindPropInfo(Instance,PropName)); end; function GetRawInterfaceProp(Instance: TObject; PropInfo: TTypeMemberProperty ): Pointer; begin Result:=Pointer(GetJSValueProp(Instance,PropInfo)); end; procedure SetRawInterfaceProp(Instance: TObject; const PropName: string; const Value: Pointer); begin SetRawInterfaceProp(Instance,FindPropInfo(Instance,PropName),Value); end; procedure SetRawInterfaceProp(Instance: TObject; PropInfo: TTypeMemberProperty; const Value: Pointer); begin SetJSValueProp(Instance,PropInfo,Value); end; function GetFloatProp(Instance: TObject; PropInfo: TTypeMemberProperty): Double; begin Result:=Double(GetJSValueProp(Instance,PropInfo)); end; function GetFloatProp(Instance: TObject; const PropName: string): Double; begin Result:=GetFloatProp(Instance,FindPropInfo(Instance,PropName)); end; procedure SetFloatProp(Instance: TObject; const PropName: string; Value: Double ); begin SetFloatProp(Instance,FindPropInfo(Instance,PropName),Value); end; procedure SetFloatProp(Instance: TObject; PropInfo: TTypeMemberProperty; Value: Double); begin SetJSValueProp(Instance,PropInfo,Value); end; end.