rtti.pp 124 KB

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