rtti.pp 123 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (C) 2013 Joost van der Sluis [email protected]
  4. member of the Free Pascal development team.
  5. Extended RTTI compatibility unit
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. }
  12. unit Rtti experimental;
  13. {$mode objfpc}{$H+}
  14. {$modeswitch advancedrecords}
  15. {$goto on}
  16. {$Assertions on}
  17. { Note: since the Lazarus IDE is not yet capable of correctly handling generic
  18. functions it is best to define a InLazIDE define inside the IDE that disables
  19. the generic code for CodeTools. To do this do this:
  20. - go to Tools -> Codetools Defines Editor
  21. - go to Edit -> Insert Node Below -> Define Recurse
  22. - enter the following values:
  23. Name: InLazIDE
  24. Description: Define InLazIDE everywhere
  25. Variable: InLazIDE
  26. Value from text: 1
  27. }
  28. {$ifdef InLazIDE}
  29. {$define NoGenericMethods}
  30. {$endif}
  31. interface
  32. uses
  33. Classes,
  34. SysUtils,
  35. typinfo;
  36. type
  37. TRttiObject = class;
  38. TRttiType = class;
  39. TRttiMethod = class;
  40. TRttiProperty = class;
  41. TRttiInstanceType = class;
  42. TFunctionCallCallback = class
  43. protected
  44. function GetCodeAddress: CodePointer; virtual; abstract;
  45. public
  46. property CodeAddress: CodePointer read GetCodeAddress;
  47. end;
  48. TFunctionCallFlag = (
  49. fcfStatic
  50. );
  51. TFunctionCallFlags = set of TFunctionCallFlag;
  52. TFunctionCallParameterInfo = record
  53. ParamType: PTypeInfo;
  54. ParamFlags: TParamFlags;
  55. ParaLocs: PParameterLocations;
  56. end;
  57. IValueData = interface
  58. ['{1338B2F3-2C21-4798-A641-CA2BC5BF2396}']
  59. procedure ExtractRawData(ABuffer: pointer);
  60. procedure ExtractRawDataNoCopy(ABuffer: pointer);
  61. function GetDataSize: SizeInt;
  62. function GetReferenceToRawData: pointer;
  63. end;
  64. TValueData = record
  65. FTypeInfo: PTypeInfo;
  66. FValueData: IValueData;
  67. case integer of
  68. 0: (FAsUByte: Byte);
  69. 1: (FAsUWord: Word);
  70. 2: (FAsULong: LongWord);
  71. 3: (FAsObject: Pointer);
  72. 4: (FAsClass: TClass);
  73. 5: (FAsSByte: Shortint);
  74. 6: (FAsSWord: Smallint);
  75. 7: (FAsSLong: LongInt);
  76. 8: (FAsSingle: Single);
  77. 9: (FAsDouble: Double);
  78. 10: (FAsExtended: Extended);
  79. 11: (FAsComp: Comp);
  80. 12: (FAsCurr: Currency);
  81. 13: (FAsUInt64: QWord);
  82. 14: (FAsSInt64: Int64);
  83. 15: (FAsMethod: TMethod);
  84. 16: (FAsPointer: Pointer);
  85. { FPC addition for open arrays }
  86. 17: (FArrLength: SizeInt; FElSize: SizeInt);
  87. end;
  88. { TValue }
  89. TValue = record
  90. private
  91. FData: TValueData;
  92. function GetDataSize: SizeInt;
  93. function GetTypeDataProp: PTypeData; inline;
  94. function GetTypeInfo: PTypeInfo; inline;
  95. function GetTypeKind: TTypeKind; inline;
  96. function GetIsEmpty: boolean; inline;
  97. public
  98. class function Empty: TValue; static;
  99. class procedure Make(ABuffer: pointer; ATypeInfo: PTypeInfo; out result: TValue); static;
  100. { Note: a TValue based on an open array is only valid until the routine having the open array parameter is left! }
  101. class procedure MakeOpenArray(AArray: Pointer; ALength: SizeInt; ATypeInfo: PTypeInfo; out Result: TValue); static;
  102. {$ifndef NoGenericMethods}
  103. generic class function From<T>(constref aValue: T): TValue; static; inline;
  104. { Note: a TValue based on an open array is only valid until the routine having the open array parameter is left! }
  105. generic class function FromOpenArray<T>(constref aValue: array of T): TValue; static; inline;
  106. {$endif}
  107. class function FromOrdinal(aTypeInfo: PTypeInfo; aValue: Int64): TValue; static; {inline;}
  108. function IsArray: boolean; inline;
  109. function IsOpenArray: Boolean; inline;
  110. function AsString: string; inline;
  111. function AsUnicodeString: UnicodeString;
  112. function AsAnsiString: AnsiString;
  113. function AsExtended: Extended;
  114. function IsClass: boolean; inline;
  115. function AsClass: TClass;
  116. function IsObject: boolean; inline;
  117. function AsObject: TObject;
  118. function IsOrdinal: boolean; inline;
  119. function AsOrdinal: Int64;
  120. function AsBoolean: boolean;
  121. function AsCurrency: Currency;
  122. function AsInteger: Integer;
  123. function AsInt64: Int64;
  124. function AsUInt64: QWord;
  125. function AsInterface: IInterface;
  126. function ToString: String;
  127. function GetArrayLength: SizeInt;
  128. function GetArrayElement(AIndex: SizeInt): TValue;
  129. procedure SetArrayElement(AIndex: SizeInt; constref AValue: TValue);
  130. function IsType(ATypeInfo: PTypeInfo): boolean; inline;
  131. function TryAsOrdinal(out AResult: int64): boolean;
  132. function GetReferenceToRawData: Pointer;
  133. procedure ExtractRawData(ABuffer: Pointer);
  134. procedure ExtractRawDataNoCopy(ABuffer: Pointer);
  135. class operator := (const AValue: String): TValue; inline;
  136. class operator := (AValue: LongInt): TValue; inline;
  137. class operator := (AValue: Single): TValue; inline;
  138. class operator := (AValue: Double): TValue; inline;
  139. {$ifdef FPC_HAS_TYPE_EXTENDED}
  140. class operator := (AValue: Extended): TValue; inline;
  141. {$endif}
  142. class operator := (AValue: Currency): TValue; inline;
  143. class operator := (AValue: Int64): TValue; inline;
  144. class operator := (AValue: QWord): TValue; inline;
  145. class operator := (AValue: TObject): TValue; inline;
  146. class operator := (AValue: TClass): TValue; inline;
  147. class operator := (AValue: Boolean): TValue; inline;
  148. property DataSize: SizeInt read GetDataSize;
  149. property Kind: TTypeKind read GetTypeKind;
  150. property TypeData: PTypeData read GetTypeDataProp;
  151. property TypeInfo: PTypeInfo read GetTypeInfo;
  152. property IsEmpty: boolean read GetIsEmpty;
  153. end;
  154. TValueArray = specialize TArray<TValue>;
  155. { TRttiContext }
  156. TRttiContext = record
  157. private
  158. FContextToken: IInterface;
  159. function GetByHandle(AHandle: Pointer): TRttiObject;
  160. procedure AddObject(AObject: TRttiObject);
  161. public
  162. class function Create: TRttiContext; static;
  163. procedure Free;
  164. function GetType(ATypeInfo: PTypeInfo): TRttiType;
  165. function GetType(AClass: TClass): TRttiType;
  166. //function GetTypes: specialize TArray<TRttiType>;
  167. end;
  168. { TRttiObject }
  169. TRttiObject = class abstract
  170. protected
  171. function GetHandle: Pointer; virtual; abstract;
  172. public
  173. function GetAttributes: specialize TArray<TCustomAttribute>; virtual; abstract;
  174. property Handle: Pointer read GetHandle;
  175. end;
  176. { TRttiNamedObject }
  177. TRttiNamedObject = class(TRttiObject)
  178. protected
  179. function GetName: string; virtual;
  180. public
  181. property Name: string read GetName;
  182. end;
  183. { TRttiType }
  184. TRttiType = class(TRttiNamedObject)
  185. private
  186. FTypeInfo: PTypeInfo;
  187. FAttributesResolved: boolean;
  188. FAttributes: specialize TArray<TCustomAttribute>;
  189. FMethods: specialize TArray<TRttiMethod>;
  190. function GetAsInstance: TRttiInstanceType;
  191. protected
  192. FTypeData: PTypeData;
  193. function GetName: string; override;
  194. function GetHandle: Pointer; override;
  195. function GetIsInstance: boolean; virtual;
  196. function GetIsManaged: boolean; virtual;
  197. function GetIsOrdinal: boolean; virtual;
  198. function GetIsRecord: boolean; virtual;
  199. function GetIsSet: boolean; virtual;
  200. function GetTypeKind: TTypeKind; virtual;
  201. function GetTypeSize: integer; virtual;
  202. function GetBaseType: TRttiType; virtual;
  203. public
  204. constructor Create(ATypeInfo : PTypeInfo);
  205. function GetAttributes: specialize TArray<TCustomAttribute>; override;
  206. function GetProperties: specialize TArray<TRttiProperty>; virtual;
  207. function GetProperty(const AName: string): TRttiProperty; virtual;
  208. function GetMethods: specialize TArray<TRttiMethod>; virtual;
  209. function GetMethod(const aName: String): TRttiMethod; virtual;
  210. function GetDeclaredMethods: specialize TArray<TRttiMethod>; virtual;
  211. property IsInstance: boolean read GetIsInstance;
  212. property isManaged: boolean read GetIsManaged;
  213. property IsOrdinal: boolean read GetIsOrdinal;
  214. property IsRecord: boolean read GetIsRecord;
  215. property IsSet: boolean read GetIsSet;
  216. property BaseType: TRttiType read GetBaseType;
  217. property AsInstance: TRttiInstanceType read GetAsInstance;
  218. property TypeKind: TTypeKind read GetTypeKind;
  219. property TypeSize: integer read GetTypeSize;
  220. end;
  221. { TRttiFloatType }
  222. TRttiFloatType = class(TRttiType)
  223. private
  224. function GetFloatType: TFloatType; inline;
  225. protected
  226. function GetTypeSize: integer; override;
  227. public
  228. property FloatType: TFloatType read GetFloatType;
  229. end;
  230. TRttiOrdinalType = class(TRttiType)
  231. private
  232. function GetMaxValue: LongInt; inline;
  233. function GetMinValue: LongInt; inline;
  234. function GetOrdType: TOrdType; inline;
  235. protected
  236. function GetTypeSize: Integer; override;
  237. public
  238. property OrdType: TOrdType read GetOrdType;
  239. property MinValue: LongInt read GetMinValue;
  240. property MaxValue: LongInt read GetMaxValue;
  241. end;
  242. TRttiInt64Type = class(TRttiType)
  243. private
  244. function GetMaxValue: Int64; inline;
  245. function GetMinValue: Int64; inline;
  246. function GetUnsigned: Boolean; inline;
  247. protected
  248. function GetTypeSize: integer; override;
  249. public
  250. property MinValue: Int64 read GetMinValue;
  251. property MaxValue: Int64 read GetMaxValue;
  252. property Unsigned: Boolean read GetUnsigned;
  253. end;
  254. TRttiStringKind = (skShortString, skAnsiString, skWideString, skUnicodeString);
  255. { TRttiStringType }
  256. TRttiStringType = class(TRttiType)
  257. private
  258. function GetStringKind: TRttiStringKind;
  259. public
  260. property StringKind: TRttiStringKind read GetStringKind;
  261. end;
  262. TRttiPointerType = class(TRttiType)
  263. private
  264. function GetReferredType: TRttiType;
  265. public
  266. property ReferredType: TRttiType read GetReferredType;
  267. end;
  268. { TRttiMember }
  269. TMemberVisibility=(mvPrivate, mvProtected, mvPublic, mvPublished);
  270. TRttiMember = class(TRttiNamedObject)
  271. private
  272. FParent: TRttiType;
  273. protected
  274. function GetVisibility: TMemberVisibility; virtual;
  275. public
  276. constructor Create(AParent: TRttiType);
  277. property Visibility: TMemberVisibility read GetVisibility;
  278. property Parent: TRttiType read FParent;
  279. end;
  280. { TRttiProperty }
  281. TRttiProperty = class(TRttiMember)
  282. private
  283. FPropInfo: PPropInfo;
  284. FAttributesResolved: boolean;
  285. FAttributes: specialize TArray<TCustomAttribute>;
  286. function GetPropertyType: TRttiType;
  287. function GetIsWritable: boolean;
  288. function GetIsReadable: boolean;
  289. protected
  290. function GetVisibility: TMemberVisibility; override;
  291. function GetName: string; override;
  292. function GetHandle: Pointer; override;
  293. public
  294. constructor Create(AParent: TRttiType; APropInfo: PPropInfo);
  295. function GetAttributes: specialize TArray<TCustomAttribute>; override;
  296. function GetValue(Instance: pointer): TValue;
  297. procedure SetValue(Instance: pointer; const AValue: TValue);
  298. property PropertyType: TRttiType read GetPropertyType;
  299. property IsReadable: boolean read GetIsReadable;
  300. property IsWritable: boolean read GetIsWritable;
  301. property Visibility: TMemberVisibility read GetVisibility;
  302. end;
  303. TRttiParameter = class(TRttiNamedObject)
  304. private
  305. FString: String;
  306. protected
  307. function GetParamType: TRttiType; virtual; abstract;
  308. function GetFlags: TParamFlags; virtual; abstract;
  309. public
  310. property ParamType: TRttiType read GetParamType;
  311. property Flags: TParamFlags read GetFlags;
  312. function ToString: String; override;
  313. end;
  314. TMethodImplementationCallbackMethod = procedure(aUserData: Pointer; const aArgs: TValueArray; out aResult: TValue) of object;
  315. TMethodImplementationCallbackProc = procedure(aUserData: Pointer; const aArgs: TValueArray; out aResult: TValue);
  316. TMethodImplementation = class
  317. private
  318. fLowLevelCallback: TFunctionCallCallback;
  319. fCallbackProc: TMethodImplementationCallbackProc;
  320. fCallbackMethod: TMethodImplementationCallbackMethod;
  321. fArgs: specialize TArray<TFunctionCallParameterInfo>;
  322. fArgLen: SizeInt;
  323. fRefArgs: specialize TArray<SizeInt>;
  324. fFlags: TFunctionCallFlags;
  325. fResult: PTypeInfo;
  326. fCC: TCallConv;
  327. function GetCodeAddress: CodePointer;
  328. procedure InitArgs;
  329. procedure HandleCallback(const aArgs: specialize TArray<Pointer>; aResult: Pointer; aContext: Pointer);
  330. constructor Create(aCC: TCallConv; aArgs: specialize TArray<TFunctionCallParameterInfo>; aResult: PTypeInfo; aFlags: TFunctionCallFlags; aUserData: Pointer; aCallback: TMethodImplementationCallbackMethod);
  331. constructor Create(aCC: TCallConv; aArgs: specialize TArray<TFunctionCallParameterInfo>; aResult: PTypeInfo; aFlags: TFunctionCallFlags; aUserData: Pointer; aCallback: TMethodImplementationCallbackProc);
  332. public
  333. constructor Create;
  334. destructor Destroy; override;
  335. property CodeAddress: CodePointer read GetCodeAddress;
  336. end;
  337. TRttiInvokableType = class(TRttiType)
  338. protected
  339. function GetParameters(aWithHidden: Boolean): specialize TArray<TRttiParameter>; virtual; abstract;
  340. function GetCallingConvention: TCallConv; virtual; abstract;
  341. function GetReturnType: TRttiType; virtual; abstract;
  342. function GetFlags: TFunctionCallFlags; virtual; abstract;
  343. public type
  344. TCallbackMethod = procedure(aInvokable: TRttiInvokableType; const aArgs: TValueArray; out aResult: TValue) of object;
  345. TCallbackProc = procedure(aInvokable: TRttiInvokableType; const aArgs: TValueArray; out aResult: TValue);
  346. public
  347. function GetParameters: specialize TArray<TRttiParameter>; inline;
  348. property CallingConvention: TCallConv read GetCallingConvention;
  349. property ReturnType: TRttiType read GetReturnType;
  350. function Invoke(const aProcOrMeth: TValue; const aArgs: array of TValue): TValue; virtual; abstract;
  351. { Note: once "reference to" is supported these will be replaced by a single method }
  352. function CreateImplementation(aCallback: TCallbackMethod): TMethodImplementation;
  353. function CreateImplementation(aCallback: TCallbackProc): TMethodImplementation;
  354. end;
  355. TRttiMethodType = class(TRttiInvokableType)
  356. private
  357. FCallConv: TCallConv;
  358. FReturnType: TRttiType;
  359. FParams, FParamsAll: specialize TArray<TRttiParameter>;
  360. protected
  361. function GetParameters(aWithHidden: Boolean): specialize TArray<TRttiParameter>; override;
  362. function GetCallingConvention: TCallConv; override;
  363. function GetReturnType: TRttiType; override;
  364. function GetFlags: TFunctionCallFlags; override;
  365. public
  366. function Invoke(const aCallable: TValue; const aArgs: array of TValue): TValue; override;
  367. end;
  368. TRttiProcedureType = class(TRttiInvokableType)
  369. private
  370. FParams, FParamsAll: specialize TArray<TRttiParameter>;
  371. protected
  372. function GetParameters(aWithHidden: Boolean): specialize TArray<TRttiParameter>; override;
  373. function GetCallingConvention: TCallConv; override;
  374. function GetReturnType: TRttiType; override;
  375. function GetFlags: TFunctionCallFlags; override;
  376. public
  377. function Invoke(const aCallable: TValue; const aArgs: array of TValue): TValue; override;
  378. end;
  379. TDispatchKind = (
  380. dkStatic,
  381. dkVtable,
  382. dkDynamic,
  383. dkMessage,
  384. dkInterface,
  385. { the following are FPC-only and will be moved should Delphi add more }
  386. dkMessageString
  387. );
  388. TRttiMethod = class(TRttiMember)
  389. private
  390. FString: String;
  391. function GetFlags: TFunctionCallFlags;
  392. protected
  393. function GetCallingConvention: TCallConv; virtual; abstract;
  394. function GetCodeAddress: CodePointer; virtual; abstract;
  395. function GetDispatchKind: TDispatchKind; virtual; abstract;
  396. function GetHasExtendedInfo: Boolean; virtual;
  397. function GetIsClassMethod: Boolean; virtual; abstract;
  398. function GetIsConstructor: Boolean; virtual; abstract;
  399. function GetIsDestructor: Boolean; virtual; abstract;
  400. function GetIsStatic: Boolean; virtual; abstract;
  401. function GetMethodKind: TMethodKind; virtual; abstract;
  402. function GetReturnType: TRttiType; virtual; abstract;
  403. function GetVirtualIndex: SmallInt; virtual; abstract;
  404. function GetParameters(aWithHidden: Boolean): specialize TArray<TRttiParameter>; virtual; abstract;
  405. public
  406. property CallingConvention: TCallConv read GetCallingConvention;
  407. property CodeAddress: CodePointer read GetCodeAddress;
  408. property DispatchKind: TDispatchKind read GetDispatchKind;
  409. property HasExtendedInfo: Boolean read GetHasExtendedInfo;
  410. property IsClassMethod: Boolean read GetIsClassMethod;
  411. property IsConstructor: Boolean read GetIsConstructor;
  412. property IsDestructor: Boolean read GetIsDestructor;
  413. property IsStatic: Boolean read GetIsStatic;
  414. property MethodKind: TMethodKind read GetMethodKind;
  415. property ReturnType: TRttiType read GetReturnType;
  416. property VirtualIndex: SmallInt read GetVirtualIndex;
  417. function ToString: String; override;
  418. function GetParameters: specialize TArray<TRttiParameter>; inline;
  419. function Invoke(aInstance: TObject; const aArgs: array of TValue): TValue;
  420. function Invoke(aInstance: TClass; const aArgs: array of TValue): TValue;
  421. function Invoke(aInstance: TValue; const aArgs: array of TValue): TValue;
  422. { Note: once "reference to" is supported these will be replaced by a single method }
  423. function CreateImplementation(aUserData: Pointer; aCallback: TMethodImplementationCallbackMethod): TMethodImplementation;
  424. function CreateImplementation(aUserData: Pointer; aCallback: TMethodImplementationCallbackProc): TMethodImplementation;
  425. end;
  426. TRttiStructuredType = class(TRttiType)
  427. end;
  428. TInterfaceType = (
  429. itRefCounted, { aka COM interface }
  430. itRaw { aka CORBA interface }
  431. );
  432. TRttiInterfaceType = class(TRttiType)
  433. private
  434. fDeclaredMethods: specialize TArray<TRttiMethod>;
  435. protected
  436. function IntfMethodCount: Word;
  437. function MethodTable: PIntfMethodTable; virtual; abstract;
  438. function GetBaseType: TRttiType; override;
  439. function GetIntfBaseType: TRttiInterfaceType; virtual; abstract;
  440. function GetDeclaringUnitName: String; virtual; abstract;
  441. function GetGUID: TGUID; virtual; abstract;
  442. function GetGUIDStr: String; virtual;
  443. function GetIntfFlags: TIntfFlags; virtual; abstract;
  444. function GetIntfType: TInterfaceType; virtual; abstract;
  445. public
  446. property BaseType: TRttiInterfaceType read GetIntfBaseType;
  447. property DeclaringUnitName: String read GetDeclaringUnitName;
  448. property GUID: TGUID read GetGUID;
  449. property GUIDStr: String read GetGUIDStr;
  450. property IntfFlags: TIntfFlags read GetIntfFlags;
  451. property IntfType: TInterfaceType read GetIntfType;
  452. function GetDeclaredMethods: specialize TArray<TRttiMethod>; override;
  453. end;
  454. { TRttiInstanceType }
  455. TRttiInstanceType = class(TRttiStructuredType)
  456. private
  457. FPropertiesResolved: Boolean;
  458. FProperties: specialize TArray<TRttiProperty>;
  459. function GetDeclaringUnitName: string;
  460. function GetMetaClassType: TClass;
  461. protected
  462. function GetIsInstance: boolean; override;
  463. function GetTypeSize: integer; override;
  464. function GetBaseType: TRttiType; override;
  465. public
  466. function GetProperties: specialize TArray<TRttiProperty>; override;
  467. property MetaClassType: TClass read GetMetaClassType;
  468. property DeclaringUnitName: string read GetDeclaringUnitName;
  469. end;
  470. TVirtualInterfaceInvokeEvent = procedure(aMethod: TRttiMethod; const aArgs: TValueArray; out aResult: TValue) of object;
  471. TVirtualInterface = class(TInterfacedObject, IInterface)
  472. private
  473. fGUID: TGUID;
  474. fOnInvoke: TVirtualInterfaceInvokeEvent;
  475. fContext: TRttiContext;
  476. fThunks: array[0..2] of CodePointer;
  477. fImpls: array of TMethodImplementation;
  478. fVmt: PCodePointer;
  479. fQueryInterfaceType: TRttiType;
  480. fAddRefType: TRttiType;
  481. fReleaseType: TRttiType;
  482. protected
  483. function QueryInterface(constref aIID: TGuid; out aObj): LongInt;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  484. procedure HandleIInterfaceCallback(aInvokable: TRttiInvokableType; const aArgs: TValueArray; out aResult: TValue);
  485. procedure HandleUserCallback(aUserData: Pointer; const aArgs: TValueArray; out aResult: TValue);
  486. public
  487. constructor Create(aPIID: PTypeInfo);
  488. constructor Create(aPIID: PTypeInfo; aInvokeEvent: TVirtualInterfaceInvokeEvent);
  489. destructor Destroy; override;
  490. property OnInvoke: TVirtualInterfaceInvokeEvent read fOnInvoke write fOnInvoke;
  491. end;
  492. ERtti = class(Exception);
  493. EInsufficientRtti = class(ERtti);
  494. EInvocationError = class(ERtti);
  495. ENonPublicType = class(ERtti);
  496. TFunctionCallParameter = record
  497. ValueRef: Pointer;
  498. ValueSize: SizeInt;
  499. Info: TFunctionCallParameterInfo;
  500. end;
  501. TFunctionCallParameterArray = specialize TArray<TFunctionCallParameter>;
  502. TFunctionCallProc = procedure(const aArgs: specialize TArray<Pointer>; aResult: Pointer; aContext: Pointer);
  503. TFunctionCallMethod = procedure(const aArgs: specialize TArray<Pointer>; aResult: Pointer; aContext: Pointer) of object;
  504. TFunctionCallManager = record
  505. Invoke: procedure(CodeAddress: CodePointer; const Args: TFunctionCallParameterArray; CallingConvention: TCallConv;
  506. ResultType: PTypeInfo; ResultValue: Pointer; Flags: TFunctionCallFlags);
  507. CreateCallbackProc: function(aHandler: TFunctionCallProc; aCallConv: TCallConv; aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags; aContext: Pointer): TFunctionCallCallback;
  508. CreateCallbackMethod: function(aHandler: TFunctionCallMethod; aCallConv: TCallConv; aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags; aContext: Pointer): TFunctionCallCallback;
  509. end;
  510. TFunctionCallManagerArray = array[TCallConv] of TFunctionCallManager;
  511. TCallConvSet = set of TCallConv;
  512. procedure SetFunctionCallManager(aCallConv: TCallConv; constref aFuncCallMgr: TFunctionCallManager; out aOldFuncCallMgr: TFunctionCallManager);
  513. procedure SetFunctionCallManager(aCallConv: TCallConv; constref aFuncCallMgr: TFunctionCallManager);
  514. procedure SetFunctionCallManager(aCallConvs: TCallConvSet; constref aFuncCallMgr: TFunctionCallManager; out aOldFuncCallMgrs: TFunctionCallManagerArray);
  515. procedure SetFunctionCallManager(aCallConvs: TCallConvSet; constref aFuncCallMgr: TFunctionCallManager);
  516. procedure SetFunctionCallManagers(aCallConvs: TCallConvSet; constref aFuncCallMgrs: TFunctionCallManagerArray; out aOldFuncCallMgrs: TFunctionCallManagerArray);
  517. procedure SetFunctionCallManagers(aCallConvs: TCallConvSet; constref aFuncCallMgrs: TFunctionCallManagerArray);
  518. procedure SetFunctionCallManagers(constref aFuncCallMgrs: TFunctionCallManagerArray; out aOldFuncCallMgrs: TFunctionCallManagerArray);
  519. procedure SetFunctionCallManagers(constref aFuncCallMgrs: TFunctionCallManagerArray);
  520. procedure GetFunctionCallManager(aCallConv: TCallConv; out aFuncCallMgr: TFunctionCallManager);
  521. procedure GetFunctionCallManagers(aCallConvs: TCallConvSet; out aFuncCallMgrs: TFunctionCallManagerArray);
  522. procedure GetFunctionCallManagers(out aFuncCallMgrs: TFunctionCallManagerArray);
  523. function Invoke(aCodeAddress: CodePointer; const aArgs: TValueArray; aCallConv: TCallConv;
  524. aResultType: PTypeInfo; aIsStatic: Boolean; aIsConstructor: Boolean): TValue;
  525. function CreateCallbackProc(aHandler: TFunctionCallProc; aCallConv: TCallConv; aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags; aContext: Pointer): TFunctionCallCallback;
  526. function CreateCallbackMethod(aHandler: TFunctionCallMethod; aCallConv: TCallConv; aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags; aContext: Pointer): TFunctionCallCallback;
  527. function IsManaged(TypeInfo: PTypeInfo): boolean;
  528. {$ifndef InLazIDE}
  529. generic function OpenArrayToDynArrayValue<T>(constref aArray: array of T): TValue;
  530. {$endif}
  531. { these resource strings are needed by units implementing function call managers }
  532. resourcestring
  533. SErrInvokeNotImplemented = 'Invoke functionality is not implemented';
  534. SErrInvokeResultTypeNoValue = 'Function has a result type, but no result pointer provided';
  535. SErrInvokeFailed = 'Invoke call failed';
  536. SErrMethodImplCreateFailed = 'Failed to create method implementation';
  537. SErrCallbackNotImplemented = 'Callback functionality is not implemented';
  538. SErrCallConvNotSupported = 'Calling convention not supported: %s';
  539. SErrTypeKindNotSupported = 'Type kind is not supported: %s';
  540. SErrCallbackHandlerNil = 'Callback handler is Nil';
  541. SErrMissingSelfParam = 'Missing self parameter';
  542. implementation
  543. uses
  544. {$ifdef windows}
  545. Windows,
  546. {$endif}
  547. {$ifdef unix}
  548. BaseUnix,
  549. {$endif}
  550. fgl;
  551. type
  552. { TRttiPool }
  553. TRttiPool = class
  554. private type
  555. TRttiObjectMap = specialize TFPGMap<Pointer, TRttiObject>;
  556. private
  557. FObjectMap: TRttiObjectMap;
  558. FTypesList: specialize TArray<TRttiType>;
  559. FTypeCount: LongInt;
  560. FLock: TRTLCriticalSection;
  561. public
  562. function GetTypes: specialize TArray<TRttiType>;
  563. function GetType(ATypeInfo: PTypeInfo): TRttiType;
  564. function GetByHandle(aHandle: Pointer): TRttiObject;
  565. procedure AddObject(aObject: TRttiObject);
  566. constructor Create;
  567. destructor Destroy; override;
  568. end;
  569. IPooltoken = interface
  570. ['{3CDB3CE9-AB55-CBAA-7B9D-2F3BB1CF5AF8}']
  571. function RttiPool: TRttiPool;
  572. end;
  573. { TPoolToken }
  574. TPoolToken = class(TInterfacedObject, IPooltoken)
  575. public
  576. constructor Create;
  577. destructor Destroy; override;
  578. function RttiPool: TRttiPool;
  579. end;
  580. { TValueDataIntImpl }
  581. TValueDataIntImpl = class(TInterfacedObject, IValueData)
  582. private
  583. FBuffer: Pointer;
  584. FDataSize: SizeInt;
  585. FTypeInfo: PTypeInfo;
  586. FIsCopy: Boolean;
  587. FUseAddRef: Boolean;
  588. public
  589. constructor CreateCopy(ACopyFromBuffer: Pointer; ALen: SizeInt; ATypeInfo: PTypeInfo; AAddRef: Boolean);
  590. constructor CreateRef(AData: Pointer; ATypeInfo: PTypeInfo; AAddRef: Boolean);
  591. destructor Destroy; override;
  592. procedure ExtractRawData(ABuffer: pointer);
  593. procedure ExtractRawDataNoCopy(ABuffer: pointer);
  594. function GetDataSize: SizeInt;
  595. function GetReferenceToRawData: pointer;
  596. end;
  597. TRttiRefCountedInterfaceType = class(TRttiInterfaceType)
  598. private
  599. function IntfData: PInterfaceData; inline;
  600. protected
  601. function MethodTable: PIntfMethodTable; override;
  602. function GetIntfBaseType: TRttiInterfaceType; override;
  603. function GetDeclaringUnitName: String; override;
  604. function GetGUID: TGUID; override;
  605. function GetIntfFlags: TIntfFlags; override;
  606. function GetIntfType: TInterfaceType; override;
  607. end;
  608. TRttiRawInterfaceType = class(TRttiInterfaceType)
  609. private
  610. function IntfData: PInterfaceRawData; inline;
  611. protected
  612. function MethodTable: PIntfMethodTable; override;
  613. function GetIntfBaseType: TRttiInterfaceType; override;
  614. function GetDeclaringUnitName: String; override;
  615. function GetGUID: TGUID; override;
  616. function GetGUIDStr: String; override;
  617. function GetIntfFlags: TIntfFlags; override;
  618. function GetIntfType: TInterfaceType; override;
  619. end;
  620. TRttiVmtMethodParameter = class(TRttiParameter)
  621. private
  622. FVmtMethodParam: PVmtMethodParam;
  623. protected
  624. function GetHandle: Pointer; override;
  625. function GetName: String; override;
  626. function GetFlags: TParamFlags; override;
  627. function GetParamType: TRttiType; override;
  628. public
  629. constructor Create(AVmtMethodParam: PVmtMethodParam);
  630. end;
  631. TRttiMethodTypeParameter = class(TRttiParameter)
  632. private
  633. fHandle: Pointer;
  634. fName: String;
  635. fFlags: TParamFlags;
  636. fType: PTypeInfo;
  637. protected
  638. function GetHandle: Pointer; override;
  639. function GetName: String; override;
  640. function GetFlags: TParamFlags; override;
  641. function GetParamType: TRttiType; override;
  642. public
  643. constructor Create(aHandle: Pointer; const aName: String; aFlags: TParamFlags; aType: PTypeInfo);
  644. end;
  645. TRttiIntfMethod = class(TRttiMethod)
  646. private
  647. FIntfMethodEntry: PIntfMethodEntry;
  648. FIndex: SmallInt;
  649. FParams, FParamsAll: specialize TArray<TRttiParameter>;
  650. protected
  651. function GetHandle: Pointer; override;
  652. function GetName: String; override;
  653. function GetCallingConvention: TCallConv; override;
  654. function GetCodeAddress: CodePointer; override;
  655. function GetDispatchKind: TDispatchKind; override;
  656. function GetHasExtendedInfo: Boolean; override;
  657. function GetIsClassMethod: Boolean; override;
  658. function GetIsConstructor: Boolean; override;
  659. function GetIsDestructor: Boolean; override;
  660. function GetIsStatic: Boolean; override;
  661. function GetMethodKind: TMethodKind; override;
  662. function GetReturnType: TRttiType; override;
  663. function GetVirtualIndex: SmallInt; override;
  664. function GetParameters(aWithHidden: Boolean): specialize TArray<TRttiParameter>; override;
  665. public
  666. constructor Create(AParent: TRttiType; AIntfMethodEntry: PIntfMethodEntry; AIndex: SmallInt);
  667. end;
  668. resourcestring
  669. SErrUnableToGetValueForType = 'Unable to get value for type %s';
  670. SErrUnableToSetValueForType = 'Unable to set value for type %s';
  671. SErrInvalidTypecast = 'Invalid class typecast';
  672. SErrRttiObjectNoHandle = 'RTTI object instance has no valid handle property';
  673. SErrRttiObjectAlreadyRegistered = 'A RTTI object with handle 0x%x is already registered';
  674. SErrInvokeInsufficientRtti = 'Insufficient RTTI to invoke function';
  675. SErrInvokeStaticNoSelf = 'Static function must not be called with in an instance: %s';
  676. SErrInvokeNotStaticNeedsSelf = 'Non static function must be called with an instance: %s';
  677. SErrInvokeClassMethodClassSelf = 'Class method needs to be called with a class type: %s';
  678. SErrInvokeArrayArgExpected = 'Array argument expected for parameter %s of method %s';
  679. SErrInvokeArgInvalidType = 'Invalid type of argument for parameter %s of method %s';
  680. SErrInvokeArgCount = 'Invalid argument count for method %s; expected %d, but got %d';
  681. SErrInvokeNoCodeAddr = 'Failed to determine code address for method: %s';
  682. SErrInvokeRttiDataError = 'The RTTI data is inconsistent for method: %s';
  683. SErrInvokeCallableNotProc = 'The callable value is not a procedure variable for: %s';
  684. SErrInvokeCallableNotMethod = 'The callable value is not a method variable for: %s';
  685. SErrMethodImplNoCallback = 'No callback specified for method implementation';
  686. SErrMethodImplInsufficientRtti = 'Insufficient RTTI to create method implementation';
  687. SErrMethodImplCreateNoArg = 'TMethodImplementation can not be created this way';
  688. SErrVirtIntfTypeNil = 'No type information provided for TVirtualInterface';
  689. SErrVirtIntfTypeMustBeIntf = 'Type ''%s'' is not an interface type';
  690. SErrVirtIntfTypeNotFound = 'Type ''%s'' is not valid';
  691. SErrVirtIntfNotAllMethodsRTTI = 'Not all methods of ''%s'' or its parents have the required RTTI';
  692. SErrVirtIntfRetrieveIInterface = 'Failed to retrieve IInterface information';
  693. SErrVirtIntfCreateThunk = 'Failed to create thunks for ''%0:s''';
  694. SErrVirtIntfCreateImpl = 'Failed to create implementation for method ''%1:s'' of ''%0:s''';
  695. SErrVirtIntfInvalidVirtIdx = 'Virtual index %2:d for method ''%1:s'' of ''%0:s'' is invalid';
  696. SErrVirtIntfMethodNil = 'Method %1:d of ''%0:s'' is Nil';
  697. SErrVirtIntfCreateVmt = 'Failed to create VMT for ''%s''';
  698. SErrVirtIntfIInterface = 'Failed to prepare IInterface method callbacks';
  699. var
  700. PoolRefCount : integer;
  701. GRttiPool : TRttiPool;
  702. FuncCallMgr: TFunctionCallManagerArray;
  703. function AllocateMemory(aSize: PtrUInt): Pointer;
  704. begin
  705. {$IF DEFINED(WINDOWS)}
  706. Result := VirtualAlloc(Nil, aSize, MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE);
  707. {$ELSEIF DEFINED(UNIX)}
  708. Result := fpmmap(Nil, aSize, PROT_READ or PROT_WRITE, MAP_PRIVATE or MAP_ANONYMOUS, 0, 0);
  709. {$ELSE}
  710. Result := Nil;
  711. {$ENDIF}
  712. end;
  713. function ProtectMemory(aPtr: Pointer; aSize: PtrUInt; aExecutable: Boolean): Boolean;
  714. {$IF DEFINED(WINDOWS)}
  715. var
  716. oldprot: DWORD;
  717. {$ENDIF}
  718. begin
  719. {$IF DEFINED(WINDOWS)}
  720. if aExecutable then
  721. Result := VirtualProtect(aPtr, aSize, PAGE_EXECUTE_READ, oldprot)
  722. else
  723. Result := VirtualProtect(aPtr, aSize, PAGE_READWRITE, oldprot);
  724. {$ELSEIF DEFINED(UNIX)}
  725. if aExecutable then
  726. Result := Fpmprotect(aPtr, aSize, PROT_EXEC or PROT_READ) = 0
  727. else
  728. Result := Fpmprotect(aPtr, aSize, PROT_READ or PROT_WRITE) = 0;
  729. {$ELSE}
  730. Result := False;
  731. {$ENDIF}
  732. end;
  733. procedure FreeMemory(aPtr: Pointer; aSize: PtrUInt);
  734. begin
  735. {$IF DEFINED(WINDOWS)}
  736. VirtualFree(aPtr, 0, MEM_RELEASE);
  737. {$ELSEIF DEFINED(UNIX)}
  738. fpmunmap(aPtr, aSize);
  739. {$ELSE}
  740. { nothing }
  741. {$ENDIF}
  742. end;
  743. label
  744. RawThunkEnd;
  745. {$if defined(cpui386)}
  746. const
  747. RawThunkPlaceholderBytesToPop = $12341234;
  748. RawThunkPlaceholderProc = $87658765;
  749. RawThunkPlaceholderContext = $43214321;
  750. type
  751. TRawThunkBytesToPop = UInt32;
  752. TRawThunkProc = PtrUInt;
  753. TRawThunkContext = PtrUInt;
  754. { works for both cdecl and stdcall }
  755. procedure RawThunk; assembler; nostackframe;
  756. asm
  757. { the stack layout is
  758. $ReturnAddr <- ESP
  759. ArgN
  760. ArgN - 1
  761. ...
  762. Arg1
  763. Arg0
  764. aBytesToPop is the size of the stack to the Self argument }
  765. movl RawThunkPlaceholderBytesToPop, %eax
  766. movl %esp, %ecx
  767. lea (%ecx,%eax), %eax
  768. movl RawThunkPlaceholderContext, (%eax)
  769. movl RawThunkPlaceholderProc, %eax
  770. jmp %eax
  771. RawThunkEnd:
  772. end;
  773. {$elseif defined(cpux86_64)}
  774. const
  775. RawThunkPlaceholderProc = PtrUInt($8765876587658765);
  776. RawThunkPlaceholderContext = PtrUInt($4321432143214321);
  777. type
  778. TRawThunkProc = PtrUInt;
  779. TRawThunkContext = PtrUInt;
  780. {$ifdef win64}
  781. procedure RawThunk; assembler; nostackframe;
  782. asm
  783. { Self is always in register RCX }
  784. movq RawThunkPlaceholderContext, %rcx
  785. movq RawThunkPlaceholderProc, %rax
  786. jmp %rax
  787. RawThunkEnd:
  788. end;
  789. {$else}
  790. procedure RawThunk; assembler; nostackframe;
  791. asm
  792. { Self is always in register RDI }
  793. movq RawThunkPlaceholderContext, %rdi
  794. movq RawThunkPlaceholderProc, %rax
  795. jmp %rax
  796. RawThunkEnd:
  797. end;
  798. {$endif}
  799. {$endif}
  800. {$if declared(RawThunk)}
  801. const
  802. RawThunkEndPtr: Pointer = @RawThunkEnd;
  803. type
  804. {$if declared(TRawThunkBytesToPop)}
  805. PRawThunkBytesToPop = ^TRawThunkBytesToPop;
  806. {$endif}
  807. PRawThunkContext = ^TRawThunkContext;
  808. PRawThunkProc = ^TRawThunkProc;
  809. {$endif}
  810. { Delphi has these as part of TRawVirtualClass.TVTable; until we have that we
  811. simply leave that here in the implementation }
  812. function AllocateRawThunk(aProc: CodePointer; aContext: Pointer; aBytesToPop: SizeInt): Pointer;
  813. {$if declared(RawThunk)}
  814. var
  815. size, i: SizeInt;
  816. {$if declared(TRawThunkBytesToPop)}
  817. btp: PRawThunkBytesToPop;
  818. btpdone: Boolean;
  819. {$endif}
  820. context: PRawThunkContext;
  821. contextdone: Boolean;
  822. proc: PRawThunkProc;
  823. procdone: Boolean;
  824. {$endif}
  825. begin
  826. {$if not declared(RawThunk)}
  827. { platform dose not have thunk support... :/ }
  828. Result := Nil;
  829. {$else}
  830. Size := PtrUInt(RawThunkEndPtr) - PtrUInt(@RawThunk) + 1;
  831. Result := AllocateMemory(size);
  832. Move(Pointer(@RawThunk)^, Result^, size);
  833. {$if declared(TRawThunkBytesToPop)}
  834. btpdone := False;
  835. {$endif}
  836. contextdone := False;
  837. procdone := False;
  838. for i := 0 to Size - 1 do begin
  839. {$if declared(TRawThunkBytesToPop)}
  840. if not btpdone and (i <= Size - SizeOf(TRawThunkBytesToPop)) then begin
  841. btp := PRawThunkBytesToPop(PByte(Result) + i);
  842. if btp^ = RawThunkPlaceholderBytesToPop then begin
  843. btp^ := TRawThunkBytesToPop(aBytesToPop);
  844. btpdone := True;
  845. end;
  846. end;
  847. {$endif}
  848. if not contextdone and (i <= Size - SizeOf(TRawThunkContext)) then begin
  849. context := PRawThunkContext(PByte(Result) + i);
  850. if context^ = RawThunkPlaceholderContext then begin
  851. context^ := TRawThunkContext(aContext);
  852. contextdone := True;
  853. end;
  854. end;
  855. if not procdone and (i <= Size - SizeOf(TRawThunkProc)) then begin
  856. proc := PRawThunkProc(PByte(Result) + i);
  857. if proc^ = RawThunkPlaceholderProc then begin
  858. proc^ := TRawThunkProc(aProc);
  859. procdone := True;
  860. end;
  861. end;
  862. end;
  863. if not contextdone or not procdone
  864. {$if declared(TRawThunkBytesToPop)}
  865. or not btpdone
  866. {$endif}
  867. then begin
  868. FreeMemory(Result, Size);
  869. Result := Nil;
  870. end else
  871. ProtectMemory(Result, Size, True);
  872. {$endif}
  873. end;
  874. procedure FreeRawThunk(aThunk: Pointer);
  875. begin
  876. {$if declared(RawThunk)}
  877. FreeMemory(aThunk, PtrUInt(RawThunkEndPtr) - PtrUInt(@RawThunk));
  878. {$endif}
  879. end;
  880. function CCToStr(aCC: TCallConv): String; inline;
  881. begin
  882. WriteStr(Result, aCC);
  883. end;
  884. procedure NoInvoke(aCodeAddress: CodePointer; const aArgs: TFunctionCallParameterArray; aCallConv: TCallConv;
  885. aResultType: PTypeInfo; aResultValue: Pointer; aFlags: TFunctionCallFlags);
  886. begin
  887. raise ENotImplemented.Create(SErrInvokeNotImplemented);
  888. end;
  889. function NoCreateCallbackProc(aFunc: TFunctionCallProc; aCallConv: TCallConv; aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags; aContext: Pointer): TFunctionCallCallback;
  890. begin
  891. Result := Nil;
  892. raise ENotImplemented.Create(SErrCallbackNotImplemented);
  893. end;
  894. function NoCreateCallbackMethod(aFunc: TFunctionCallMethod; aCallConv: TCallConv; aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags; aContext: Pointer): TFunctionCallCallback;
  895. begin
  896. Result := Nil;
  897. raise ENotImplemented.Create(SErrCallbackNotImplemented);
  898. end;
  899. const
  900. NoFunctionCallManager: TFunctionCallManager = (
  901. Invoke: @NoInvoke;
  902. CreateCallbackProc: @NoCreateCallbackProc;
  903. CreateCallbackMethod: @NoCreateCallbackMethod;
  904. );
  905. procedure SetFunctionCallManager(aCallConv: TCallConv; constref aFuncCallMgr: TFunctionCallManager;
  906. out aOldFuncCallMgr: TFunctionCallManager);
  907. begin
  908. aOldFuncCallMgr := FuncCallMgr[aCallConv];
  909. FuncCallMgr[aCallConv] := aFuncCallMgr;
  910. end;
  911. procedure SetFunctionCallManager(aCallConv: TCallConv; constref aFuncCallMgr: TFunctionCallManager);
  912. var
  913. dummy: TFunctionCallManager;
  914. begin
  915. SetFunctionCallManager(aCallConv, aFuncCallMgr, dummy);
  916. end;
  917. procedure SetFunctionCallManager(aCallConvs: TCallConvSet; constref aFuncCallMgr: TFunctionCallManager;
  918. out aOldFuncCallMgrs: TFunctionCallManagerArray);
  919. var
  920. cc: TCallConv;
  921. begin
  922. for cc := Low(TCallConv) to High(TCallConv) do
  923. if cc in aCallConvs then begin
  924. aOldFuncCallMgrs[cc] := FuncCallMgr[cc];
  925. FuncCallMgr[cc] := aFuncCallMgr;
  926. end else
  927. aOldFuncCallMgrs[cc] := Default(TFunctionCallManager);
  928. end;
  929. procedure SetFunctionCallManager(aCallConvs: TCallConvSet; constref aFuncCallMgr: TFunctionCallManager);
  930. var
  931. dummy: TFunctionCallManagerArray;
  932. begin
  933. SetFunctionCallManager(aCallConvs, aFuncCallMgr, dummy);
  934. end;
  935. procedure SetFunctionCallManagers(aCallConvs: TCallConvSet; constref aFuncCallMgrs: TFunctionCallManagerArray; out aOldFuncCallMgrs: TFunctionCallManagerArray);
  936. var
  937. cc: TCallConv;
  938. begin
  939. for cc := Low(TCallConv) to High(TCallConv) do
  940. if cc in aCallConvs then begin
  941. aOldFuncCallMgrs[cc] := FuncCallMgr[cc];
  942. FuncCallMgr[cc] := aFuncCallMgrs[cc];
  943. end else
  944. aOldFuncCallMgrs[cc] := Default(TFunctionCallManager);
  945. end;
  946. procedure SetFunctionCallManagers(aCallConvs: TCallConvSet; constref aFuncCallMgrs: TFunctionCallManagerArray);
  947. var
  948. dummy: TFunctionCallManagerArray;
  949. begin
  950. SetFunctionCallManagers(aCallConvs, aFuncCallMgrs, dummy);
  951. end;
  952. procedure SetFunctionCallManagers(constref aFuncCallMgrs: TFunctionCallManagerArray; out aOldFuncCallMgrs: TFunctionCallManagerArray);
  953. begin
  954. aOldFuncCallMgrs := FuncCallMgr;
  955. FuncCallMgr := aFuncCallMgrs;
  956. end;
  957. procedure SetFunctionCallManagers(constref aFuncCallMgrs: TFunctionCallManagerArray);
  958. var
  959. dummy: TFunctionCallManagerArray;
  960. begin
  961. SetFunctionCallManagers(aFuncCallMgrs, dummy);
  962. end;
  963. procedure GetFunctionCallManager(aCallConv: TCallConv; out aFuncCallMgr: TFunctionCallManager);
  964. begin
  965. aFuncCallMgr := FuncCallMgr[aCallConv];
  966. end;
  967. procedure GetFunctionCallManagers(aCallConvs: TCallConvSet; out aFuncCallMgrs: TFunctionCallManagerArray);
  968. var
  969. cc: TCallConv;
  970. begin
  971. for cc := Low(TCallConv) to High(TCallConv) do
  972. if cc in aCallConvs then
  973. aFuncCallMgrs[cc] := FuncCallMgr[cc]
  974. else
  975. aFuncCallMgrs[cc] := Default(TFunctionCallManager);
  976. end;
  977. procedure GetFunctionCallManagers(out aFuncCallMgrs: TFunctionCallManagerArray);
  978. begin
  979. aFuncCallMgrs := FuncCallMgr;
  980. end;
  981. procedure InitDefaultFunctionCallManager;
  982. var
  983. cc: TCallConv;
  984. begin
  985. for cc := Low(TCallConv) to High(TCallConv) do
  986. FuncCallMgr[cc] := NoFunctionCallManager;
  987. end;
  988. { TRttiPool }
  989. function TRttiPool.GetTypes: specialize TArray<TRttiType>;
  990. begin
  991. if not Assigned(FTypesList) then
  992. Exit(Nil);
  993. {$ifdef FPC_HAS_FEATURE_THREADING}
  994. EnterCriticalsection(FLock);
  995. try
  996. {$endif}
  997. Result := Copy(FTypesList, 0, FTypeCount);
  998. {$ifdef FPC_HAS_FEATURE_THREADING}
  999. finally
  1000. LeaveCriticalsection(FLock);
  1001. end;
  1002. {$endif}
  1003. end;
  1004. function TRttiPool.GetType(ATypeInfo: PTypeInfo): TRttiType;
  1005. var
  1006. obj: TRttiObject;
  1007. begin
  1008. if not Assigned(ATypeInfo) then
  1009. Exit(Nil);
  1010. {$ifdef FPC_HAS_FEATURE_THREADING}
  1011. EnterCriticalsection(FLock);
  1012. try
  1013. {$endif}
  1014. Result := Nil;
  1015. obj := GetByHandle(ATypeInfo);
  1016. if Assigned(obj) then
  1017. Result := obj as TRttiType;
  1018. if not Assigned(Result) then
  1019. begin
  1020. if FTypeCount = Length(FTypesList) then
  1021. begin
  1022. SetLength(FTypesList, FTypeCount * 2);
  1023. end;
  1024. case ATypeInfo^.Kind of
  1025. tkClass : Result := TRttiInstanceType.Create(ATypeInfo);
  1026. tkInterface: Result := TRttiRefCountedInterfaceType.Create(ATypeInfo);
  1027. tkInterfaceRaw: Result := TRttiRawInterfaceType.Create(ATypeInfo);
  1028. tkInt64,
  1029. tkQWord: Result := TRttiInt64Type.Create(ATypeInfo);
  1030. tkInteger,
  1031. tkChar,
  1032. tkWChar: Result := TRttiOrdinalType.Create(ATypeInfo);
  1033. tkSString,
  1034. tkLString,
  1035. tkAString,
  1036. tkUString,
  1037. tkWString : Result := TRttiStringType.Create(ATypeInfo);
  1038. tkFloat : Result := TRttiFloatType.Create(ATypeInfo);
  1039. tkPointer : Result := TRttiPointerType.Create(ATypeInfo);
  1040. tkProcVar : Result := TRttiProcedureType.Create(ATypeInfo);
  1041. tkMethod : Result := TRttiMethodType.Create(ATypeInfo);
  1042. else
  1043. Result := TRttiType.Create(ATypeInfo);
  1044. end;
  1045. FTypesList[FTypeCount] := Result;
  1046. FObjectMap.Add(ATypeInfo, Result);
  1047. Inc(FTypeCount);
  1048. end;
  1049. {$ifdef FPC_HAS_FEATURE_THREADING}
  1050. finally
  1051. LeaveCriticalsection(FLock);
  1052. end;
  1053. {$endif}
  1054. end;
  1055. function TRttiPool.GetByHandle(aHandle: Pointer): TRttiObject;
  1056. var
  1057. idx: LongInt;
  1058. begin
  1059. if not Assigned(aHandle) then
  1060. Exit(Nil);
  1061. {$ifdef FPC_HAS_FEATURE_THREADING}
  1062. EnterCriticalsection(FLock);
  1063. try
  1064. {$endif}
  1065. idx := FObjectMap.IndexOf(aHandle);
  1066. if idx < 0 then
  1067. Result := Nil
  1068. else
  1069. Result := FObjectMap.Data[idx];
  1070. {$ifdef FPC_HAS_FEATURE_THREADING}
  1071. finally
  1072. LeaveCriticalsection(FLock);
  1073. end;
  1074. {$endif}
  1075. end;
  1076. procedure TRttiPool.AddObject(aObject: TRttiObject);
  1077. var
  1078. idx: LongInt;
  1079. begin
  1080. if not Assigned(aObject) then
  1081. Exit;
  1082. if not Assigned(aObject.Handle) then
  1083. raise EArgumentException.Create(SErrRttiObjectNoHandle);
  1084. {$ifdef FPC_HAS_FEATURE_THREADING}
  1085. EnterCriticalsection(FLock);
  1086. try
  1087. {$endif}
  1088. idx := FObjectMap.IndexOf(aObject.Handle);
  1089. if idx < 0 then
  1090. FObjectMap.Add(aObject.Handle, aObject)
  1091. else if FObjectMap.Data[idx] <> aObject then
  1092. raise EInvalidOpException.CreateFmt(SErrRttiObjectAlreadyRegistered, [aObject.Handle]);
  1093. {$ifdef FPC_HAS_FEATURE_THREADING}
  1094. finally
  1095. LeaveCriticalsection(FLock);
  1096. end;
  1097. {$endif}
  1098. end;
  1099. constructor TRttiPool.Create;
  1100. begin
  1101. {$ifdef FPC_HAS_FEATURE_THREADING}
  1102. InitCriticalSection(FLock);
  1103. {$endif}
  1104. SetLength(FTypesList, 32);
  1105. FObjectMap := TRttiObjectMap.Create;
  1106. end;
  1107. destructor TRttiPool.Destroy;
  1108. var
  1109. i: LongInt;
  1110. begin
  1111. for i := 0 to FObjectMap.Count - 1 do
  1112. FObjectMap.Data[i].Free;
  1113. FObjectMap.Free;
  1114. {$ifdef FPC_HAS_FEATURE_THREADING}
  1115. DoneCriticalsection(FLock);
  1116. {$endif}
  1117. inherited Destroy;
  1118. end;
  1119. { TPoolToken }
  1120. constructor TPoolToken.Create;
  1121. begin
  1122. inherited Create;
  1123. if InterlockedIncrement(PoolRefCount)=1 then
  1124. GRttiPool := TRttiPool.Create;
  1125. end;
  1126. destructor TPoolToken.Destroy;
  1127. begin
  1128. if InterlockedDecrement(PoolRefCount)=0 then
  1129. GRttiPool.Free;
  1130. inherited;
  1131. end;
  1132. function TPoolToken.RttiPool: TRttiPool;
  1133. begin
  1134. result := GRttiPool;
  1135. end;
  1136. { TValueDataIntImpl }
  1137. procedure IntFinalize(APointer, ATypeInfo: Pointer);
  1138. external name 'FPC_FINALIZE';
  1139. procedure IntInitialize(APointer, ATypeInfo: Pointer);
  1140. external name 'FPC_INITIALIZE';
  1141. procedure IntAddRef(APointer, ATypeInfo: Pointer);
  1142. external name 'FPC_ADDREF';
  1143. function IntCopy(ASource, ADest, ATypeInfo: Pointer): SizeInt;
  1144. external name 'FPC_COPY';
  1145. constructor TValueDataIntImpl.CreateCopy(ACopyFromBuffer: Pointer; ALen: SizeInt; ATypeInfo: PTypeInfo; AAddRef: Boolean);
  1146. begin
  1147. FTypeInfo := ATypeInfo;
  1148. FDataSize:=ALen;
  1149. if ALen>0 then
  1150. begin
  1151. Getmem(FBuffer,FDataSize);
  1152. if Assigned(ACopyFromBuffer) then
  1153. system.move(ACopyFromBuffer^,FBuffer^,FDataSize)
  1154. else
  1155. FillChar(FBuffer^, FDataSize, 0);
  1156. end;
  1157. FIsCopy := True;
  1158. FUseAddRef := AAddRef;
  1159. if AAddRef and (ALen > 0) then begin
  1160. if Assigned(ACopyFromBuffer) then
  1161. IntAddRef(FBuffer, FTypeInfo)
  1162. else
  1163. IntInitialize(FBuffer, FTypeInfo);
  1164. end;
  1165. end;
  1166. constructor TValueDataIntImpl.CreateRef(AData: Pointer; ATypeInfo: PTypeInfo; AAddRef: Boolean);
  1167. begin
  1168. FTypeInfo := ATypeInfo;
  1169. FDataSize := SizeOf(Pointer);
  1170. if Assigned(AData) then
  1171. FBuffer := PPointer(AData)^
  1172. else
  1173. FBuffer := Nil;
  1174. FIsCopy := False;
  1175. FUseAddRef := AAddRef;
  1176. if AAddRef and Assigned(AData) then
  1177. IntAddRef(@FBuffer, FTypeInfo);
  1178. end;
  1179. destructor TValueDataIntImpl.Destroy;
  1180. begin
  1181. if Assigned(FBuffer) then begin
  1182. if FUseAddRef then
  1183. if FIsCopy then
  1184. IntFinalize(FBuffer, FTypeInfo)
  1185. else
  1186. IntFinalize(@FBuffer, FTypeInfo);
  1187. if FIsCopy then
  1188. Freemem(FBuffer);
  1189. end;
  1190. inherited Destroy;
  1191. end;
  1192. procedure TValueDataIntImpl.ExtractRawData(ABuffer: pointer);
  1193. begin
  1194. if FDataSize = 0 then
  1195. Exit;
  1196. if FIsCopy then
  1197. System.Move(FBuffer^, ABuffer^, FDataSize)
  1198. else
  1199. System.Move(FBuffer{!}, ABuffer^, FDataSize);
  1200. if FUseAddRef then
  1201. IntAddRef(ABuffer, FTypeInfo);
  1202. end;
  1203. procedure TValueDataIntImpl.ExtractRawDataNoCopy(ABuffer: pointer);
  1204. begin
  1205. if FDataSize = 0 then
  1206. Exit;
  1207. if FIsCopy then
  1208. system.move(FBuffer^, ABuffer^, FDataSize)
  1209. else
  1210. System.Move(FBuffer{!}, ABuffer^, FDataSize);
  1211. end;
  1212. function TValueDataIntImpl.GetDataSize: SizeInt;
  1213. begin
  1214. result := FDataSize;
  1215. end;
  1216. function TValueDataIntImpl.GetReferenceToRawData: pointer;
  1217. begin
  1218. if FIsCopy then
  1219. result := FBuffer
  1220. else
  1221. result := @FBuffer;
  1222. end;
  1223. { TValue }
  1224. class function TValue.Empty: TValue;
  1225. begin
  1226. result.FData.FTypeInfo := nil;
  1227. {$if SizeOf(TMethod) > SizeOf(QWord)}
  1228. Result.FData.FAsMethod.Code := Nil;
  1229. Result.FData.FAsMethod.Data := Nil;
  1230. {$else}
  1231. Result.FData.FAsUInt64 := 0;
  1232. {$endif}
  1233. end;
  1234. function TValue.GetTypeDataProp: PTypeData;
  1235. begin
  1236. result := GetTypeData(FData.FTypeInfo);
  1237. end;
  1238. function TValue.GetTypeInfo: PTypeInfo;
  1239. begin
  1240. result := FData.FTypeInfo;
  1241. end;
  1242. function TValue.GetTypeKind: TTypeKind;
  1243. begin
  1244. if not Assigned(FData.FTypeInfo) then
  1245. Result := tkUnknown
  1246. else
  1247. result := FData.FTypeInfo^.Kind;
  1248. end;
  1249. function TValue.GetDataSize: SizeInt;
  1250. begin
  1251. if Assigned(FData.FValueData) and (Kind <> tkSString) then
  1252. Result := FData.FValueData.GetDataSize
  1253. else begin
  1254. Result := 0;
  1255. case Kind of
  1256. tkEnumeration,
  1257. tkBool,
  1258. tkInt64,
  1259. tkQWord,
  1260. tkInteger:
  1261. case TypeData^.OrdType of
  1262. otSByte,
  1263. otUByte:
  1264. Result := SizeOf(Byte);
  1265. otSWord,
  1266. otUWord:
  1267. Result := SizeOf(Word);
  1268. otSLong,
  1269. otULong:
  1270. Result := SizeOf(LongWord);
  1271. otSQWord,
  1272. otUQWord:
  1273. Result := SizeOf(QWord);
  1274. end;
  1275. tkChar:
  1276. Result := SizeOf(AnsiChar);
  1277. tkFloat:
  1278. case TypeData^.FloatType of
  1279. ftSingle:
  1280. Result := SizeOf(Single);
  1281. ftDouble:
  1282. Result := SizeOf(Double);
  1283. ftExtended:
  1284. Result := SizeOf(Extended);
  1285. ftComp:
  1286. Result := SizeOf(Comp);
  1287. ftCurr:
  1288. Result := SizeOf(Currency);
  1289. end;
  1290. tkSet:
  1291. Result := TypeData^.SetSize;
  1292. tkMethod:
  1293. Result := SizeOf(TMethod);
  1294. tkSString:
  1295. { ShortString can hold max. 254 characters as [0] is Length and [255] is #0 }
  1296. Result := SizeOf(ShortString) - 2;
  1297. tkVariant:
  1298. Result := SizeOf(Variant);
  1299. tkProcVar:
  1300. Result := SizeOf(CodePointer);
  1301. tkWChar:
  1302. Result := SizeOf(WideChar);
  1303. tkUChar:
  1304. Result := SizeOf(UnicodeChar);
  1305. tkFile:
  1306. { ToDo }
  1307. Result := SizeOf(TTextRec);
  1308. tkAString,
  1309. tkWString,
  1310. tkUString,
  1311. tkInterface,
  1312. tkDynArray,
  1313. tkClass,
  1314. tkHelper,
  1315. tkClassRef,
  1316. tkInterfaceRaw,
  1317. tkPointer:
  1318. Result := SizeOf(Pointer);
  1319. tkObject,
  1320. tkRecord:
  1321. Result := TypeData^.RecSize;
  1322. tkArray:
  1323. Result := TypeData^.ArrayData.Size;
  1324. tkUnknown,
  1325. tkLString:
  1326. Assert(False);
  1327. end;
  1328. end;
  1329. end;
  1330. class procedure TValue.Make(ABuffer: pointer; ATypeInfo: PTypeInfo; out result: TValue);
  1331. type
  1332. PBoolean16 = ^Boolean16;
  1333. PBoolean32 = ^Boolean32;
  1334. PBoolean64 = ^Boolean64;
  1335. PByteBool = ^ByteBool;
  1336. PQWordBool = ^QWordBool;
  1337. PMethod = ^TMethod;
  1338. var
  1339. td: PTypeData;
  1340. size: SizeInt;
  1341. begin
  1342. result.FData.FTypeInfo:=ATypeInfo;
  1343. { resets the whole variant part; FValueData is already Nil }
  1344. {$if SizeOf(TMethod) > SizeOf(QWord)}
  1345. Result.FData.FAsMethod.Code := Nil;
  1346. Result.FData.FAsMethod.Data := Nil;
  1347. {$else}
  1348. Result.FData.FAsUInt64 := 0;
  1349. {$endif}
  1350. if not Assigned(ATypeInfo) then
  1351. Exit;
  1352. { first handle those types that need a TValueData implementation }
  1353. case ATypeInfo^.Kind of
  1354. tkSString : begin
  1355. td := GetTypeData(ATypeInfo);
  1356. result.FData.FValueData := TValueDataIntImpl.CreateCopy(ABuffer, td^.MaxLength + 1, ATypeInfo, True);
  1357. end;
  1358. tkWString,
  1359. tkUString,
  1360. tkAString : result.FData.FValueData := TValueDataIntImpl.CreateRef(ABuffer, ATypeInfo, True);
  1361. tkDynArray : result.FData.FValueData := TValueDataIntImpl.CreateRef(ABuffer, ATypeInfo, True);
  1362. tkArray : result.FData.FValueData := TValueDataIntImpl.CreateCopy(ABuffer, Result.TypeData^.ArrayData.Size, ATypeInfo, False);
  1363. tkObject,
  1364. tkRecord : result.FData.FValueData := TValueDataIntImpl.CreateCopy(ABuffer, Result.TypeData^.RecSize, ATypeInfo, False);
  1365. tkInterface: result.FData.FValueData := TValueDataIntImpl.CreateRef(ABuffer, ATypeInfo, True);
  1366. end;
  1367. if not Assigned(ABuffer) then
  1368. Exit;
  1369. { now handle those that are happy with the variant part of FData }
  1370. case ATypeInfo^.Kind of
  1371. tkSString,
  1372. tkWString,
  1373. tkUString,
  1374. tkAString,
  1375. tkDynArray,
  1376. tkArray,
  1377. tkObject,
  1378. tkRecord,
  1379. tkInterface:
  1380. { ignore }
  1381. ;
  1382. tkClass : result.FData.FAsObject := PPointer(ABuffer)^;
  1383. tkClassRef : result.FData.FAsClass := PClass(ABuffer)^;
  1384. tkInterfaceRaw : result.FData.FAsPointer := PPointer(ABuffer)^;
  1385. tkInt64 : result.FData.FAsSInt64 := PInt64(ABuffer)^;
  1386. tkQWord : result.FData.FAsUInt64 := PQWord(ABuffer)^;
  1387. tkProcVar : result.FData.FAsMethod.Code := PCodePointer(ABuffer)^;
  1388. tkMethod : result.FData.FAsMethod := PMethod(ABuffer)^;
  1389. tkPointer : result.FData.FAsPointer := PPointer(ABuffer)^;
  1390. tkSet : begin
  1391. td := GetTypeData(ATypeInfo);
  1392. case td^.OrdType of
  1393. otUByte: begin
  1394. { this can either really be 1 Byte or a set > 32-bit, so
  1395. check the underlying type }
  1396. if not (td^.CompType^.Kind in [tkInteger,tkEnumeration]) then
  1397. raise Exception.CreateFmt(SErrUnableToGetValueForType,[ATypeInfo^.Name]);
  1398. case td^.SetSize of
  1399. 0, 1:
  1400. Result.FData.FAsUByte := PByte(ABuffer)^;
  1401. { these two cases shouldn't happen, but better safe than sorry... }
  1402. 2:
  1403. Result.FData.FAsUWord := PWord(ABuffer)^;
  1404. 3, 4:
  1405. Result.FData.FAsULong := PLongWord(ABuffer)^;
  1406. { maybe we should also allow storage as otUQWord? }
  1407. 5..8:
  1408. Result.FData.FAsUInt64 := PQWord(ABuffer)^;
  1409. else
  1410. Result.FData.FValueData := TValueDataIntImpl.CreateCopy(ABuffer, td^.SetSize, ATypeInfo, False);
  1411. end;
  1412. end;
  1413. otUWord:
  1414. Result.FData.FAsUWord := PWord(ABuffer)^;
  1415. otULong:
  1416. Result.FData.FAsULong := PLongWord(ABuffer)^;
  1417. else
  1418. { ehm... Panic? }
  1419. raise Exception.CreateFmt(SErrUnableToGetValueForType,[ATypeInfo^.Name]);
  1420. end;
  1421. end;
  1422. tkChar,
  1423. tkWChar,
  1424. tkUChar,
  1425. tkEnumeration,
  1426. tkInteger : begin
  1427. case GetTypeData(ATypeInfo)^.OrdType of
  1428. otSByte: result.FData.FAsSByte := PShortInt(ABuffer)^;
  1429. otUByte: result.FData.FAsUByte := PByte(ABuffer)^;
  1430. otSWord: result.FData.FAsSWord := PSmallInt(ABuffer)^;
  1431. otUWord: result.FData.FAsUWord := PWord(ABuffer)^;
  1432. otSLong: result.FData.FAsSLong := PLongInt(ABuffer)^;
  1433. otULong: result.FData.FAsULong := PLongWord(ABuffer)^;
  1434. end;
  1435. end;
  1436. tkBool : begin
  1437. case GetTypeData(ATypeInfo)^.OrdType of
  1438. otUByte: result.FData.FAsUByte := Byte(System.PBoolean(ABuffer)^);
  1439. otUWord: result.FData.FAsUWord := Word(PBoolean16(ABuffer)^);
  1440. otULong: result.FData.FAsULong := DWord(PBoolean32(ABuffer)^);
  1441. otUQWord: result.FData.FAsUInt64 := QWord(PBoolean64(ABuffer)^);
  1442. otSByte: result.FData.FAsSByte := ShortInt(PByteBool(ABuffer)^);
  1443. otSWord: result.FData.FAsSWord := SmallInt(PWordBool(ABuffer)^);
  1444. otSLong: result.FData.FAsSLong := LongInt(PLongBool(ABuffer)^);
  1445. otSQWord: result.FData.FAsSInt64 := Int64(PQWordBool(ABuffer)^);
  1446. end;
  1447. end;
  1448. tkFloat : begin
  1449. case GetTypeData(ATypeInfo)^.FloatType of
  1450. ftCurr : result.FData.FAsCurr := PCurrency(ABuffer)^;
  1451. ftSingle : result.FData.FAsSingle := PSingle(ABuffer)^;
  1452. ftDouble : result.FData.FAsDouble := PDouble(ABuffer)^;
  1453. ftExtended: result.FData.FAsExtended := PExtended(ABuffer)^;
  1454. ftComp : result.FData.FAsComp := PComp(ABuffer)^;
  1455. end;
  1456. end;
  1457. else
  1458. raise Exception.CreateFmt(SErrUnableToGetValueForType,[ATypeInfo^.Name]);
  1459. end;
  1460. end;
  1461. class procedure TValue.MakeOpenArray(AArray: Pointer; ALength: SizeInt; ATypeInfo: PTypeInfo; out Result: TValue);
  1462. var
  1463. el: TValue;
  1464. begin
  1465. Result.FData.FTypeInfo := ATypeInfo;
  1466. { resets the whole variant part; FValueData is already Nil }
  1467. {$if SizeOf(TMethod) > SizeOf(QWord)}
  1468. Result.FData.FAsMethod.Code := Nil;
  1469. Result.FData.FAsMethod.Data := Nil;
  1470. {$else}
  1471. Result.FData.FAsUInt64 := 0;
  1472. {$endif}
  1473. if not Assigned(ATypeInfo) then
  1474. Exit;
  1475. if ATypeInfo^.Kind <> tkArray then
  1476. Exit;
  1477. if not Assigned(AArray) then
  1478. Exit;
  1479. if ALength < 0 then
  1480. Exit;
  1481. Result.FData.FValueData := TValueDataIntImpl.CreateRef(@AArray, ATypeInfo, False);
  1482. Result.FData.FArrLength := ALength;
  1483. Make(Nil, Result.TypeData^.ArrayData.ElType, el);
  1484. Result.FData.FElSize := el.DataSize;
  1485. end;
  1486. {$ifndef NoGenericMethods}
  1487. generic class function TValue.From<T>(constref aValue: T): TValue;
  1488. begin
  1489. TValue.Make(@aValue, PTypeInfo(System.TypeInfo(T)), Result);
  1490. end;
  1491. generic class function TValue.FromOpenArray<T>(constref aValue: array of T): TValue;
  1492. var
  1493. arrdata: Pointer;
  1494. begin
  1495. if Length(aValue) > 0 then
  1496. arrdata := @aValue[0]
  1497. else
  1498. arrdata := Nil;
  1499. TValue.MakeOpenArray(arrdata, Length(aValue), PTypeInfo(System.TypeInfo(aValue)), Result);
  1500. end;
  1501. {$endif}
  1502. class function TValue.FromOrdinal(aTypeInfo: PTypeInfo; aValue: Int64): TValue;
  1503. begin
  1504. if not Assigned(aTypeInfo) or
  1505. not (aTypeInfo^.Kind in [tkInteger, tkInt64, tkQWord, tkEnumeration, tkBool, tkChar, tkWChar, tkUChar]) then
  1506. raise EInvalidCast.Create(SErrInvalidTypecast);
  1507. TValue.Make(@aValue, aTypeInfo, Result);
  1508. end;
  1509. function TValue.GetIsEmpty: boolean;
  1510. begin
  1511. result := (FData.FTypeInfo=nil) or
  1512. ((Kind in [tkSString, tkObject, tkRecord, tkArray]) and not Assigned(FData.FValueData)) or
  1513. ((Kind in [tkClass, tkClassRef, tkInterfaceRaw]) and not Assigned(FData.FAsPointer));
  1514. end;
  1515. function TValue.IsArray: boolean;
  1516. begin
  1517. result := kind in [tkArray, tkDynArray];
  1518. end;
  1519. function TValue.IsOpenArray: Boolean;
  1520. var
  1521. td: PTypeData;
  1522. begin
  1523. td := TypeData;
  1524. Result := (Kind = tkArray) and (td^.ArrayData.Size = 0) and (td^.ArrayData.ElCount = 0)
  1525. end;
  1526. function TValue.AsString: string;
  1527. begin
  1528. if System.GetTypeKind(String) = tkUString then
  1529. Result := String(AsUnicodeString)
  1530. else
  1531. Result := String(AsAnsiString);
  1532. end;
  1533. function TValue.AsUnicodeString: UnicodeString;
  1534. begin
  1535. if (Kind in [tkSString, tkAString, tkUString, tkWString]) and not Assigned(FData.FValueData) then
  1536. Result := ''
  1537. else
  1538. case Kind of
  1539. tkSString:
  1540. Result := UnicodeString(PShortString(FData.FValueData.GetReferenceToRawData)^);
  1541. tkAString:
  1542. Result := UnicodeString(PAnsiString(FData.FValueData.GetReferenceToRawData)^);
  1543. tkWString:
  1544. Result := UnicodeString(PWideString(FData.FValueData.GetReferenceToRawData)^);
  1545. tkUString:
  1546. Result := UnicodeString(PUnicodeString(FData.FValueData.GetReferenceToRawData)^);
  1547. else
  1548. raise EInvalidCast.Create(SErrInvalidTypecast);
  1549. end;
  1550. end;
  1551. function TValue.AsAnsiString: AnsiString;
  1552. begin
  1553. if (Kind in [tkSString, tkAString, tkUString, tkWString]) and not Assigned(FData.FValueData) then
  1554. Result := ''
  1555. else
  1556. case Kind of
  1557. tkSString:
  1558. Result := AnsiString(PShortString(FData.FValueData.GetReferenceToRawData)^);
  1559. tkAString:
  1560. Result := AnsiString(PAnsiString(FData.FValueData.GetReferenceToRawData)^);
  1561. tkWString:
  1562. Result := AnsiString(PWideString(FData.FValueData.GetReferenceToRawData)^);
  1563. tkUString:
  1564. Result := AnsiString(PUnicodeString(FData.FValueData.GetReferenceToRawData)^);
  1565. else
  1566. raise EInvalidCast.Create(SErrInvalidTypecast);
  1567. end;
  1568. end;
  1569. function TValue.AsExtended: Extended;
  1570. begin
  1571. if Kind = tkFloat then
  1572. begin
  1573. case TypeData^.FloatType of
  1574. ftSingle : result := FData.FAsSingle;
  1575. ftDouble : result := FData.FAsDouble;
  1576. ftExtended : result := FData.FAsExtended;
  1577. ftCurr : result := FData.FAsCurr;
  1578. ftComp : result := FData.FAsComp;
  1579. else
  1580. raise EInvalidCast.Create(SErrInvalidTypecast);
  1581. end;
  1582. end
  1583. else
  1584. raise EInvalidCast.Create(SErrInvalidTypecast);
  1585. end;
  1586. function TValue.IsObject: boolean;
  1587. begin
  1588. result := (Kind = tkClass) or ((Kind = tkUnknown) and not Assigned(FData.FAsObject));
  1589. end;
  1590. function TValue.IsClass: boolean;
  1591. begin
  1592. result := (Kind = tkClassRef) or ((Kind in [tkClass,tkUnknown]) and not Assigned(FData.FAsObject));
  1593. end;
  1594. function TValue.IsOrdinal: boolean;
  1595. begin
  1596. result := (Kind in [tkInteger, tkInt64, tkQWord, tkBool, tkEnumeration, tkChar, tkWChar, tkUChar]) or
  1597. ((Kind in [tkClass, tkClassRef, tkInterfaceRaw, tkUnknown]) and not Assigned(FData.FAsPointer));
  1598. end;
  1599. function TValue.IsType(ATypeInfo: PTypeInfo): boolean;
  1600. begin
  1601. result := ATypeInfo = TypeInfo;
  1602. end;
  1603. function TValue.AsObject: TObject;
  1604. begin
  1605. if IsObject or (IsClass and not Assigned(FData.FAsObject)) then
  1606. result := TObject(FData.FAsObject)
  1607. else
  1608. raise EInvalidCast.Create(SErrInvalidTypecast);
  1609. end;
  1610. function TValue.AsClass: TClass;
  1611. begin
  1612. if IsClass then
  1613. result := FData.FAsClass
  1614. else
  1615. raise EInvalidCast.Create(SErrInvalidTypecast);
  1616. end;
  1617. function TValue.AsBoolean: boolean;
  1618. begin
  1619. if (Kind = tkBool) then
  1620. case TypeData^.OrdType of
  1621. otSByte: Result := ByteBool(FData.FAsSByte);
  1622. otUByte: Result := Boolean(FData.FAsUByte);
  1623. otSWord: Result := WordBool(FData.FAsSWord);
  1624. otUWord: Result := Boolean16(FData.FAsUWord);
  1625. otSLong: Result := LongBool(FData.FAsSLong);
  1626. otULong: Result := Boolean32(FData.FAsULong);
  1627. otSQWord: Result := QWordBool(FData.FAsSInt64);
  1628. otUQWord: Result := Boolean64(FData.FAsUInt64);
  1629. end
  1630. else
  1631. raise EInvalidCast.Create(SErrInvalidTypecast);
  1632. end;
  1633. function TValue.AsOrdinal: Int64;
  1634. begin
  1635. if IsOrdinal then
  1636. if Kind in [tkClass, tkClassRef, tkInterfaceRaw, tkUnknown] then
  1637. Result := 0
  1638. else
  1639. case TypeData^.OrdType of
  1640. otSByte: Result := FData.FAsSByte;
  1641. otUByte: Result := FData.FAsUByte;
  1642. otSWord: Result := FData.FAsSWord;
  1643. otUWord: Result := FData.FAsUWord;
  1644. otSLong: Result := FData.FAsSLong;
  1645. otULong: Result := FData.FAsULong;
  1646. otSQWord: Result := FData.FAsSInt64;
  1647. otUQWord: Result := FData.FAsUInt64;
  1648. end
  1649. else
  1650. raise EInvalidCast.Create(SErrInvalidTypecast);
  1651. end;
  1652. function TValue.AsCurrency: Currency;
  1653. begin
  1654. if (Kind = tkFloat) and (TypeData^.FloatType=ftCurr) then
  1655. result := FData.FAsCurr
  1656. else
  1657. raise EInvalidCast.Create(SErrInvalidTypecast);
  1658. end;
  1659. function TValue.AsInteger: Integer;
  1660. begin
  1661. if Kind in [tkInteger, tkInt64, tkQWord] then
  1662. case TypeData^.OrdType of
  1663. otSByte: Result := FData.FAsSByte;
  1664. otUByte: Result := FData.FAsUByte;
  1665. otSWord: Result := FData.FAsSWord;
  1666. otUWord: Result := FData.FAsUWord;
  1667. otSLong: Result := FData.FAsSLong;
  1668. otULong: Result := FData.FAsULong;
  1669. otSQWord: Result := FData.FAsSInt64;
  1670. otUQWord: Result := FData.FAsUInt64;
  1671. end
  1672. else
  1673. raise EInvalidCast.Create(SErrInvalidTypecast);
  1674. end;
  1675. function TValue.AsInt64: Int64;
  1676. begin
  1677. if Kind in [tkInteger, tkInt64, tkQWord] then
  1678. case TypeData^.OrdType of
  1679. otSByte: Result := FData.FAsSByte;
  1680. otUByte: Result := FData.FAsUByte;
  1681. otSWord: Result := FData.FAsSWord;
  1682. otUWord: Result := FData.FAsUWord;
  1683. otSLong: Result := FData.FAsSLong;
  1684. otULong: Result := FData.FAsULong;
  1685. otSQWord: Result := FData.FAsSInt64;
  1686. otUQWord: Result := FData.FAsUInt64;
  1687. end
  1688. else if (Kind = tkFloat) and (TypeData^.FloatType = ftComp) then
  1689. Result := Int64(FData.FAsComp)
  1690. else
  1691. raise EInvalidCast.Create(SErrInvalidTypecast);
  1692. end;
  1693. function TValue.AsUInt64: QWord;
  1694. begin
  1695. if Kind in [tkInteger, tkInt64, tkQWord] then
  1696. case TypeData^.OrdType of
  1697. otSByte: Result := FData.FAsSByte;
  1698. otUByte: Result := FData.FAsUByte;
  1699. otSWord: Result := FData.FAsSWord;
  1700. otUWord: Result := FData.FAsUWord;
  1701. otSLong: Result := FData.FAsSLong;
  1702. otULong: Result := FData.FAsULong;
  1703. otSQWord: Result := FData.FAsSInt64;
  1704. otUQWord: Result := FData.FAsUInt64;
  1705. end
  1706. else if (Kind = tkFloat) and (TypeData^.FloatType = ftComp) then
  1707. Result := QWord(FData.FAsComp)
  1708. else
  1709. raise EInvalidCast.Create(SErrInvalidTypecast);
  1710. end;
  1711. function TValue.AsInterface: IInterface;
  1712. begin
  1713. if Kind = tkInterface then
  1714. Result := PInterface(FData.FValueData.GetReferenceToRawData)^
  1715. else if (Kind in [tkClass, tkClassRef, tkUnknown]) and not Assigned(FData.FAsPointer) then
  1716. Result := Nil
  1717. else
  1718. raise EInvalidCast.Create(SErrInvalidTypecast);
  1719. end;
  1720. function TValue.ToString: String;
  1721. begin
  1722. case Kind of
  1723. tkWString,
  1724. tkUString : result := AsUnicodeString;
  1725. tkSString,
  1726. tkAString : result := AsAnsiString;
  1727. tkInteger : result := IntToStr(AsInteger);
  1728. tkQWord : result := IntToStr(AsUInt64);
  1729. tkInt64 : result := IntToStr(AsInt64);
  1730. tkBool : result := BoolToStr(AsBoolean, True);
  1731. tkPointer : result := '(pointer @ ' + HexStr(FData.FAsPointer) + ')';
  1732. tkInterface : result := '(interface @ ' + HexStr(PPointer(FData.FValueData.GetReferenceToRawData)^) + ')';
  1733. tkInterfaceRaw : result := '(raw interface @ ' + HexStr(FData.FAsPointer) + ')';
  1734. else
  1735. result := '';
  1736. end;
  1737. end;
  1738. function TValue.GetArrayLength: SizeInt;
  1739. var
  1740. td: PTypeData;
  1741. begin
  1742. if not IsArray then
  1743. raise EInvalidCast.Create(SErrInvalidTypecast);
  1744. if Kind = tkDynArray then
  1745. Result := DynArraySize(PPointer(FData.FValueData.GetReferenceToRawData)^)
  1746. else begin
  1747. td := TypeData;
  1748. if (td^.ArrayData.Size = 0) and (td^.ArrayData.ElCount = 0) then
  1749. Result := FData.FArrLength
  1750. else
  1751. Result := td^.ArrayData.ElCount;
  1752. end;
  1753. end;
  1754. function TValue.GetArrayElement(AIndex: SizeInt): TValue;
  1755. var
  1756. data: Pointer;
  1757. eltype: PTypeInfo;
  1758. elsize: SizeInt;
  1759. td: PTypeData;
  1760. begin
  1761. if not IsArray then
  1762. raise EInvalidCast.Create(SErrInvalidTypecast);
  1763. if Kind = tkDynArray then begin
  1764. data := DynArrayIndex(PPointer(FData.FValueData.GetReferenceToRawData)^, [AIndex], FData.FTypeInfo);
  1765. eltype := TypeData^.elType2;
  1766. end else begin
  1767. td := TypeData;
  1768. eltype := td^.ArrayData.ElType;
  1769. { open array? }
  1770. if (td^.ArrayData.Size = 0) and (td^.ArrayData.ElCount = 0) then begin
  1771. data := PPointer(FData.FValueData.GetReferenceToRawData)^;
  1772. elsize := FData.FElSize
  1773. end else begin
  1774. data := FData.FValueData.GetReferenceToRawData;
  1775. elsize := td^.ArrayData.Size div td^.ArrayData.ElCount;
  1776. end;
  1777. data := PByte(data) + AIndex * elsize;
  1778. end;
  1779. { MakeWithoutCopy? }
  1780. Make(data, eltype, Result);
  1781. end;
  1782. procedure TValue.SetArrayElement(AIndex: SizeInt; constref AValue: TValue);
  1783. var
  1784. data: Pointer;
  1785. eltype: PTypeInfo;
  1786. elsize: SizeInt;
  1787. td, tdv: PTypeData;
  1788. begin
  1789. if not IsArray then
  1790. raise EInvalidCast.Create(SErrInvalidTypecast);
  1791. if Kind = tkDynArray then begin
  1792. data := DynArrayIndex(PPointer(FData.FValueData.GetReferenceToRawData)^, [AIndex], FData.FTypeInfo);
  1793. eltype := TypeData^.elType2;
  1794. end else begin
  1795. td := TypeData;
  1796. eltype := td^.ArrayData.ElType;
  1797. { open array? }
  1798. if (td^.ArrayData.Size = 0) and (td^.ArrayData.ElCount = 0) then begin
  1799. data := PPointer(FData.FValueData.GetReferenceToRawData)^;
  1800. elsize := FData.FElSize
  1801. end else begin
  1802. data := FData.FValueData.GetReferenceToRawData;
  1803. elsize := td^.ArrayData.Size div td^.ArrayData.ElCount;
  1804. end;
  1805. data := PByte(data) + AIndex * elsize;
  1806. end;
  1807. { maybe we'll later on allow some typecasts, but for now be restrictive }
  1808. if eltype^.Kind <> AValue.Kind then
  1809. raise EInvalidCast.Create(SErrInvalidTypecast);
  1810. td := GetTypeData(eltype);
  1811. tdv := AValue.TypeData;
  1812. if ((eltype^.Kind in [tkInteger, tkBool, tkEnumeration, tkSet]) and (td^.OrdType <> tdv^.OrdType)) or
  1813. ((eltype^.Kind = tkFloat) and (td^.FloatType <> tdv^.FloatType)) then
  1814. raise EInvalidCast.Create(SErrInvalidTypecast);
  1815. if Assigned(AValue.FData.FValueData) and (eltype^.Kind <> tkSString) then
  1816. IntCopy(AValue.FData.FValueData.GetReferenceToRawData, data, eltype)
  1817. else
  1818. Move(AValue.GetReferenceToRawData^, data^, AValue.DataSize);
  1819. end;
  1820. function TValue.TryAsOrdinal(out AResult: int64): boolean;
  1821. begin
  1822. result := IsOrdinal;
  1823. if result then
  1824. AResult := AsOrdinal;
  1825. end;
  1826. function TValue.GetReferenceToRawData: Pointer;
  1827. begin
  1828. if not Assigned(FData.FTypeInfo) then
  1829. Result := Nil
  1830. else if Assigned(FData.FValueData) then
  1831. Result := FData.FValueData.GetReferenceToRawData
  1832. else begin
  1833. Result := Nil;
  1834. case Kind of
  1835. tkInteger,
  1836. tkEnumeration,
  1837. tkInt64,
  1838. tkQWord,
  1839. tkBool:
  1840. case TypeData^.OrdType of
  1841. otSByte:
  1842. Result := @FData.FAsSByte;
  1843. otUByte:
  1844. Result := @FData.FAsUByte;
  1845. otSWord:
  1846. Result := @FData.FAsSWord;
  1847. otUWord:
  1848. Result := @FData.FAsUWord;
  1849. otSLong:
  1850. Result := @FData.FAsSLong;
  1851. otULong:
  1852. Result := @FData.FAsULong;
  1853. otSQWord:
  1854. Result := @FData.FAsSInt64;
  1855. otUQWord:
  1856. Result := @FData.FAsUInt64;
  1857. end;
  1858. tkSet: begin
  1859. case TypeData^.OrdType of
  1860. otUByte: begin
  1861. case TypeData^.SetSize of
  1862. 1:
  1863. Result := @FData.FAsUByte;
  1864. 2:
  1865. Result := @FData.FAsUWord;
  1866. 3, 4:
  1867. Result := @FData.FAsULong;
  1868. 5..8:
  1869. Result := @FData.FAsUInt64;
  1870. else
  1871. { this should have gone through FAsValueData :/ }
  1872. Result := Nil;
  1873. end;
  1874. end;
  1875. otUWord:
  1876. Result := @FData.FAsUWord;
  1877. otULong:
  1878. Result := @FData.FAsULong;
  1879. else
  1880. Result := Nil;
  1881. end;
  1882. end;
  1883. tkChar:
  1884. Result := @FData.FAsUByte;
  1885. tkFloat:
  1886. case TypeData^.FloatType of
  1887. ftSingle:
  1888. Result := @FData.FAsSingle;
  1889. ftDouble:
  1890. Result := @FData.FAsDouble;
  1891. ftExtended:
  1892. Result := @FData.FAsExtended;
  1893. ftComp:
  1894. Result := @FData.FAsComp;
  1895. ftCurr:
  1896. Result := @FData.FAsCurr;
  1897. end;
  1898. tkMethod:
  1899. Result := @FData.FAsMethod;
  1900. tkClass:
  1901. Result := @FData.FAsObject;
  1902. tkWChar:
  1903. Result := @FData.FAsUWord;
  1904. tkInterfaceRaw:
  1905. Result := @FData.FAsPointer;
  1906. tkProcVar:
  1907. Result := @FData.FAsMethod.Code;
  1908. tkUChar:
  1909. Result := @FData.FAsUWord;
  1910. tkFile:
  1911. Result := @FData.FAsPointer;
  1912. tkClassRef:
  1913. Result := @FData.FAsClass;
  1914. tkPointer:
  1915. Result := @FData.FAsPointer;
  1916. tkVariant,
  1917. tkDynArray,
  1918. tkArray,
  1919. tkObject,
  1920. tkRecord,
  1921. tkInterface,
  1922. tkSString,
  1923. tkLString,
  1924. tkAString,
  1925. tkUString,
  1926. tkWString:
  1927. Assert(false, 'Managed/complex type not handled through IValueData');
  1928. end;
  1929. end;
  1930. end;
  1931. procedure TValue.ExtractRawData(ABuffer: Pointer);
  1932. begin
  1933. if Assigned(FData.FValueData) then
  1934. FData.FValueData.ExtractRawData(ABuffer)
  1935. else if Assigned(FData.FTypeInfo) then
  1936. Move((@FData.FAsPointer)^, ABuffer^, DataSize);
  1937. end;
  1938. procedure TValue.ExtractRawDataNoCopy(ABuffer: Pointer);
  1939. begin
  1940. if Assigned(FData.FValueData) then
  1941. FData.FValueData.ExtractRawDataNoCopy(ABuffer)
  1942. else if Assigned(FData.FTypeInfo) then
  1943. Move((@FData.FAsPointer)^, ABuffer^, DataSize);
  1944. end;
  1945. class operator TValue.:=(const AValue: String): TValue;
  1946. begin
  1947. Make(@AValue, System.TypeInfo(AValue), Result);
  1948. end;
  1949. class operator TValue.:=(AValue: LongInt): TValue;
  1950. begin
  1951. Make(@AValue, System.TypeInfo(AValue), Result);
  1952. end;
  1953. class operator TValue.:=(AValue: Single): TValue;
  1954. begin
  1955. Make(@AValue, System.TypeInfo(AValue), Result);
  1956. end;
  1957. class operator TValue.:=(AValue: Double): TValue;
  1958. begin
  1959. Make(@AValue, System.TypeInfo(AValue), Result);
  1960. end;
  1961. {$ifdef FPC_HAS_TYPE_EXTENDED}
  1962. class operator TValue.:=(AValue: Extended): TValue;
  1963. begin
  1964. Make(@AValue, System.TypeInfo(AValue), Result);
  1965. end;
  1966. {$endif}
  1967. class operator TValue.:=(AValue: Currency): TValue;
  1968. begin
  1969. Make(@AValue, System.TypeInfo(AValue), Result);
  1970. end;
  1971. class operator TValue.:=(AValue: Int64): TValue;
  1972. begin
  1973. Make(@AValue, System.TypeInfo(AValue), Result);
  1974. end;
  1975. class operator TValue.:=(AValue: QWord): TValue;
  1976. begin
  1977. Make(@AValue, System.TypeInfo(AValue), Result);
  1978. end;
  1979. class operator TValue.:=(AValue: TObject): TValue;
  1980. begin
  1981. Make(@AValue, System.TypeInfo(AValue), Result);
  1982. end;
  1983. class operator TValue.:=(AValue: TClass): TValue;
  1984. begin
  1985. Make(@AValue, System.TypeInfo(AValue), Result);
  1986. end;
  1987. class operator TValue.:=(AValue: Boolean): TValue;
  1988. begin
  1989. Make(@AValue, System.TypeInfo(AValue), Result);
  1990. end;
  1991. function Invoke(aCodeAddress: CodePointer; const aArgs: TValueArray;
  1992. aCallConv: TCallConv; aResultType: PTypeInfo; aIsStatic: Boolean;
  1993. aIsConstructor: Boolean): TValue;
  1994. var
  1995. funcargs: TFunctionCallParameterArray;
  1996. i: LongInt;
  1997. flags: TFunctionCallFlags;
  1998. begin
  1999. { sanity check }
  2000. if not Assigned(FuncCallMgr[aCallConv].Invoke) then
  2001. raise ENotImplemented.Create(SErrInvokeNotImplemented);
  2002. { ToDo: handle IsConstructor }
  2003. if aIsConstructor then
  2004. raise ENotImplemented.Create(SErrInvokeNotImplemented);
  2005. flags := [];
  2006. if aIsStatic then
  2007. Include(flags, fcfStatic)
  2008. else if Length(aArgs) = 0 then
  2009. raise EInvocationError.Create(SErrMissingSelfParam);
  2010. SetLength(funcargs, Length(aArgs));
  2011. for i := Low(aArgs) to High(aArgs) do begin
  2012. funcargs[i - Low(aArgs) + Low(funcargs)].ValueRef := aArgs[i].GetReferenceToRawData;
  2013. funcargs[i - Low(aArgs) + Low(funcargs)].ValueSize := aArgs[i].DataSize;
  2014. funcargs[i - Low(aArgs) + Low(funcargs)].Info.ParamType := aArgs[i].TypeInfo;
  2015. funcargs[i - Low(aArgs) + Low(funcargs)].Info.ParamFlags := [];
  2016. funcargs[i - Low(aArgs) + Low(funcargs)].Info.ParaLocs := Nil;
  2017. end;
  2018. if Assigned(aResultType) then
  2019. TValue.Make(Nil, aResultType, Result)
  2020. else
  2021. Result := TValue.Empty;
  2022. FuncCallMgr[aCallConv].Invoke(aCodeAddress, funcargs, aCallConv, aResultType, Result.GetReferenceToRawData, flags);
  2023. end;
  2024. function Invoke(const aName: String; aCodeAddress: CodePointer; aCallConv: TCallConv; aStatic: Boolean; aInstance: TValue; constref aArgs: array of TValue; const aParams: specialize TArray<TRttiParameter>; aReturnType: TRttiType): TValue;
  2025. var
  2026. arrparam, param: TRttiParameter;
  2027. unhidden, highs, i: SizeInt;
  2028. args: TFunctionCallParameterArray;
  2029. highargs: array of SizeInt;
  2030. restype: PTypeInfo;
  2031. resptr: Pointer;
  2032. mgr: TFunctionCallManager;
  2033. flags: TFunctionCallFlags;
  2034. begin
  2035. mgr := FuncCallMgr[aCallConv];
  2036. if not Assigned(mgr.Invoke) then
  2037. raise EInvocationError.CreateFmt(SErrCallConvNotSupported, [CCToStr(aCallConv)]);
  2038. if not Assigned(aCodeAddress) then
  2039. raise EInvocationError.CreateFmt(SErrInvokeNoCodeAddr, [aName]);
  2040. unhidden := 0;
  2041. highs := 0;
  2042. for param in aParams do begin
  2043. if unhidden < Length(aArgs) then begin
  2044. if pfArray in param.Flags then begin
  2045. if Assigned(aArgs[unhidden].TypeInfo) and not aArgs[unhidden].IsArray and (aArgs[unhidden].Kind <> param.ParamType.TypeKind) then
  2046. raise EInvocationError.CreateFmt(SErrInvokeArrayArgExpected, [param.Name, aName]);
  2047. end else if not (pfHidden in param.Flags) then begin
  2048. if Assigned(param.ParamType) and (aArgs[unhidden].Kind <> param.ParamType.TypeKind) then
  2049. raise EInvocationError.CreateFmt(SErrInvokeArgInvalidType, [param.Name, aName]);
  2050. end;
  2051. end;
  2052. if not (pfHidden in param.Flags) then
  2053. Inc(unhidden);
  2054. if pfHigh in param.Flags then
  2055. Inc(highs);
  2056. end;
  2057. if unhidden <> Length(aArgs) then
  2058. raise EInvocationError.CreateFmt(SErrInvokeArgCount, [aName, unhidden, Length(aArgs)]);
  2059. if Assigned(aReturnType) then begin
  2060. TValue.Make(Nil, aReturnType.FTypeInfo, Result);
  2061. resptr := Result.GetReferenceToRawData;
  2062. restype := aReturnType.FTypeInfo;
  2063. end else begin
  2064. Result := TValue.Empty;
  2065. resptr := Nil;
  2066. restype := Nil;
  2067. end;
  2068. SetLength(highargs, highs);
  2069. SetLength(args, Length(aParams));
  2070. unhidden := 0;
  2071. highs := 0;
  2072. for i := 0 to High(aParams) do begin
  2073. param := aParams[i];
  2074. if Assigned(param.ParamType) then
  2075. args[i].Info.ParamType := param.ParamType.FTypeInfo
  2076. else
  2077. args[i].Info.ParamType := Nil;
  2078. args[i].Info.ParamFlags := param.Flags;
  2079. args[i].Info.ParaLocs := Nil;
  2080. if pfHidden in param.Flags then begin
  2081. if pfSelf in param.Flags then
  2082. args[i].ValueRef := aInstance.GetReferenceToRawData
  2083. else if pfResult in param.Flags then begin
  2084. if not Assigned(restype) then
  2085. raise EInvocationError.CreateFmt(SErrInvokeRttiDataError, [aName]);
  2086. args[i].ValueRef := resptr;
  2087. restype := Nil;
  2088. resptr := Nil;
  2089. end else if pfHigh in param.Flags then begin
  2090. { the corresponding array argument is the *previous* unhidden argument }
  2091. if aArgs[unhidden - 1].IsArray then
  2092. highargs[highs] := aArgs[unhidden - 1].GetArrayLength - 1
  2093. else if not Assigned(aArgs[unhidden - 1].TypeInfo) then
  2094. highargs[highs] := -1
  2095. else
  2096. highargs[highs] := 0;
  2097. args[i].ValueRef := @highargs[highs];
  2098. Inc(highs);
  2099. end;
  2100. end else begin
  2101. if (pfArray in param.Flags) then begin
  2102. if not Assigned(aArgs[unhidden].TypeInfo) then
  2103. args[i].ValueRef := Nil
  2104. else if aArgs[unhidden].Kind = tkDynArray then
  2105. args[i].ValueRef := PPointer(aArgs[unhidden].GetReferenceToRawData)^
  2106. else
  2107. args[i].ValueRef := aArgs[unhidden].GetReferenceToRawData;
  2108. end else
  2109. args[i].ValueRef := aArgs[unhidden].GetReferenceToRawData;
  2110. Inc(unhidden);
  2111. end;
  2112. end;
  2113. flags := [];
  2114. if aStatic then
  2115. Include(flags, fcfStatic);
  2116. mgr.Invoke(aCodeAddress, args, aCallConv, restype, resptr, flags);
  2117. end;
  2118. function CreateCallbackProc(aHandler: TFunctionCallProc; aCallConv: TCallConv; aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags; aContext: Pointer): TFunctionCallCallback;
  2119. begin
  2120. if not Assigned(FuncCallMgr[aCallConv].CreateCallbackProc) then
  2121. raise ENotImplemented.Create(SErrCallbackNotImplemented);
  2122. if not Assigned(aHandler) then
  2123. raise EArgumentNilException.Create(SErrCallbackHandlerNil);
  2124. Result := FuncCallMgr[aCallConv].CreateCallbackProc(aHandler, aCallConv, aArgs, aResultType, aFlags, aContext);
  2125. end;
  2126. function CreateCallbackMethod(aHandler: TFunctionCallMethod; aCallConv: TCallConv; aArgs: array of TFunctionCallParameterInfo; aResultType: PTypeInfo; aFlags: TFunctionCallFlags; aContext: Pointer): TFunctionCallCallback;
  2127. begin
  2128. if not Assigned(FuncCallMgr[aCallConv].CreateCallbackMethod) then
  2129. raise ENotImplemented.Create(SErrCallbackNotImplemented);
  2130. if not Assigned(aHandler) then
  2131. raise EArgumentNilException.Create(SErrCallbackHandlerNil);
  2132. Result := FuncCallMgr[aCallConv].CreateCallbackMethod(aHandler, aCallConv, aArgs, aResultType, aFlags, aContext);
  2133. end;
  2134. function IsManaged(TypeInfo: PTypeInfo): boolean;
  2135. begin
  2136. if Assigned(TypeInfo) then
  2137. case TypeInfo^.Kind of
  2138. tkAString,
  2139. tkLString,
  2140. tkWString,
  2141. tkUString,
  2142. tkInterface,
  2143. tkVariant,
  2144. tkDynArray : Result := true;
  2145. tkArray : Result := IsManaged(GetTypeData(TypeInfo)^.ArrayData.ElType);
  2146. tkRecord,
  2147. tkObject :
  2148. with GetTypeData(TypeInfo)^.RecInitData^ do
  2149. Result := (ManagedFieldCount > 0) or Assigned(ManagementOp);
  2150. else
  2151. Result := false;
  2152. end
  2153. else
  2154. Result := false;
  2155. end;
  2156. {$ifndef InLazIDE}
  2157. generic function OpenArrayToDynArrayValue<T>(constref aArray: array of T): TValue;
  2158. var
  2159. arr: specialize TArray<T>;
  2160. i: SizeInt;
  2161. begin
  2162. SetLength(arr, Length(aArray));
  2163. for i := 0 to High(aArray) do
  2164. arr[i] := aArray[i];
  2165. Result := TValue.specialize From<specialize TArray<T>>(arr);
  2166. end;
  2167. {$endif}
  2168. { TRttiPointerType }
  2169. function TRttiPointerType.GetReferredType: TRttiType;
  2170. begin
  2171. Result := GRttiPool.GetType(FTypeData^.RefType);
  2172. end;
  2173. { TRttiRefCountedInterfaceType }
  2174. function TRttiRefCountedInterfaceType.IntfData: PInterfaceData;
  2175. begin
  2176. Result := PInterfaceData(FTypeData);
  2177. end;
  2178. function TRttiRefCountedInterfaceType.MethodTable: PIntfMethodTable;
  2179. begin
  2180. Result := IntfData^.MethodTable;
  2181. end;
  2182. function TRttiRefCountedInterfaceType.GetIntfBaseType: TRttiInterfaceType;
  2183. var
  2184. context: TRttiContext;
  2185. begin
  2186. if not Assigned(IntfData^.Parent) then
  2187. Exit(Nil);
  2188. context := TRttiContext.Create;
  2189. try
  2190. Result := context.GetType(IntfData^.Parent^) as TRttiInterfaceType;
  2191. finally
  2192. context.Free;
  2193. end;
  2194. end;
  2195. function TRttiRefCountedInterfaceType.GetDeclaringUnitName: String;
  2196. begin
  2197. Result := IntfData^.UnitName;
  2198. end;
  2199. function TRttiRefCountedInterfaceType.GetGUID: TGUID;
  2200. begin
  2201. Result := IntfData^.GUID;
  2202. end;
  2203. function TRttiRefCountedInterfaceType.GetIntfFlags: TIntfFlags;
  2204. begin
  2205. Result := IntfData^.Flags;
  2206. end;
  2207. function TRttiRefCountedInterfaceType.GetIntfType: TInterfaceType;
  2208. begin
  2209. Result := itRefCounted;
  2210. end;
  2211. { TRttiRawInterfaceType }
  2212. function TRttiRawInterfaceType.IntfData: PInterfaceRawData;
  2213. begin
  2214. Result := PInterfaceRawData(FTypeData);
  2215. end;
  2216. function TRttiRawInterfaceType.MethodTable: PIntfMethodTable;
  2217. begin
  2218. { currently there is none! }
  2219. Result := Nil;
  2220. end;
  2221. function TRttiRawInterfaceType.GetIntfBaseType: TRttiInterfaceType;
  2222. var
  2223. context: TRttiContext;
  2224. begin
  2225. if not Assigned(IntfData^.Parent) then
  2226. Exit(Nil);
  2227. context := TRttiContext.Create;
  2228. try
  2229. Result := context.GetType(IntfData^.Parent^) as TRttiInterfaceType;
  2230. finally
  2231. context.Free;
  2232. end;
  2233. end;
  2234. function TRttiRawInterfaceType.GetDeclaringUnitName: String;
  2235. begin
  2236. Result := IntfData^.UnitName;
  2237. end;
  2238. function TRttiRawInterfaceType.GetGUID: TGUID;
  2239. begin
  2240. Result := IntfData^.IID;
  2241. end;
  2242. function TRttiRawInterfaceType.GetGUIDStr: String;
  2243. begin
  2244. Result := IntfData^.IIDStr;
  2245. end;
  2246. function TRttiRawInterfaceType.GetIntfFlags: TIntfFlags;
  2247. begin
  2248. Result := IntfData^.Flags;
  2249. end;
  2250. function TRttiRawInterfaceType.GetIntfType: TInterfaceType;
  2251. begin
  2252. Result := itRaw;
  2253. end;
  2254. { TRttiVmtMethodParameter }
  2255. function TRttiVmtMethodParameter.GetHandle: Pointer;
  2256. begin
  2257. Result := FVmtMethodParam;
  2258. end;
  2259. function TRttiVmtMethodParameter.GetName: String;
  2260. begin
  2261. Result := FVmtMethodParam^.Name;
  2262. end;
  2263. function TRttiVmtMethodParameter.GetFlags: TParamFlags;
  2264. begin
  2265. Result := FVmtMethodParam^.Flags;
  2266. end;
  2267. function TRttiVmtMethodParameter.GetParamType: TRttiType;
  2268. var
  2269. context: TRttiContext;
  2270. begin
  2271. if not Assigned(FVmtMethodParam^.ParamType) then
  2272. Exit(Nil);
  2273. context := TRttiContext.Create;
  2274. try
  2275. Result := context.GetType(FVmtMethodParam^.ParamType^);
  2276. finally
  2277. context.Free;
  2278. end;
  2279. end;
  2280. constructor TRttiVmtMethodParameter.Create(AVmtMethodParam: PVmtMethodParam);
  2281. begin
  2282. inherited Create;
  2283. FVmtMethodParam := AVmtMethodParam;
  2284. end;
  2285. { TRttiMethodTypeParameter }
  2286. function TRttiMethodTypeParameter.GetHandle: Pointer;
  2287. begin
  2288. Result := fHandle;
  2289. end;
  2290. function TRttiMethodTypeParameter.GetName: String;
  2291. begin
  2292. Result := fName;
  2293. end;
  2294. function TRttiMethodTypeParameter.GetFlags: TParamFlags;
  2295. begin
  2296. Result := fFlags;
  2297. end;
  2298. function TRttiMethodTypeParameter.GetParamType: TRttiType;
  2299. var
  2300. context: TRttiContext;
  2301. begin
  2302. context := TRttiContext.Create;
  2303. try
  2304. Result := context.GetType(FType);
  2305. finally
  2306. context.Free;
  2307. end;
  2308. end;
  2309. constructor TRttiMethodTypeParameter.Create(aHandle: Pointer; const aName: String; aFlags: TParamFlags; aType: PTypeInfo);
  2310. begin
  2311. fHandle := aHandle;
  2312. fName := aName;
  2313. fFlags := aFlags;
  2314. fType := aType;
  2315. end;
  2316. { TRttiIntfMethod }
  2317. function TRttiIntfMethod.GetHandle: Pointer;
  2318. begin
  2319. Result := FIntfMethodEntry;
  2320. end;
  2321. function TRttiIntfMethod.GetName: String;
  2322. begin
  2323. Result := FIntfMethodEntry^.Name;
  2324. end;
  2325. function TRttiIntfMethod.GetCallingConvention: TCallConv;
  2326. begin
  2327. Result := FIntfMethodEntry^.CC;
  2328. end;
  2329. function TRttiIntfMethod.GetCodeAddress: CodePointer;
  2330. begin
  2331. Result := Nil;
  2332. end;
  2333. function TRttiIntfMethod.GetDispatchKind: TDispatchKind;
  2334. begin
  2335. Result := dkInterface;
  2336. end;
  2337. function TRttiIntfMethod.GetHasExtendedInfo: Boolean;
  2338. begin
  2339. Result := True;
  2340. end;
  2341. function TRttiIntfMethod.GetIsClassMethod: Boolean;
  2342. begin
  2343. Result := False;
  2344. end;
  2345. function TRttiIntfMethod.GetIsConstructor: Boolean;
  2346. begin
  2347. Result := False;
  2348. end;
  2349. function TRttiIntfMethod.GetIsDestructor: Boolean;
  2350. begin
  2351. Result := False;
  2352. end;
  2353. function TRttiIntfMethod.GetIsStatic: Boolean;
  2354. begin
  2355. Result := False;
  2356. end;
  2357. function TRttiIntfMethod.GetMethodKind: TMethodKind;
  2358. begin
  2359. Result := FIntfMethodEntry^.Kind;
  2360. end;
  2361. function TRttiIntfMethod.GetReturnType: TRttiType;
  2362. var
  2363. context: TRttiContext;
  2364. begin
  2365. if not Assigned(FIntfMethodEntry^.ResultType) then
  2366. Exit(Nil);
  2367. context := TRttiContext.Create;
  2368. try
  2369. Result := context.GetType(FIntfMethodEntry^.ResultType^);
  2370. finally
  2371. context.Free;
  2372. end;
  2373. end;
  2374. function TRttiIntfMethod.GetVirtualIndex: SmallInt;
  2375. begin
  2376. Result := FIndex;
  2377. end;
  2378. constructor TRttiIntfMethod.Create(AParent: TRttiType; AIntfMethodEntry: PIntfMethodEntry; AIndex: SmallInt);
  2379. begin
  2380. inherited Create(AParent);
  2381. FIntfMethodEntry := AIntfMethodEntry;
  2382. FIndex := AIndex;
  2383. end;
  2384. function TRttiIntfMethod.GetParameters(aWithHidden: Boolean): specialize TArray<TRttiParameter>;
  2385. var
  2386. param: PVmtMethodParam;
  2387. total, visible: SizeInt;
  2388. context: TRttiContext;
  2389. obj: TRttiObject;
  2390. begin
  2391. if aWithHidden and (Length(FParamsAll) > 0) then
  2392. Exit(FParamsAll);
  2393. if not aWithHidden and (Length(FParams) > 0) then
  2394. Exit(FParams);
  2395. if FIntfMethodEntry^.ParamCount = 0 then
  2396. Exit(Nil);
  2397. SetLength(FParams, FIntfMethodEntry^.ParamCount);
  2398. SetLength(FParamsAll, FIntfMethodEntry^.ParamCount);
  2399. context := TRttiContext.Create;
  2400. try
  2401. total := 0;
  2402. visible := 0;
  2403. param := FIntfMethodEntry^.Param[0];
  2404. while total < FIntfMethodEntry^.ParamCount do begin
  2405. obj := context.GetByHandle(param);
  2406. if Assigned(obj) then
  2407. FParamsAll[total] := obj as TRttiVmtMethodParameter
  2408. else begin
  2409. FParamsAll[total] := TRttiVmtMethodParameter.Create(param);
  2410. context.AddObject(FParamsAll[total]);
  2411. end;
  2412. if not (pfHidden in param^.Flags) then begin
  2413. FParams[visible] := FParamsAll[total];
  2414. Inc(visible);
  2415. end;
  2416. param := param^.Next;
  2417. Inc(total);
  2418. end;
  2419. if visible <> total then
  2420. SetLength(FParams, visible);
  2421. finally
  2422. context.Free;
  2423. end;
  2424. if aWithHidden then
  2425. Result := FParamsAll
  2426. else
  2427. Result := FParams;
  2428. end;
  2429. { TRttiInt64Type }
  2430. function TRttiInt64Type.GetMaxValue: Int64;
  2431. begin
  2432. Result := FTypeData^.MaxInt64Value;
  2433. end;
  2434. function TRttiInt64Type.GetMinValue: Int64;
  2435. begin
  2436. Result := FTypeData^.MinInt64Value;
  2437. end;
  2438. function TRttiInt64Type.GetUnsigned: Boolean;
  2439. begin
  2440. Result := FTypeData^.OrdType = otUQWord;
  2441. end;
  2442. function TRttiInt64Type.GetTypeSize: integer;
  2443. begin
  2444. Result := SizeOf(QWord);
  2445. end;
  2446. { TRttiOrdinalType }
  2447. function TRttiOrdinalType.GetMaxValue: LongInt;
  2448. begin
  2449. Result := FTypeData^.MaxValue;
  2450. end;
  2451. function TRttiOrdinalType.GetMinValue: LongInt;
  2452. begin
  2453. Result := FTypeData^.MinValue;
  2454. end;
  2455. function TRttiOrdinalType.GetOrdType: TOrdType;
  2456. begin
  2457. Result := FTypeData^.OrdType;
  2458. end;
  2459. function TRttiOrdinalType.GetTypeSize: Integer;
  2460. begin
  2461. case OrdType of
  2462. otSByte,
  2463. otUByte:
  2464. Result := SizeOf(Byte);
  2465. otSWord,
  2466. otUWord:
  2467. Result := SizeOf(Word);
  2468. otSLong,
  2469. otULong:
  2470. Result := SizeOf(LongWord);
  2471. otSQWord,
  2472. otUQWord:
  2473. Result := SizeOf(QWord);
  2474. end;
  2475. end;
  2476. { TRttiFloatType }
  2477. function TRttiFloatType.GetFloatType: TFloatType;
  2478. begin
  2479. result := FTypeData^.FloatType;
  2480. end;
  2481. function TRttiFloatType.GetTypeSize: integer;
  2482. begin
  2483. case FloatType of
  2484. ftSingle:
  2485. Result := SizeOf(Single);
  2486. ftDouble:
  2487. Result := SizeOf(Double);
  2488. ftExtended:
  2489. Result := SizeOf(Extended);
  2490. ftComp:
  2491. Result := SizeOf(Comp);
  2492. ftCurr:
  2493. Result := SizeOf(Currency);
  2494. end;
  2495. end;
  2496. { TRttiParameter }
  2497. function TRttiParameter.ToString: String;
  2498. var
  2499. f: TParamFlags;
  2500. n: String;
  2501. t: TRttiType;
  2502. begin
  2503. if FString = '' then begin
  2504. f := Flags;
  2505. if pfVar in f then
  2506. FString := 'var'
  2507. else if pfConst in f then
  2508. FString := 'const'
  2509. else if pfOut in f then
  2510. FString := 'out'
  2511. else if pfConstRef in f then
  2512. FString := 'constref';
  2513. if FString <> '' then
  2514. FString := FString + ' ';
  2515. n := Name;
  2516. if n = '' then
  2517. n := '<unknown>';
  2518. FString := FString + n;
  2519. t := ParamType;
  2520. if Assigned(t) then begin
  2521. FString := FString + ': ';
  2522. if pfArray in flags then
  2523. FString := 'array of ';
  2524. FString := FString + t.Name;
  2525. end;
  2526. end;
  2527. Result := FString;
  2528. end;
  2529. { TMethodImplementation }
  2530. function TMethodImplementation.GetCodeAddress: CodePointer;
  2531. begin
  2532. Result := fLowLevelCallback.CodeAddress;
  2533. end;
  2534. procedure TMethodImplementation.InitArgs;
  2535. var
  2536. i, refargs: SizeInt;
  2537. begin
  2538. i := 0;
  2539. refargs := 0;
  2540. SetLength(fRefArgs, Length(fArgs));
  2541. while i < Length(fArgs) do begin
  2542. if (fArgs[i].ParamFlags * [pfVar, pfOut] <> []) and not (pfHidden in fArgs[i].ParamFlags) then begin
  2543. fRefArgs[refargs] := fArgLen;
  2544. Inc(refargs);
  2545. end;
  2546. if pfArray in fArgs[i].ParamFlags then begin
  2547. Inc(i);
  2548. if (i = Length(fArgs)) or not (pfHigh in fArgs[i].ParamFlags) then
  2549. raise EInsufficientRtti.Create(SErrMethodImplCreateFailed);
  2550. Inc(fArgLen);
  2551. end else if not (pfHidden in fArgs[i].ParamFlags) or (pfSelf in fArgs[i].ParamFlags) then
  2552. Inc(fArgLen)
  2553. else if (pfResult in fArgs[i].ParamFlags) then
  2554. fResult := fArgs[i].ParamType;
  2555. Inc(i);
  2556. end;
  2557. SetLength(fRefArgs, refargs);
  2558. end;
  2559. procedure TMethodImplementation.HandleCallback(const aArgs: specialize TArray<Pointer>; aResult: Pointer; aContext: Pointer);
  2560. var
  2561. i, argidx: SizeInt;
  2562. args: TValueArray;
  2563. res: TValue;
  2564. begin
  2565. Assert(fArgLen = Length(aArgs), 'Length of arguments does not match');
  2566. SetLength(args, fArgLen);
  2567. argidx := 0;
  2568. i := 0;
  2569. while i < Length(fArgs) do begin
  2570. if pfArray in fArgs[i].ParamFlags then begin
  2571. Inc(i);
  2572. Assert((i < Length(fArgs)) and (pfHigh in fArgs[i].ParamFlags), 'Expected high parameter after open array parameter');
  2573. TValue.MakeOpenArray(aArgs[i - 1], SizeInt(aArgs[i]), fArgs[i].ParamType, args[argidx]);
  2574. end else if not (pfHidden in fArgs[i].ParamFlags) or (pfSelf in fArgs[i].ParamFlags) then begin
  2575. if Assigned(fArgs[i].ParamType) then
  2576. TValue.Make(aArgs[i], fArgs[i].ParamType, args[argidx])
  2577. else
  2578. TValue.Make(@aArgs[i], TypeInfo(Pointer), args[argidx]);
  2579. end;
  2580. Inc(i);
  2581. Inc(argidx);
  2582. end;
  2583. if Assigned(fCallbackMethod) then
  2584. fCallbackMethod(aContext, args, res)
  2585. else
  2586. fCallbackProc(aContext, args, res);
  2587. { copy back var/out parameters }
  2588. for i := 0 to High(fRefArgs) do begin
  2589. args[fRefArgs[i]].ExtractRawData(aArgs[fRefArgs[i]]);
  2590. end;
  2591. if Assigned(fResult) then
  2592. res.ExtractRawData(aResult);
  2593. end;
  2594. constructor TMethodImplementation.Create(aCC: TCallConv; aArgs: specialize TArray<TFunctionCallParameterInfo>; aResult: PTypeInfo; aFlags: TFunctionCallFlags; aUserData: Pointer; aCallback: TMethodImplementationCallbackMethod);
  2595. begin
  2596. fCC := aCC;
  2597. fArgs := aArgs;
  2598. fResult := aResult;
  2599. fFlags := aFlags;
  2600. fCallbackMethod := aCallback;
  2601. InitArgs;
  2602. fLowLevelCallback := CreateCallbackMethod(@HandleCallback, fCC, aArgs, aResult, aFlags, aUserData);
  2603. if not Assigned(fLowLevelCallback) then
  2604. raise EInsufficientRtti.Create(SErrMethodImplCreateFailed);
  2605. end;
  2606. constructor TMethodImplementation.Create(aCC: TCallConv; aArgs: specialize TArray<TFunctionCallParameterInfo>; aResult: PTypeInfo; aFlags: TFunctionCallFlags; aUserData: Pointer; aCallback: TMethodImplementationCallbackProc);
  2607. begin
  2608. fCC := aCC;
  2609. fArgs := aArgs;
  2610. fResult := aResult;
  2611. fFlags := aFlags;
  2612. fCallbackProc := aCallback;
  2613. InitArgs;
  2614. fLowLevelCallback := CreateCallbackMethod(@HandleCallback, fCC, aArgs, aResult, aFlags, aUserData);
  2615. if not Assigned(fLowLevelCallback) then
  2616. raise EInsufficientRtti.Create(SErrMethodImplCreateFailed);
  2617. end;
  2618. constructor TMethodImplementation.Create;
  2619. begin
  2620. raise EInvalidOpException.Create(SErrMethodImplCreateNoArg);
  2621. end;
  2622. destructor TMethodImplementation.Destroy;
  2623. begin
  2624. fLowLevelCallback.Free;
  2625. inherited Destroy;
  2626. end;
  2627. { TRttiMethod }
  2628. function TRttiMethod.GetHasExtendedInfo: Boolean;
  2629. begin
  2630. Result := False;
  2631. end;
  2632. function TRttiMethod.GetFlags: TFunctionCallFlags;
  2633. begin
  2634. Result := [];
  2635. if IsStatic then
  2636. Include(Result, fcfStatic);
  2637. end;
  2638. function TRttiMethod.GetParameters: specialize TArray<TRttiParameter>;
  2639. begin
  2640. Result := GetParameters(False);
  2641. end;
  2642. function TRttiMethod.ToString: String;
  2643. var
  2644. ret: TRttiType;
  2645. n: String;
  2646. params: specialize TArray<TRttiParameter>;
  2647. i: LongInt;
  2648. begin
  2649. if FString = '' then begin
  2650. n := Name;
  2651. if n = '' then
  2652. n := '<unknown>';
  2653. if not HasExtendedInfo then begin
  2654. FString := 'method ' + n;
  2655. end else begin
  2656. ret := ReturnType;
  2657. if IsClassMethod then
  2658. FString := 'class ';
  2659. if IsConstructor then
  2660. FString := FString + 'constructor'
  2661. else if IsDestructor then
  2662. FString := FString + 'destructor'
  2663. else if Assigned(ret) then
  2664. FString := FString + 'function'
  2665. else
  2666. FString := FString + 'procedure';
  2667. FString := FString + ' ' + n;
  2668. params := GetParameters;
  2669. if Length(params) > 0 then begin
  2670. FString := FString + '(';
  2671. for i := 0 to High(params) do begin
  2672. if i > 0 then
  2673. FString := FString + '; ';
  2674. FString := FString + params[i].ToString;
  2675. end;
  2676. FString := FString + ')';
  2677. end;
  2678. if Assigned(ret) then
  2679. FString := FString + ': ' + ret.Name;
  2680. if IsStatic then
  2681. FString := FString + '; static';
  2682. end;
  2683. end;
  2684. Result := FString;
  2685. end;
  2686. function TRttiMethod.Invoke(aInstance: TObject; const aArgs: array of TValue): TValue;
  2687. var
  2688. instance: TValue;
  2689. begin
  2690. TValue.Make(@aInstance, TypeInfo(TObject), instance);
  2691. Result := Invoke(instance, aArgs);
  2692. end;
  2693. function TRttiMethod.Invoke(aInstance: TClass; const aArgs: array of TValue): TValue;
  2694. var
  2695. instance: TValue;
  2696. begin
  2697. TValue.Make(@aInstance, TypeInfo(TClass), instance);
  2698. Result := Invoke(instance, aArgs);
  2699. end;
  2700. function TRttiMethod.Invoke(aInstance: TValue; const aArgs: array of TValue): TValue;
  2701. var
  2702. addr: CodePointer;
  2703. vmt: PCodePointer;
  2704. begin
  2705. if not HasExtendedInfo then
  2706. raise EInvocationError.Create(SErrInvokeInsufficientRtti);
  2707. if IsStatic and not aInstance.IsEmpty then
  2708. raise EInvocationError.CreateFmt(SErrInvokeStaticNoSelf, [Name]);
  2709. if not IsStatic and aInstance.IsEmpty then
  2710. raise EInvocationError.CreateFmt(SErrInvokeNotStaticNeedsSelf, [Name]);
  2711. if not IsStatic and IsClassMethod and not aInstance.IsClass then
  2712. raise EInvocationError.CreateFmt(SErrInvokeClassMethodClassSelf, [Name]);
  2713. addr := Nil;
  2714. if IsStatic then
  2715. addr := CodeAddress
  2716. else begin
  2717. vmt := Nil;
  2718. if aInstance.Kind in [tkInterface, tkInterfaceRaw] then
  2719. vmt := PCodePointer(PPPointer(aInstance.GetReferenceToRawData)^^);
  2720. { ToDo }
  2721. if Assigned(vmt) then
  2722. addr := vmt[VirtualIndex];
  2723. end;
  2724. Result := Rtti.Invoke(Name, addr, CallingConvention, IsStatic, aInstance, aArgs, GetParameters(True), ReturnType);
  2725. end;
  2726. function TRttiMethod.CreateImplementation(aUserData: Pointer; aCallback: TMethodImplementationCallbackMethod): TMethodImplementation;
  2727. var
  2728. params: specialize TArray<TRttiParameter>;
  2729. args: specialize TArray<TFunctionCallParameterInfo>;
  2730. res: PTypeInfo;
  2731. restype: TRttiType;
  2732. resinparam: Boolean;
  2733. i: SizeInt;
  2734. begin
  2735. if not Assigned(aCallback) then
  2736. raise EArgumentNilException.Create(SErrMethodImplNoCallback);
  2737. resinparam := False;
  2738. params := GetParameters(True);
  2739. SetLength(args, Length(params));
  2740. for i := 0 to High(params) do begin
  2741. if Assigned(params[i].ParamType) then
  2742. args[i].ParamType := params[i].ParamType.FTypeInfo
  2743. else
  2744. args[i].ParamType := Nil;
  2745. args[i].ParamFlags := params[i].Flags;
  2746. args[i].ParaLocs := Nil;
  2747. if pfResult in params[i].Flags then
  2748. resinparam := True;
  2749. end;
  2750. restype := GetReturnType;
  2751. if Assigned(restype) and not resinparam then
  2752. res := restype.FTypeInfo
  2753. else
  2754. res := Nil;
  2755. Result := TMethodImplementation.Create(GetCallingConvention, args, res, GetFlags, aUserData, aCallback);
  2756. end;
  2757. function TRttiMethod.CreateImplementation(aUserData: Pointer; aCallback: TMethodImplementationCallbackProc): TMethodImplementation;
  2758. var
  2759. params: specialize TArray<TRttiParameter>;
  2760. args: specialize TArray<TFunctionCallParameterInfo>;
  2761. res: PTypeInfo;
  2762. restype: TRttiType;
  2763. resinparam: Boolean;
  2764. i: SizeInt;
  2765. begin
  2766. if not Assigned(aCallback) then
  2767. raise EArgumentNilException.Create(SErrMethodImplNoCallback);
  2768. resinparam := False;
  2769. params := GetParameters(True);
  2770. SetLength(args, Length(params));
  2771. for i := 0 to High(params) do begin
  2772. if Assigned(params[i].ParamType) then
  2773. args[i].ParamType := params[i].ParamType.FTypeInfo
  2774. else
  2775. args[i].ParamType := Nil;
  2776. args[i].ParamFlags := params[i].Flags;
  2777. args[i].ParaLocs := Nil;
  2778. if pfResult in params[i].Flags then
  2779. resinparam := True;
  2780. end;
  2781. restype := GetReturnType;
  2782. if Assigned(restype) and not resinparam then
  2783. res := restype.FTypeInfo
  2784. else
  2785. res := Nil;
  2786. Result := TMethodImplementation.Create(GetCallingConvention, args, res, GetFlags, aUserData, aCallback);
  2787. end;
  2788. { TRttiInvokableType }
  2789. function TRttiInvokableType.GetParameters: specialize TArray<TRttiParameter>;
  2790. begin
  2791. Result := GetParameters(False);
  2792. end;
  2793. function TRttiInvokableType.CreateImplementation(aCallback: TCallbackMethod): TMethodImplementation;
  2794. var
  2795. params: specialize TArray<TRttiParameter>;
  2796. args: specialize TArray<TFunctionCallParameterInfo>;
  2797. res: PTypeInfo;
  2798. restype: TRttiType;
  2799. resinparam: Boolean;
  2800. i: SizeInt;
  2801. begin
  2802. if not Assigned(aCallback) then
  2803. raise EArgumentNilException.Create(SErrMethodImplNoCallback);
  2804. resinparam := False;
  2805. params := GetParameters(True);
  2806. SetLength(args, Length(params));
  2807. for i := 0 to High(params) do begin
  2808. if Assigned(params[i].ParamType) then
  2809. args[i].ParamType := params[i].ParamType.FTypeInfo
  2810. else
  2811. args[i].ParamType := Nil;
  2812. args[i].ParamFlags := params[i].Flags;
  2813. args[i].ParaLocs := Nil;
  2814. if pfResult in params[i].Flags then
  2815. resinparam := True;
  2816. end;
  2817. restype := GetReturnType;
  2818. if Assigned(restype) and not resinparam then
  2819. res := restype.FTypeInfo
  2820. else
  2821. res := Nil;
  2822. Result := TMethodImplementation.Create(GetCallingConvention, args, res, GetFlags, Self, TMethodImplementationCallbackMethod(aCallback));
  2823. end;
  2824. function TRttiInvokableType.CreateImplementation(aCallback: TCallbackProc): TMethodImplementation;
  2825. var
  2826. params: specialize TArray<TRttiParameter>;
  2827. args: specialize TArray<TFunctionCallParameterInfo>;
  2828. res: PTypeInfo;
  2829. restype: TRttiType;
  2830. resinparam: Boolean;
  2831. i: SizeInt;
  2832. begin
  2833. if not Assigned(aCallback) then
  2834. raise EArgumentNilException.Create(SErrMethodImplNoCallback);
  2835. resinparam := False;
  2836. params := GetParameters(True);
  2837. SetLength(args, Length(params));
  2838. for i := 0 to High(params) do begin
  2839. if Assigned(params[i].ParamType) then
  2840. args[i].ParamType := params[i].ParamType.FTypeInfo
  2841. else
  2842. args[i].ParamType := Nil;
  2843. args[i].ParamFlags := params[i].Flags;
  2844. args[i].ParaLocs := Nil;
  2845. if pfResult in params[i].Flags then
  2846. resinparam := True;
  2847. end;
  2848. restype := GetReturnType;
  2849. if Assigned(restype) and not resinparam then
  2850. res := restype.FTypeInfo
  2851. else
  2852. res := Nil;
  2853. Result := TMethodImplementation.Create(GetCallingConvention, args, res, GetFlags, Self, TMethodImplementationCallbackProc(aCallback));
  2854. end;
  2855. { TRttiMethodType }
  2856. function TRttiMethodType.GetParameters(aWithHidden: Boolean): specialize TArray<TRttiParameter>;
  2857. type
  2858. TParamInfo = record
  2859. Handle: Pointer;
  2860. Flags: TParamFlags;
  2861. Name: String;
  2862. end;
  2863. PParamFlags = ^TParamFlags;
  2864. PCallConv = ^TCallConv;
  2865. PPPTypeInfo = ^PPTypeInfo;
  2866. var
  2867. infos: array of TParamInfo;
  2868. total, visible, i: SizeInt;
  2869. ptr: PByte;
  2870. paramtypes: PPPTypeInfo;
  2871. paramtype: PTypeInfo;
  2872. context: TRttiContext;
  2873. obj: TRttiObject;
  2874. begin
  2875. if aWithHidden and (Length(FParamsAll) > 0) then
  2876. Exit(FParamsAll);
  2877. if not aWithHidden and (Length(FParams) > 0) then
  2878. Exit(FParams);
  2879. ptr := AlignTParamFlags(@FTypeData^.ParamList[0]);
  2880. visible := 0;
  2881. total := 0;
  2882. if FTypeData^.ParamCount > 0 then begin
  2883. SetLength(infos, FTypeData^.ParamCount);
  2884. while total < FTypeData^.ParamCount do begin
  2885. infos[total].Handle := ptr;
  2886. infos[total].Flags := PParamFlags(ptr)^;
  2887. Inc(ptr, SizeOf(TParamFlags));
  2888. { handle name }
  2889. infos[total].Name := PShortString(ptr)^;
  2890. Inc(ptr, ptr^ + SizeOf(Byte));
  2891. { skip type name }
  2892. Inc(ptr, ptr^ + SizeOf(Byte));
  2893. { align }
  2894. ptr := AlignTParamFlags(ptr);
  2895. if not (pfHidden in infos[total].Flags) then
  2896. Inc(visible);
  2897. Inc(total);
  2898. end;
  2899. end;
  2900. if FTypeData^.MethodKind in [mkFunction, mkClassFunction] then begin
  2901. { skip return type name }
  2902. ptr := AlignTypeData(PByte(ptr) + ptr^ + SizeOf(Byte));
  2903. { handle return type }
  2904. FReturnType := GRttiPool.GetType(PPPTypeInfo(ptr)^^);
  2905. Inc(ptr, SizeOf(PPTypeInfo));
  2906. end;
  2907. { handle calling convention }
  2908. FCallConv := PCallConv(ptr)^;
  2909. Inc(ptr, SizeOf(TCallConv));
  2910. SetLength(FParamsAll, FTypeData^.ParamCount);
  2911. SetLength(FParams, visible);
  2912. if FTypeData^.ParamCount > 0 then begin
  2913. context := TRttiContext.Create;
  2914. try
  2915. paramtypes := PPPTypeInfo(ptr);
  2916. visible := 0;
  2917. for i := 0 to FTypeData^.ParamCount - 1 do begin
  2918. obj := context.GetByHandle(infos[i].Handle);
  2919. if Assigned(obj) then
  2920. FParamsAll[i] := obj as TRttiMethodTypeParameter
  2921. else begin
  2922. if Assigned(paramtypes[i]) then
  2923. paramtype := paramtypes[i]^
  2924. else
  2925. paramtype := Nil;
  2926. FParamsAll[i] := TRttiMethodTypeParameter.Create(infos[i].Handle, infos[i].Name, infos[i].Flags, paramtype);
  2927. context.AddObject(FParamsAll[i]);
  2928. end;
  2929. if not (pfHidden in infos[i].Flags) then begin
  2930. FParams[visible] := FParamsAll[i];
  2931. Inc(visible);
  2932. end;
  2933. end;
  2934. finally
  2935. context.Free;
  2936. end;
  2937. end;
  2938. if aWithHidden then
  2939. Result := FParamsAll
  2940. else
  2941. Result := FParams;
  2942. end;
  2943. function TRttiMethodType.GetCallingConvention: TCallConv;
  2944. begin
  2945. { the calling convention is located after the parameters, so get the parameters
  2946. which will also initialize the calling convention }
  2947. GetParameters(True);
  2948. Result := FCallConv;
  2949. end;
  2950. function TRttiMethodType.GetReturnType: TRttiType;
  2951. begin
  2952. if FTypeData^.MethodKind in [mkFunction, mkClassFunction] then begin
  2953. { the return type is located after the parameters, so get the parameters
  2954. which will also initialize the return type }
  2955. GetParameters(True);
  2956. Result := FReturnType;
  2957. end else
  2958. Result := Nil;
  2959. end;
  2960. function TRttiMethodType.GetFlags: TFunctionCallFlags;
  2961. begin
  2962. Result := [];
  2963. end;
  2964. function TRttiMethodType.Invoke(const aCallable: TValue; const aArgs: array of TValue): TValue;
  2965. var
  2966. method: PMethod;
  2967. inst: TValue;
  2968. begin
  2969. if aCallable.Kind <> tkMethod then
  2970. raise EInvocationError.CreateFmt(SErrInvokeCallableNotMethod, [Name]);
  2971. method := PMethod(aCallable.GetReferenceToRawData);
  2972. { by using a pointer we can also use this for non-class instance methods }
  2973. TValue.Make(@method^.Data, PTypeInfo(TypeInfo(Pointer)), inst);
  2974. Result := Rtti.Invoke(Name, method^.Code, CallingConvention, False, inst, aArgs, GetParameters(True), ReturnType);
  2975. end;
  2976. { TRttiProcedureType }
  2977. function TRttiProcedureType.GetParameters(aWithHidden: Boolean): specialize TArray<TRttiParameter>;
  2978. var
  2979. visible, i: SizeInt;
  2980. param: PProcedureParam;
  2981. obj: TRttiObject;
  2982. context: TRttiContext;
  2983. begin
  2984. if aWithHidden and (Length(FParamsAll) > 0) then
  2985. Exit(FParamsAll);
  2986. if not aWithHidden and (Length(FParams) > 0) then
  2987. Exit(FParams);
  2988. if FTypeData^.ProcSig.ParamCount = 0 then
  2989. Exit(Nil);
  2990. SetLength(FParamsAll, FTypeData^.ProcSig.ParamCount);
  2991. SetLength(FParams, FTypeData^.ProcSig.ParamCount);
  2992. context := TRttiContext.Create;
  2993. try
  2994. param := AlignTypeData(PProcedureParam(@FTypeData^.ProcSig.ParamCount + SizeOf(FTypeData^.ProcSig.ParamCount)));
  2995. visible := 0;
  2996. for i := 0 to FTypeData^.ProcSig.ParamCount - 1 do begin
  2997. obj := context.GetByHandle(param);
  2998. if Assigned(obj) then
  2999. FParamsAll[i] := obj as TRttiMethodTypeParameter
  3000. else begin
  3001. FParamsAll[i] := TRttiMethodTypeParameter.Create(param, param^.Name, param^.ParamFlags, param^.ParamType);
  3002. context.AddObject(FParamsAll[i]);
  3003. end;
  3004. if not (pfHidden in param^.ParamFlags) then begin
  3005. FParams[visible] := FParamsAll[i];
  3006. Inc(visible);
  3007. end;
  3008. param := PProcedureParam(AlignTypeData(PByte(@param^.Name) + Length(param^.Name) + SizeOf(param^.Name[0])));
  3009. end;
  3010. SetLength(FParams, visible);
  3011. finally
  3012. context.Free;
  3013. end;
  3014. if aWithHidden then
  3015. Result := FParamsAll
  3016. else
  3017. Result := FParams;
  3018. end;
  3019. function TRttiProcedureType.GetCallingConvention: TCallConv;
  3020. begin
  3021. Result := FTypeData^.ProcSig.CC;
  3022. end;
  3023. function TRttiProcedureType.GetReturnType: TRttiType;
  3024. var
  3025. context: TRttiContext;
  3026. begin
  3027. if not Assigned(FTypeData^.ProcSig.ResultTypeRef) then
  3028. Exit(Nil);
  3029. context := TRttiContext.Create;
  3030. try
  3031. Result := context.GetType(FTypeData^.ProcSig.ResultTypeRef^);
  3032. finally
  3033. context.Free;
  3034. end;
  3035. end;
  3036. function TRttiProcedureType.GetFlags: TFunctionCallFlags;
  3037. begin
  3038. Result := [fcfStatic];
  3039. end;
  3040. function TRttiProcedureType.Invoke(const aCallable: TValue; const aArgs: array of TValue): TValue;
  3041. begin
  3042. if aCallable.Kind <> tkProcVar then
  3043. raise EInvocationError.CreateFmt(SErrInvokeCallableNotProc, [Name]);
  3044. Result := Rtti.Invoke(Name, PCodePointer(aCallable.GetReferenceToRawData)^, CallingConvention, True, TValue.Empty, aArgs, GetParameters(True), ReturnType);
  3045. end;
  3046. { TRttiStringType }
  3047. function TRttiStringType.GetStringKind: TRttiStringKind;
  3048. begin
  3049. case TypeKind of
  3050. tkSString : result := skShortString;
  3051. tkLString : result := skAnsiString;
  3052. tkAString : result := skAnsiString;
  3053. tkUString : result := skUnicodeString;
  3054. tkWString : result := skWideString;
  3055. end;
  3056. end;
  3057. { TRttiInterfaceType }
  3058. function TRttiInterfaceType.IntfMethodCount: Word;
  3059. var
  3060. parent: TRttiInterfaceType;
  3061. table: PIntfMethodTable;
  3062. begin
  3063. parent := GetIntfBaseType;
  3064. if Assigned(parent) then
  3065. Result := parent.IntfMethodCount
  3066. else
  3067. Result := 0;
  3068. table := MethodTable;
  3069. if Assigned(table) then
  3070. Inc(Result, table^.Count);
  3071. end;
  3072. function TRttiInterfaceType.GetBaseType: TRttiType;
  3073. begin
  3074. Result := GetIntfBaseType;
  3075. end;
  3076. function TRttiInterfaceType.GetGUIDStr: String;
  3077. begin
  3078. Result := GUIDToString(GUID);
  3079. end;
  3080. function TRttiInterfaceType.GetDeclaredMethods: specialize TArray<TRttiMethod>;
  3081. var
  3082. methtable: PIntfMethodTable;
  3083. count, index: Word;
  3084. method: PIntfMethodEntry;
  3085. context: TRttiContext;
  3086. obj: TRttiObject;
  3087. parent: TRttiInterfaceType;
  3088. parentmethodcount: Word;
  3089. begin
  3090. if Assigned(fDeclaredMethods) then
  3091. Exit(fDeclaredMethods);
  3092. methtable := MethodTable;
  3093. if not Assigned(methtable) then
  3094. Exit(Nil);
  3095. if (methtable^.Count = 0) or (methtable^.RTTICount = $ffff) then
  3096. Exit(Nil);
  3097. parent := GetIntfBaseType;
  3098. if Assigned(parent) then
  3099. parentmethodcount := parent.IntfMethodCount
  3100. else
  3101. parentmethodcount := 0;
  3102. SetLength(fDeclaredMethods, methtable^.Count);
  3103. context := TRttiContext.Create;
  3104. try
  3105. method := methtable^.Method[0];
  3106. count := methtable^.Count;
  3107. while count > 0 do begin
  3108. index := methtable^.Count - count;
  3109. obj := context.GetByHandle(method);
  3110. if Assigned(obj) then
  3111. fDeclaredMethods[index] := obj as TRttiMethod
  3112. else begin
  3113. fDeclaredMethods[index] := TRttiIntfMethod.Create(Self, method, parentmethodcount + index);
  3114. context.AddObject(fDeclaredMethods[index]);
  3115. end;
  3116. method := method^.Next;
  3117. Dec(count);
  3118. end;
  3119. finally
  3120. context.Free;
  3121. end;
  3122. Result := fDeclaredMethods;
  3123. end;
  3124. { TRttiInstanceType }
  3125. function TRttiInstanceType.GetMetaClassType: TClass;
  3126. begin
  3127. result := FTypeData^.ClassType;
  3128. end;
  3129. function TRttiInstanceType.GetDeclaringUnitName: string;
  3130. begin
  3131. result := FTypeData^.UnitName;
  3132. end;
  3133. function TRttiInstanceType.GetBaseType: TRttiType;
  3134. var
  3135. AContext: TRttiContext;
  3136. begin
  3137. AContext := TRttiContext.Create;
  3138. try
  3139. result := AContext.GetType(FTypeData^.ParentInfo);
  3140. finally
  3141. AContext.Free;
  3142. end;
  3143. end;
  3144. function TRttiInstanceType.GetIsInstance: boolean;
  3145. begin
  3146. Result:=True;
  3147. end;
  3148. function TRttiInstanceType.GetTypeSize: integer;
  3149. begin
  3150. Result:=sizeof(TObject);
  3151. end;
  3152. function TRttiInstanceType.GetProperties: specialize TArray<TRttiProperty>;
  3153. var
  3154. TypeInfo: PTypeInfo;
  3155. TypeRttiType: TRttiType;
  3156. TD: PTypeData;
  3157. PPD: PPropData;
  3158. TP: PPropInfo;
  3159. Count: longint;
  3160. obj: TRttiObject;
  3161. begin
  3162. if not FPropertiesResolved then
  3163. begin
  3164. TypeInfo := FTypeInfo;
  3165. // Get the total properties count
  3166. SetLength(FProperties,FTypeData^.PropCount);
  3167. TypeRttiType:= self;
  3168. repeat
  3169. TD:=GetTypeData(TypeInfo);
  3170. // published properties count for this object
  3171. // skip the attribute-info if available
  3172. PPD := PClassData(TD)^.PropertyTable;
  3173. Count:=PPD^.PropCount;
  3174. // Now point TP to first propinfo record.
  3175. TP:=PPropInfo(@PPD^.PropList);
  3176. While Count>0 do
  3177. begin
  3178. // Don't overwrite properties with the same name
  3179. if FProperties[TP^.NameIndex]=nil then begin
  3180. obj := GRttiPool.GetByHandle(TP);
  3181. if Assigned(obj) then
  3182. FProperties[TP^.NameIndex] := obj as TRttiProperty
  3183. else begin
  3184. FProperties[TP^.NameIndex] := TRttiProperty.Create(TypeRttiType, TP);
  3185. GRttiPool.AddObject(FProperties[TP^.NameIndex]);
  3186. end;
  3187. end;
  3188. // Point to TP next propinfo record.
  3189. // Located at Name[Length(Name)+1] !
  3190. TP:=TP^.Next;
  3191. Dec(Count);
  3192. end;
  3193. TypeInfo:=TD^.Parentinfo;
  3194. TypeRttiType:= GRttiPool.GetType(TypeInfo);
  3195. until TypeInfo=nil;
  3196. end;
  3197. result := FProperties;
  3198. end;
  3199. { TRttiMember }
  3200. function TRttiMember.GetVisibility: TMemberVisibility;
  3201. begin
  3202. result := mvPublished;
  3203. end;
  3204. constructor TRttiMember.Create(AParent: TRttiType);
  3205. begin
  3206. inherited Create();
  3207. FParent := AParent;
  3208. end;
  3209. { TRttiProperty }
  3210. function TRttiProperty.GetPropertyType: TRttiType;
  3211. begin
  3212. result := GRttiPool.GetType(FPropInfo^.PropType);
  3213. end;
  3214. function TRttiProperty.GetIsReadable: boolean;
  3215. begin
  3216. result := assigned(FPropInfo^.GetProc);
  3217. end;
  3218. function TRttiProperty.GetIsWritable: boolean;
  3219. begin
  3220. result := assigned(FPropInfo^.SetProc);
  3221. end;
  3222. function TRttiProperty.GetVisibility: TMemberVisibility;
  3223. begin
  3224. // At this moment only pulished rtti-property-info is supported by fpc
  3225. result := mvPublished;
  3226. end;
  3227. function TRttiProperty.GetName: string;
  3228. begin
  3229. Result:=FPropInfo^.Name;
  3230. end;
  3231. function TRttiProperty.GetHandle: Pointer;
  3232. begin
  3233. Result := FPropInfo;
  3234. end;
  3235. constructor TRttiProperty.Create(AParent: TRttiType; APropInfo: PPropInfo);
  3236. begin
  3237. inherited Create(AParent);
  3238. FPropInfo := APropInfo;
  3239. end;
  3240. function TRttiProperty.GetAttributes: specialize TArray<TCustomAttribute>;
  3241. var
  3242. i: SizeInt;
  3243. at: PAttributeTable;
  3244. begin
  3245. if not FAttributesResolved then
  3246. begin
  3247. at := FPropInfo^.AttributeTable;
  3248. if Assigned(at) then
  3249. begin
  3250. SetLength(FAttributes, at^.AttributeCount);
  3251. for i := 0 to High(FAttributes) do
  3252. FAttributes[i] := TCustomAttribute(GetAttribute(at, i));
  3253. end;
  3254. FAttributesResolved:=true;
  3255. end;
  3256. result := FAttributes;
  3257. end;
  3258. function TRttiProperty.GetValue(Instance: pointer): TValue;
  3259. procedure ValueFromBool(value: Int64);
  3260. var
  3261. b8: Boolean;
  3262. b16: Boolean16;
  3263. b32: Boolean32;
  3264. bb: ByteBool;
  3265. bw: WordBool;
  3266. bl: LongBool;
  3267. td: PTypeData;
  3268. p: Pointer;
  3269. begin
  3270. td := GetTypeData(FPropInfo^.PropType);
  3271. case td^.OrdType of
  3272. otUByte:
  3273. begin
  3274. b8 := Boolean(value);
  3275. p := @b8;
  3276. end;
  3277. otUWord:
  3278. begin
  3279. b16 := Boolean16(value);
  3280. p := @b16;
  3281. end;
  3282. otULong:
  3283. begin
  3284. b32 := Boolean32(value);
  3285. p := @b32;
  3286. end;
  3287. otSByte:
  3288. begin
  3289. bb := ByteBool(value);
  3290. p := @bb;
  3291. end;
  3292. otSWord:
  3293. begin
  3294. bw := WordBool(value);
  3295. p := @bw;
  3296. end;
  3297. otSLong:
  3298. begin
  3299. bl := LongBool(value);
  3300. p := @bl;
  3301. end;
  3302. end;
  3303. TValue.Make(p, FPropInfo^.PropType, result);
  3304. end;
  3305. procedure ValueFromInt(value: Int64);
  3306. var
  3307. i8: UInt8;
  3308. i16: UInt16;
  3309. i32: UInt32;
  3310. td: PTypeData;
  3311. p: Pointer;
  3312. begin
  3313. td := GetTypeData(FPropInfo^.PropType);
  3314. case td^.OrdType of
  3315. otUByte,
  3316. otSByte:
  3317. begin
  3318. i8 := value;
  3319. p := @i8;
  3320. end;
  3321. otUWord,
  3322. otSWord:
  3323. begin
  3324. i16 := value;
  3325. p := @i16;
  3326. end;
  3327. otULong,
  3328. otSLong:
  3329. begin
  3330. i32 := value;
  3331. p := @i32;
  3332. end;
  3333. end;
  3334. TValue.Make(p, FPropInfo^.PropType, result);
  3335. end;
  3336. var
  3337. s: string;
  3338. ss: ShortString;
  3339. i: int64;
  3340. c: Char;
  3341. wc: WideChar;
  3342. begin
  3343. case FPropinfo^.PropType^.Kind of
  3344. tkSString:
  3345. begin
  3346. ss := GetStrProp(TObject(Instance), FPropInfo);
  3347. TValue.Make(@ss, FPropInfo^.PropType, result);
  3348. end;
  3349. tkAString:
  3350. begin
  3351. s := GetStrProp(TObject(Instance), FPropInfo);
  3352. TValue.Make(@s, FPropInfo^.PropType, result);
  3353. end;
  3354. tkBool:
  3355. begin
  3356. i := GetOrdProp(TObject(Instance), FPropInfo);
  3357. ValueFromBool(i);
  3358. end;
  3359. tkInteger:
  3360. begin
  3361. i := GetOrdProp(TObject(Instance), FPropInfo);
  3362. ValueFromInt(i);
  3363. end;
  3364. tkChar:
  3365. begin
  3366. c := AnsiChar(GetOrdProp(TObject(Instance), FPropInfo));
  3367. TValue.Make(@c, FPropInfo^.PropType, result);
  3368. end;
  3369. tkWChar:
  3370. begin
  3371. wc := WideChar(GetOrdProp(TObject(Instance), FPropInfo));
  3372. TValue.Make(@wc, FPropInfo^.PropType, result);
  3373. end;
  3374. tkInt64,
  3375. tkQWord:
  3376. begin
  3377. i := GetOrdProp(TObject(Instance), FPropInfo);
  3378. TValue.Make(@i, FPropInfo^.PropType, result);
  3379. end;
  3380. else
  3381. result := TValue.Empty;
  3382. end
  3383. end;
  3384. procedure TRttiProperty.SetValue(Instance: pointer; const AValue: TValue);
  3385. begin
  3386. case FPropinfo^.PropType^.Kind of
  3387. tkSString,
  3388. tkAString:
  3389. SetStrProp(TObject(Instance), FPropInfo, AValue.AsString);
  3390. tkInteger,
  3391. tkInt64,
  3392. tkQWord,
  3393. tkChar,
  3394. tkBool,
  3395. tkWChar:
  3396. SetOrdProp(TObject(Instance), FPropInfo, AValue.AsOrdinal);
  3397. else
  3398. raise exception.createFmt(SErrUnableToSetValueForType, [PropertyType.Name]);
  3399. end
  3400. end;
  3401. function TRttiType.GetIsInstance: boolean;
  3402. begin
  3403. result := false;
  3404. end;
  3405. function TRttiType.GetIsManaged: boolean;
  3406. begin
  3407. result := Rtti.IsManaged(FTypeInfo);
  3408. end;
  3409. function TRttiType.GetIsOrdinal: boolean;
  3410. begin
  3411. result := false;
  3412. end;
  3413. function TRttiType.GetIsRecord: boolean;
  3414. begin
  3415. result := false;
  3416. end;
  3417. function TRttiType.GetIsSet: boolean;
  3418. begin
  3419. result := false;
  3420. end;
  3421. function TRttiType.GetAsInstance: TRttiInstanceType;
  3422. begin
  3423. // This is a ridicoulous design, but Delphi-compatible...
  3424. result := TRttiInstanceType(self);
  3425. end;
  3426. function TRttiType.GetBaseType: TRttiType;
  3427. begin
  3428. result := nil;
  3429. end;
  3430. function TRttiType.GetTypeKind: TTypeKind;
  3431. begin
  3432. result := FTypeInfo^.Kind;
  3433. end;
  3434. function TRttiType.GetTypeSize: integer;
  3435. begin
  3436. result := -1;
  3437. end;
  3438. function TRttiType.GetName: string;
  3439. begin
  3440. Result:=FTypeInfo^.Name;
  3441. end;
  3442. function TRttiType.GetHandle: Pointer;
  3443. begin
  3444. Result := FTypeInfo;
  3445. end;
  3446. constructor TRttiType.Create(ATypeInfo: PTypeInfo);
  3447. begin
  3448. inherited Create();
  3449. FTypeInfo:=ATypeInfo;
  3450. if assigned(FTypeInfo) then
  3451. FTypeData:=GetTypeData(ATypeInfo);
  3452. end;
  3453. function TRttiType.GetAttributes: specialize TArray<TCustomAttribute>;
  3454. var
  3455. i: Integer;
  3456. at: PAttributeTable;
  3457. begin
  3458. if not FAttributesResolved then
  3459. begin
  3460. at := GetAttributeTable(FTypeInfo);
  3461. if Assigned(at) then
  3462. begin
  3463. setlength(FAttributes,at^.AttributeCount);
  3464. for i := 0 to at^.AttributeCount-1 do
  3465. FAttributes[i]:=GetAttribute(at,i);
  3466. end;
  3467. FAttributesResolved:=true;
  3468. end;
  3469. result := FAttributes;
  3470. end;
  3471. function TRttiType.GetProperties: specialize TArray<TRttiProperty>;
  3472. begin
  3473. Result := Nil;
  3474. end;
  3475. function TRttiType.GetProperty(const AName: string): TRttiProperty;
  3476. var
  3477. FPropList: specialize TArray<TRttiProperty>;
  3478. i: Integer;
  3479. begin
  3480. result := nil;
  3481. FPropList := GetProperties;
  3482. for i := 0 to length(FPropList)-1 do
  3483. if sametext(FPropList[i].Name,AName) then
  3484. begin
  3485. result := FPropList[i];
  3486. break;
  3487. end;
  3488. end;
  3489. function TRttiType.GetMethods: specialize TArray<TRttiMethod>;
  3490. var
  3491. parentmethods, selfmethods: specialize TArray<TRttiMethod>;
  3492. parent: TRttiType;
  3493. begin
  3494. if Assigned(fMethods) then
  3495. Exit(fMethods);
  3496. selfmethods := GetDeclaredMethods;
  3497. parent := GetBaseType;
  3498. if Assigned(parent) then begin
  3499. parentmethods := parent.GetMethods;
  3500. end;
  3501. fMethods := Concat(parentmethods, selfmethods);
  3502. Result := fMethods;
  3503. end;
  3504. function TRttiType.GetMethod(const aName: String): TRttiMethod;
  3505. var
  3506. methods: specialize TArray<TRttiMethod>;
  3507. method: TRttiMethod;
  3508. begin
  3509. methods := GetMethods;
  3510. for method in methods do
  3511. if SameText(method.Name, AName) then
  3512. Exit(method);
  3513. Result := Nil;
  3514. end;
  3515. function TRttiType.GetDeclaredMethods: specialize TArray<TRttiMethod>;
  3516. begin
  3517. Result := Nil;
  3518. end;
  3519. { TRttiNamedObject }
  3520. function TRttiNamedObject.GetName: string;
  3521. begin
  3522. result := '';
  3523. end;
  3524. { TRttiContext }
  3525. class function TRttiContext.Create: TRttiContext;
  3526. begin
  3527. result.FContextToken := nil;
  3528. end;
  3529. procedure TRttiContext.Free;
  3530. begin
  3531. FContextToken := nil;
  3532. end;
  3533. function TRttiContext.GetByHandle(AHandle: Pointer): TRttiObject;
  3534. begin
  3535. if not Assigned(FContextToken) then
  3536. FContextToken := TPoolToken.Create;
  3537. Result := (FContextToken as IPooltoken).RttiPool.GetByHandle(AHandle);
  3538. end;
  3539. procedure TRttiContext.AddObject(AObject: TRttiObject);
  3540. begin
  3541. if not Assigned(FContextToken) then
  3542. FContextToken := TPoolToken.Create;
  3543. (FContextToken as IPooltoken).RttiPool.AddObject(AObject);
  3544. end;
  3545. function TRttiContext.GetType(ATypeInfo: PTypeInfo): TRttiType;
  3546. begin
  3547. if not assigned(FContextToken) then
  3548. FContextToken := TPoolToken.Create;
  3549. result := (FContextToken as IPooltoken).RttiPool.GetType(ATypeInfo);
  3550. end;
  3551. function TRttiContext.GetType(AClass: TClass): TRttiType;
  3552. begin
  3553. if assigned(AClass) then
  3554. result := GetType(PTypeInfo(AClass.ClassInfo))
  3555. else
  3556. result := nil;
  3557. end;
  3558. {function TRttiContext.GetTypes: specialize TArray<TRttiType>;
  3559. begin
  3560. if not assigned(FContextToken) then
  3561. FContextToken := TPoolToken.Create;
  3562. result := (FContextToken as IPooltoken).RttiPool.GetTypes;
  3563. end;}
  3564. type
  3565. TQueryInterface = function(constref aIID: TGUID; out aObj): LongInt of object;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  3566. TAddRef = function: LongInt of object;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  3567. TRelease = function: LongInt of object;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  3568. { TVirtualInterface }
  3569. {.$define DEBUG_VIRTINTF}
  3570. constructor TVirtualInterface.Create(aPIID: PTypeInfo);
  3571. function GetIInterfaceMethod(aTypeInfo: PTypeInfo; const aName: String; out aType: TRttiType): TMethodImplementation;
  3572. begin
  3573. aType := fContext.GetType(aTypeInfo);
  3574. if not (aType is TRttiMethodType) then
  3575. raise EInsufficientRtti.Create(SErrVirtIntfIInterface) at get_caller_addr(get_frame), get_caller_frame(get_frame);
  3576. Result := TRttiMethodType(aType).CreateImplementation(@HandleIInterfaceCallback);
  3577. if not Assigned(Result) then
  3578. raise ERtti.CreateFmt(SErrVirtIntfCreateImpl, [aPIID^.Name, aName]) at get_caller_addr(get_frame), get_caller_frame(get_frame);
  3579. end;
  3580. const
  3581. BytesToPopQueryInterface =
  3582. {$ifdef cpui386}
  3583. 3 * SizeOf(Pointer); { aIID + aObj + $RetAddr }
  3584. {$else}
  3585. 0;
  3586. {$endif}
  3587. BytesToPopAddRef =
  3588. {$ifdef cpui386}
  3589. 1 * SizeOf(Pointer); { $RetAddr }
  3590. {$else}
  3591. 0;
  3592. {$endif}
  3593. BytesToPopRelease =
  3594. {$ifdef cpui386}
  3595. 1 * SizeOf(Pointer); { $RetAddr }
  3596. {$else}
  3597. 0;
  3598. {$endif}
  3599. var
  3600. t: TRttiType;
  3601. ti: PTypeInfo;
  3602. td: PInterfaceData;
  3603. methods: specialize TArray<TRttiMethod>;
  3604. m: TRttiMethod;
  3605. mt: PIntfMethodTable;
  3606. count, i: SizeInt;
  3607. begin
  3608. if not Assigned(aPIID) then
  3609. raise EArgumentNilException.Create(SErrVirtIntfTypeNil);
  3610. { ToDo: add support for raw interfaces once they support RTTI }
  3611. if aPIID^.Kind <> tkInterface then
  3612. raise EArgumentException.CreateFmt(SErrVirtIntfTypeMustBeIntf, [aPIID^.Name]);
  3613. fContext := TRttiContext.Create;
  3614. t := fContext.GetType(aPIID);
  3615. if not Assigned(t) then
  3616. raise EInsufficientRtti.CreateFmt(SErrVirtIntfTypeNotFound, [aPIID^.Name]);
  3617. { check whether the interface and all its parents have RTTI enabled (the only
  3618. exception is IInterface as we know the methods of that) }
  3619. td := PInterfaceData(GetTypeData(aPIID));
  3620. fGUID := td^.GUID;
  3621. fThunks[0] := AllocateRawThunk(TMethod(@QueryInterface).Code, Pointer(Self), BytesToPopQueryInterface);
  3622. fThunks[1] := AllocateRawThunk(TMethod(@_AddRef).Code, Pointer(Self), BytesToPopAddRef);
  3623. fThunks[2] := AllocateRawThunk(TMethod(@_Release).Code, Pointer(Self), BytesToPopRelease);
  3624. for i := Low(fThunks) to High(fThunks) do
  3625. if not Assigned(fThunks[i]) then
  3626. raise ENotImplemented.CreateFmt(SErrVirtIntfCreateThunk, [aPIID^.Name]);
  3627. ti := aPIID;
  3628. { ignore the three methods of IInterface }
  3629. count := 0;
  3630. while ti <> TypeInfo(IInterface) do begin
  3631. mt := td^.MethodTable;
  3632. if (mt^.Count > 0) and (mt^.RTTICount <> mt^.Count) then
  3633. raise EInsufficientRtti.CreateFmt(SErrVirtIntfNotAllMethodsRTTI, [aPIID^.Name]);
  3634. Inc(count, mt^.Count);
  3635. ti := td^.Parent^;
  3636. td := PInterfaceData(GetTypeData(ti));
  3637. end;
  3638. SetLength(fImpls, count);
  3639. methods := t.GetMethods;
  3640. for m in methods do begin
  3641. if m.VirtualIndex > High(fImpls) + Length(fThunks) then
  3642. raise ERtti.CreateFmt(SErrVirtIntfInvalidVirtIdx, [aPIID^.Name, m.Name, m.VirtualIndex]);
  3643. if m.VirtualIndex < Length(fThunks) then
  3644. raise ERtti.CreateFmt(SErrVirtIntfInvalidVirtIdx, [aPIID^.Name, m.Name, m.VirtualIndex]);
  3645. { we use the childmost entry, except for the IInterface methods }
  3646. if Assigned(fImpls[m.VirtualIndex - Length(fThunks)]) then begin
  3647. {$IFDEF DEBUG_VIRTINTF}Writeln('Ignoring duplicate implementation for index ', m.VirtualIndex);{$ENDIF}
  3648. Continue;
  3649. end;
  3650. fImpls[m.VirtualIndex - Length(fThunks)] := m.CreateImplementation(m, @HandleUserCallback);
  3651. end;
  3652. for i := 0 to High(fImpls) do
  3653. if not Assigned(fImpls) then
  3654. raise ERtti.CreateFmt(SErrVirtIntfMethodNil, [aPIID^.Name, i]);
  3655. fVmt := GetMem(Length(fImpls) * SizeOf(CodePointer) + Length(fThunks) * SizeOf(CodePointer));
  3656. if not Assigned(fVmt) then
  3657. raise ERtti.CreateFmt(SErrVirtIntfCreateVmt, [aPIID^.Name]);
  3658. for i := 0 to High(fThunks) do begin
  3659. fVmt[i] := fThunks[i];
  3660. {$IFDEF DEBUG_VIRTINTF}Writeln('VMT ', i, ': ', HexStr(fVmt[i]));{$ENDIF}
  3661. end;
  3662. for i := 0 to High(fImpls) do begin
  3663. fVmt[i + Length(fThunks)] := fImpls[i].CodeAddress;
  3664. {$IFDEF DEBUG_VIRTINTF}Writeln('VMT ', i + Length(fThunks), ': ', HexStr(fVmt[i + Length(fThunks)]));{$ENDIF}
  3665. end;
  3666. end;
  3667. constructor TVirtualInterface.Create(aPIID: PTypeInfo; aInvokeEvent: TVirtualInterfaceInvokeEvent);
  3668. begin
  3669. Create(aPIID);
  3670. OnInvoke := aInvokeEvent;
  3671. end;
  3672. destructor TVirtualInterface.Destroy;
  3673. var
  3674. impl: TMethodImplementation;
  3675. thunk: CodePointer;
  3676. begin
  3677. {$IFDEF DEBUG_VIRTINTF}Writeln('Freeing implementations');{$ENDIF}
  3678. for impl in fImpls do
  3679. impl.Free;
  3680. {$IFDEF DEBUG_VIRTINTF}Writeln('Freeing thunks');{$ENDIF}
  3681. for thunk in fThunks do
  3682. FreeRawThunk(thunk);
  3683. {$IFDEF DEBUG_VIRTINTF}Writeln('Freeing VMT');{$ENDIF}
  3684. if Assigned(fVmt) then
  3685. FreeMem(fVmt);
  3686. {$IFDEF DEBUG_VIRTINTF}Writeln('Freeing Context');{$ENDIF}
  3687. fContext.Free;
  3688. {$IFDEF DEBUG_VIRTINTF}Writeln('Done');{$ENDIF}
  3689. inherited Destroy;
  3690. end;
  3691. function TVirtualInterface.QueryInterface(constref aIID: TGuid; out aObj): LongInt;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  3692. begin
  3693. {$IFDEF DEBUG_VIRTINTF}Writeln('QueryInterface for ', GUIDToString(aIID));{$ENDIF}
  3694. if IsEqualGUID(aIID, fGUID) then begin
  3695. {$IFDEF DEBUG_VIRTINTF}Writeln('Returning ', HexStr(@fVmt));{$ENDIF}
  3696. Pointer(aObj) := @fVmt;
  3697. { QueryInterface increases the reference count }
  3698. _AddRef;
  3699. Result := S_OK;
  3700. end else
  3701. Result := inherited QueryInterface(aIID, aObj);
  3702. end;
  3703. procedure TVirtualInterface.HandleIInterfaceCallback(aInvokable: TRttiInvokableType; const aArgs: TValueArray; out aResult: TValue);
  3704. var
  3705. res: LongInt;
  3706. guid: TGuid;
  3707. begin
  3708. {$IFDEF DEBUG_VIRTINTF}Writeln(aInvokable.Name);{$ENDIF}
  3709. if aInvokable = fQueryInterfaceType then begin
  3710. {$IFDEF DEBUG_VIRTINTF}Writeln('Call for QueryInterface');{$ENDIF}
  3711. Move(aArgs[1].GetReferenceToRawData^, guid, SizeOf(guid));
  3712. res := QueryInterface(guid, PPointer(aArgs[2].GetReferenceToRawData)^);
  3713. TValue.Make(@res, TypeInfo(LongInt), aResult);
  3714. end else if aInvokable = fAddRefType then begin
  3715. {$IFDEF DEBUG_VIRTINTF}Writeln('Call for AddRef');{$ENDIF}
  3716. res := _AddRef;
  3717. TValue.Make(@res, TypeInfo(LongInt), aResult);
  3718. end else if aInvokable = fReleaseType then begin
  3719. {$IFDEF DEBUG_VIRTINTF}Writeln('Call for Release');{$ENDIF}
  3720. res := _Release;
  3721. TValue.Make(@res, TypeInfo(LongInt), aResult);
  3722. end;
  3723. end;
  3724. procedure TVirtualInterface.HandleUserCallback(aUserData: Pointer; const aArgs: TValueArray; out aResult: TValue);
  3725. begin
  3726. {$IFDEF DEBUG_VIRTINTF}Writeln('Call for ', TRttiMethod(aUserData).Name);{$ENDIF}
  3727. if Assigned(fOnInvoke) then
  3728. fOnInvoke(TRttiMethod(aUserData), aArgs, aResult);
  3729. end;
  3730. {$ifndef InLazIDE}
  3731. {$if defined(CPUI386) or (defined(CPUX86_64) and defined(WIN64))}
  3732. {$I invoke.inc}
  3733. {$endif}
  3734. {$endif}
  3735. initialization
  3736. PoolRefCount := 0;
  3737. InitDefaultFunctionCallManager;
  3738. {$ifdef SYSTEM_HAS_INVOKE}
  3739. InitSystemFunctionCallManager;
  3740. {$endif}
  3741. end.