rtti.pp 125 KB

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