rtti.pp 123 KB

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