rtti.pp 128 KB

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