rtti.pp 124 KB

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