objpas.inc 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  4. This unit makes Free Pascal as much as possible Delphi compatible
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$ifdef FPC_HAS_FEATURE_VARIANTS}
  12. procedure DoDispCallByIDError(res : Pointer; const disp : IDispatch;desc : PDispDesc; params : Pointer);
  13. begin
  14. handleerroraddrframeind(RuntimeErrorExitCodes[reVarDispatch],
  15. get_pc_addr,get_frame);
  16. end;
  17. procedure fpc_dispatch_by_id(Result: Pointer; const Dispatch: pointer;
  18. DispDesc: Pointer; Params: Pointer); compilerproc;
  19. type
  20. TDispProc = procedure(res : Pointer; const disp : IDispatch;desc : PDispDesc; params : Pointer);
  21. begin
  22. TDispProc(DispCallByIDProc)(Result,IDispatch(Dispatch),DispDesc,Params);
  23. end;
  24. {$endif FPC_HAS_FEATURE_VARIANTS}
  25. {****************************************************************************
  26. Internal Routines called from the Compiler
  27. ****************************************************************************}
  28. { the reverse order of the parameters make code generation easier }
  29. function fpc_do_is(aclass : tclass;aobject : tobject) : boolean;[public,alias: 'FPC_DO_IS']; compilerproc;
  30. begin
  31. fpc_do_is:=assigned(aobject) and assigned(aclass) and
  32. aobject.inheritsfrom(aclass);
  33. end;
  34. {$IFDEF FPC_HAS_FEATURE_THREADING}
  35. threadvar
  36. CastErrorFrom : ShortString;
  37. CastErrorTo : ShortString;
  38. {$ELSE}
  39. var
  40. CastErrorFrom : ShortString = '';
  41. CastErrorTo : ShortString = '';
  42. {$ENDIF}
  43. procedure SetCastErrorInfo(const aFrom,aTo : shortstring);
  44. begin
  45. CastErrorFrom:=aFrom;
  46. CastErrorTo:=aTo;
  47. end;
  48. { the reverse order of the parameters make code generation easier }
  49. function fpc_do_as(aclass : tclass;aobject : tobject): tobject;[public,alias: 'FPC_DO_AS']; compilerproc;
  50. begin
  51. if assigned(aobject) and not(aobject.inheritsfrom(aclass)) then
  52. begin
  53. SetCastErrorInfo(aObject.ClassName,aClass.ClassName);
  54. handleerroraddrframeInd(219,get_pc_addr,get_frame);
  55. end;
  56. result := aobject;
  57. end;
  58. { interface helpers }
  59. procedure fpc_intf_decr_ref(var i: pointer);[public,alias: 'FPC_INTF_DECR_REF']; compilerproc;
  60. var
  61. iFetch: pointer;
  62. begin
  63. iFetch:=i;
  64. if assigned(iFetch) then
  65. begin
  66. i:=nil;
  67. IUnknown(iFetch)._Release;
  68. end;
  69. end;
  70. { local declaration for intf_decr_ref for local access }
  71. procedure intf_decr_ref(var i: pointer); [external name 'FPC_INTF_DECR_REF'];
  72. procedure fpc_intf_incr_ref(i: pointer);[public,alias: 'FPC_INTF_INCR_REF']; compilerproc;
  73. begin
  74. if assigned(i) then
  75. IUnknown(i)._AddRef;
  76. end;
  77. { local declaration of intf_incr_ref for local access }
  78. procedure intf_incr_ref(i: pointer); [external name 'FPC_INTF_INCR_REF'];
  79. procedure fpc_intf_assign(var D: pointer; const S: pointer);[public,alias: 'FPC_INTF_ASSIGN']; compilerproc;
  80. begin
  81. if assigned(S) then
  82. IUnknown(S)._AddRef;
  83. if assigned(D) then
  84. IUnknown(D)._Release;
  85. D:=S;
  86. end;
  87. procedure fpc_intf_assign(var D: pointer; const s: pointer); [external name 'FPC_INTF_ASSIGN'];
  88. {procedure fpc_intf_assign_by_iid(var D: pointer; const S: pointer; const iid: TGUID);[public,alias: 'FPC_INTF_ASSIGN2']; compilerproc;
  89. var
  90. tmp : pointer;
  91. begin
  92. if assigned(S) then
  93. begin
  94. tmp:=nil;
  95. if IUnknown(S).QueryInterface(iid,tmp)<>S_OK then
  96. handleerror(219);
  97. if assigned(D) then
  98. IUnknown(D)._Release;
  99. D:=tmp;
  100. end
  101. else
  102. begin
  103. if assigned(D) then
  104. IUnknown(D)._Release;
  105. D:=nil;
  106. end;
  107. end;}
  108. function fpc_intf_is(const S: pointer; const iid: TGUID): Boolean;[public,alias: 'FPC_INTF_IS']; compilerproc;
  109. var
  110. tmpi: pointer;
  111. begin
  112. tmpi:=nil;
  113. fpc_intf_is:=Assigned(S) and (IUnknown(S).QueryInterface(iid,tmpi)=S_OK);
  114. if Assigned(tmpi) then
  115. IUnknown(tmpi)._Release;
  116. end;
  117. function fpc_intf_is_class(const S: pointer; const aclass: tclass): Boolean;[public,alias: 'FPC_INTF_IS_CLASS']; compilerproc;
  118. var
  119. tmpo: tobject;
  120. begin
  121. fpc_intf_is_class:=Assigned(S) and (IUnknown(S).QueryInterface(IObjectInstance,tmpo)=S_OK) and tmpo.InheritsFrom(aclass);
  122. end;
  123. function fpc_class_is_intf(const S: pointer; const iid: TGUID): Boolean;[public,alias: 'FPC_CLASS_IS_INTF']; compilerproc;
  124. var
  125. tmpi: pointer;
  126. tmpi2: pointer; // weak!
  127. begin
  128. tmpi:=nil;
  129. tmpi2:=nil;
  130. fpc_class_is_intf:=Assigned(S) and ((TObject(S).GetInterfaceWeak(IUnknown,tmpi2) and (IUnknown(tmpi2).QueryInterface(IID,tmpi)=S_OK)) or
  131. TObject(S).GetInterface(IID,tmpi));
  132. if Assigned(tmpi) then
  133. IUnknown(tmpi)._Release;
  134. end;
  135. function fpc_class_is_corbaintf(const S: pointer; const iid: Shortstring): Boolean;[public,alias: 'FPC_CLASS_IS_CORBAINTF']; compilerproc;
  136. begin
  137. fpc_class_is_corbaintf:=Assigned(S) and Assigned(TObject(S).GetInterfaceEntryByStr(iid));
  138. end;
  139. function fpc_intf_cast(const S: pointer; const iid: TGUID): IInterface;[public,alias: 'FPC_INTF_CAST']; compilerproc;
  140. var
  141. tmpi: pointer;
  142. begin
  143. tmpi:=nil;
  144. if Assigned(S) and (IUnknown(S).QueryInterface(iid,tmpi)=S_OK) then
  145. pointer(fpc_intf_cast):=tmpi
  146. else
  147. fpc_intf_cast:= nil;
  148. end;
  149. function fpc_intf_cast_class(const S: pointer; const aclass: tclass): pointer;[public,alias: 'FPC_INTF_CAST_CLASS']; compilerproc;
  150. var
  151. tmpo: tobject;
  152. begin
  153. if Assigned(S) and (IUnknown(S).QueryInterface(IObjectInstance,tmpo)=S_OK) and tmpo.InheritsFrom(aclass) then
  154. fpc_intf_cast_class:=tmpo
  155. else
  156. fpc_intf_cast_class:=nil;
  157. end;
  158. function fpc_class_cast_intf(const S: pointer; const iid: TGUID): IInterface;[public,alias: 'FPC_CLASS_CAST_INTF']; compilerproc;
  159. var
  160. tmpi: pointer;
  161. tmpi2: pointer; // weak!
  162. begin
  163. tmpi:=nil;
  164. tmpi2:=nil;
  165. if Assigned(S) and ((TObject(S).GetInterfaceWeak(IUnknown,tmpi2) and (IUnknown(tmpi2).QueryInterface(IID,tmpi)=S_OK)) or
  166. TObject(S).GetInterface(IID,tmpi)) then
  167. begin
  168. // decrease reference count
  169. fpc_class_cast_intf:=nil;
  170. pointer(fpc_class_cast_intf):=tmpi
  171. end
  172. else
  173. fpc_class_cast_intf:=nil;
  174. end;
  175. function fpc_class_cast_corbaintf(const S: pointer; const iid: Shortstring): Pointer;[public,alias: 'FPC_CLASS_CAST_CORBAINTF']; compilerproc;
  176. var
  177. tmpi: pointer;
  178. begin
  179. if Assigned(S) and TObject(S).GetInterface(iid,tmpi) then
  180. fpc_class_cast_corbaintf:=tmpi
  181. else
  182. fpc_class_cast_corbaintf:=nil;
  183. end;
  184. function fpc_intf_as(const S: pointer; const iid: TGUID): IInterface;[public,alias: 'FPC_INTF_AS']; compilerproc;
  185. var
  186. tmpi: pointer; // _AddRef before _Release
  187. errObj : TObject;
  188. begin
  189. if assigned(S) then
  190. begin
  191. tmpi:=nil;
  192. if IUnknown(S).QueryInterface(iid,tmpi)<>S_OK then
  193. begin
  194. if (IUnknown(S).QueryInterface(IObjectInstance,errObj)=S_OK) then
  195. SetCastErrorInfo(errObj.ClassName,iid.AsString)
  196. else
  197. SetCastErrorInfo('External interface',iid.AsString);
  198. handleerror(219);
  199. end;
  200. // decrease reference count
  201. fpc_intf_as:=nil;
  202. pointer(fpc_intf_as):=tmpi;
  203. end
  204. else
  205. fpc_intf_as:=nil;
  206. end;
  207. function fpc_intf_as_class(const S: pointer; const aclass: tclass): pointer;[public,alias: 'FPC_INTF_AS_CLASS']; compilerproc;
  208. var
  209. tmpo: tobject;
  210. errObj : TObject;
  211. begin
  212. if assigned(S) then
  213. begin
  214. if not ((IUnknown(S).QueryInterface(IObjectInstance,tmpo)=S_OK) and tmpo.inheritsfrom(aclass)) then
  215. begin
  216. if (IUnknown(S).QueryInterface(IObjectInstance,errObj)=S_OK) then
  217. SetCastErrorInfo(errObj.ClassName,aClass.ClassName)
  218. else
  219. SetCastErrorInfo('External interface',aClass.ClassName);
  220. handleerror(219);
  221. end;
  222. fpc_intf_as_class:=tmpo;
  223. end
  224. else
  225. fpc_intf_as_class:=nil;
  226. end;
  227. function fpc_class_as_intf(const S: pointer; const iid: TGUID): IInterface;[public,alias: 'FPC_CLASS_AS_INTF']; compilerproc;
  228. var
  229. tmpi: pointer; // _AddRef before _Release
  230. tmpi2: pointer; // weak!
  231. errObj : TObject;
  232. begin
  233. if assigned(S) then
  234. begin
  235. tmpi:=nil;
  236. tmpi2:=nil;
  237. if not ((TObject(S).GetInterfaceWeak(IUnknown,tmpi2) and (IUnknown(tmpi2).QueryInterface(IID,tmpi)=S_OK)) or TObject(S).GetInterface(IID,tmpi)) then
  238. begin
  239. SetCastErrorInfo(TObject(S).ClassName,iid.AsString);
  240. handleerror(219);
  241. end;
  242. // decrease reference count
  243. fpc_class_as_intf:=nil;
  244. pointer(fpc_class_as_intf):=tmpi;
  245. end
  246. else
  247. fpc_class_as_intf:=nil;
  248. end;
  249. function fpc_class_as_corbaintf(const S: pointer; const iid: Shortstring): Pointer;[public,alias: 'FPC_CLASS_AS_CORBAINTF']; compilerproc;
  250. var
  251. tmpi: pointer; // _AddRef before _Release
  252. begin
  253. if assigned(S) then
  254. begin
  255. tmpi:=nil;
  256. if not TObject(S).GetInterface(iid,tmpi) then
  257. begin
  258. SetCastErrorInfo(TObject(S).ClassName,iid);
  259. handleerror(219);
  260. end;
  261. fpc_class_as_corbaintf:=tmpi;
  262. end
  263. else
  264. fpc_class_as_corbaintf:=nil;
  265. end;
  266. {****************************************************************************
  267. TVMT
  268. ****************************************************************************}
  269. function TVmt.GetvParent: PVmt;
  270. begin
  271. if Assigned(vParentRef) then
  272. GetvParent:=vParentRef^
  273. else
  274. GetvParent:=Nil;
  275. end;
  276. {****************************************************************************
  277. TGUID
  278. ****************************************************************************}
  279. class operator TGUID.=(const aLeft, aRight: TGUID): Boolean;
  280. var
  281. P1,P2 : ^Cardinal;
  282. begin
  283. P1:=PCardinal(@aLeft);
  284. P2:=PCardinal(@aRight);
  285. Result:=(P1[0]=P2[0]) and (P1[1]=P2[1]) and (P1[2]=P2[2]) and (P1[3]=P2[3]);
  286. end;
  287. class operator TGUID.<>(const aLeft, aRight: TGUID): Boolean;
  288. begin
  289. Result:=Not (aLeft=aRight);
  290. end;
  291. class function TGUID.Empty: TGUID; static;
  292. begin
  293. Result:=Default(TGUID);
  294. end;
  295. class function TGUID.Create(const aData; aBigEndian: Boolean = False): TGUID; overload; static;
  296. begin
  297. Result:=Create(PByte(@aData),aBigEndian);
  298. end;
  299. class function TGUID.Create(const aData : PByte; aBigEndian: Boolean = False): TGUID; overload; static;
  300. const
  301. SysBigendian = {$IFDEF FPC_LITTLE_ENDIAN} false {$ELSE} true {$ENDIF};
  302. begin
  303. Result := PGuid(aData)^;
  304. if (aBigEndian=SysBigEndian) then
  305. exit;
  306. Result.D1:=SwapEndian(Result.D1);
  307. Result.D2:=SwapEndian(Result.D2);
  308. Result.D3:=SwapEndian(Result.D3);
  309. end;
  310. class function TGUID.Create(const aData: array of Byte; aStartIndex: Cardinal; aBigEndian: Boolean = False): TGUID; overload; static;
  311. begin
  312. if ((Length(aData)-aStartIndex)<16) then
  313. Result:=Empty
  314. else
  315. Result:=Create(PByte(@aData[aStartIndex]),aBigEndian);
  316. end;
  317. function TGUID.IsEmpty: Boolean;
  318. var
  319. P : ^Cardinal;
  320. begin
  321. P:=PCardinal(@Self);
  322. Result:=(P[0]=0) and (P[1]=0) and (P[2]=0) and (P[3]=0)
  323. end;
  324. function TGUID.AsString : ShortString;
  325. begin
  326. WriteStr(Result,'{',hexstr(Longint(D1),8),
  327. '-',HexStr(D2,4),
  328. '-',HexStr(D3,4),
  329. '-',HexStr(D4[0],2), HexStr(D4[1],2),
  330. '-',HexStr(D4[2],2), HexStr(D4[3],2), HexStr(D4[4],2), HexStr(D4[5],2), HexStr(D4[6],2), HexStr(D4[7],2),
  331. '}');
  332. end;
  333. {****************************************************************************
  334. TINTERFACEENTRY
  335. ****************************************************************************}
  336. function tinterfaceentry.GetIID: pguid;
  337. begin
  338. if Assigned(IIDRef) then
  339. GetIID:=IIDRef^
  340. else
  341. GetIID:=Nil;
  342. end;
  343. function tinterfaceentry.GetIIDStr: pshortstring;
  344. begin
  345. if Assigned(IIDStrRef) then
  346. GetIIDStr:=IIDStrRef^
  347. else
  348. GetIIDStr:=Nil;
  349. end;
  350. {****************************************************************************
  351. TOBJECT
  352. ****************************************************************************}
  353. constructor TObject.Create;
  354. begin
  355. end;
  356. destructor TObject.Destroy;
  357. begin
  358. {$IFDEF ENABLE_OBJECTHOOK}
  359. if assigned(DestroyObjectHook) then
  360. DestroyObjectHook(Self);
  361. {$ENDIF}
  362. end;
  363. procedure TObject.Free;
  364. begin
  365. // the call via self avoids a warning
  366. if self<>nil then
  367. self.destroy;
  368. end;
  369. class function TObject.InstanceSize : SizeInt;
  370. begin
  371. InstanceSize := PVmt(Self)^.vInstanceSize;
  372. end;
  373. procedure InitInterfacePointers(objclass: tclass;instance : pointer);
  374. var
  375. ovmt: PVmt;
  376. i: sizeuint;
  377. intftable: pinterfacetable;
  378. Res: pinterfaceentry;
  379. begin
  380. ovmt := PVmt(objclass);
  381. while assigned(ovmt) and assigned(ovmt^.vIntfTable) do
  382. begin
  383. intftable:=ovmt^.vIntfTable;
  384. i:=intftable^.EntryCount;
  385. Res:=@intftable^.Entries[0];
  386. while i>0 do begin
  387. if Res^.IType = etStandard then
  388. ppointer(@(pbyte(instance)[Res^.IOffset]))^:=
  389. pointer(Res^.VTable);
  390. inc(Res);
  391. dec(i);
  392. end;
  393. ovmt:=ovmt^.vParent;
  394. end;
  395. end;
  396. class function TObject.InitInstance(instance : pointer) : tobject;
  397. var
  398. vmt : PVmt;
  399. inittable : pointer;
  400. Res : ^TRTTIRecordOpOffsetEntry;
  401. {$ifdef FPC_HAS_FEATURE_RTTI}
  402. mopinittable : PRTTIRecordOpOffsetTable;
  403. {$endif def FPC_HAS_FEATURE_RTTI}
  404. i : longword;
  405. begin
  406. { the size is saved at offset 0 }
  407. fillchar(instance^, InstanceSize, 0);
  408. { insert VMT pointer into the new created memory area }
  409. { (in class methods self contains the VMT!) }
  410. {$IFNDEF SYSTEM_HAS_FEATURE_MONITOR}
  411. ppointer(instance)^:=pointer(self);
  412. {$ELSE}
  413. {$IFDEF VER3_2}
  414. // In 3.2.x Compiler (used during bootstrap) still inserts VMT at offset...
  415. ppointer(PByte(instance)+SizeOf(Pointer))^:=pointer(self);
  416. {$ELSE}
  417. // As of 3.3.x compiler forces insert of VMT at first pos.
  418. ppointer(instance)^:=pointer(self);
  419. {$ENDIF}
  420. {$ENDIF}
  421. if assigned(PVmt(self)^.vIntfTable) then
  422. InitInterfacePointers(self,instance);
  423. {$ifdef FPC_HAS_FEATURE_RTTI}
  424. { for management operators like initialize call int_initialize }
  425. vmt := PVmt(self);
  426. if assigned(vmt) then
  427. begin
  428. inittable:=vmt^.vInitTable;
  429. if assigned(inittable) then
  430. begin
  431. mopinittable:=RTTIRecordMopInitTable(inittable);
  432. if assigned(mopinittable) then
  433. begin
  434. {$push}
  435. { ensure that no range check errors pop up with the [0..0] array }
  436. {$R-}
  437. i:=mopinittable^.Count;
  438. Res:=@mopinittable^.Entries[0];
  439. while i>0 do
  440. begin
  441. TRTTIRecVarOp(Res^.ManagmentOperator)(PByte(Instance)+Res^.FieldOffset);
  442. inc(Res);
  443. dec(i);
  444. end;
  445. {$pop}
  446. end;
  447. end;
  448. end;
  449. {$endif def FPC_HAS_FEATURE_RTTI}
  450. InitInstance:=TObject(Instance);
  451. {$IFDEF ENABLE_OBJECTHOOK}
  452. If Assigned(AllocateObjectHook) then
  453. AllocateObjectHook(TObject(Instance));
  454. {$ENDIF}
  455. end;
  456. class function TObject.ClassParent : tclass;
  457. begin
  458. { type of self is class of tobject => it points to the vmt }
  459. { the parent vmt is saved at offset vmtParent }
  460. classparent:=tclass(PVmt(Self)^.vParent);
  461. end;
  462. class function TObject.NewInstance : tobject;
  463. var
  464. p : pointer;
  465. begin
  466. getmem(p, InstanceSize);
  467. if p <> nil then
  468. InitInstance(p);
  469. NewInstance:=TObject(p);
  470. end;
  471. procedure TObject.FreeInstance;
  472. begin
  473. CleanupInstance;
  474. FreeMem(Pointer(Self));
  475. end;
  476. class function TObject.ClassType : TClass;
  477. begin
  478. ClassType:=TClass(Pointer(Self))
  479. end;
  480. type
  481. {$PUSH}
  482. {$PACKRECORDS NORMAL}
  483. tmethodnamerec =
  484. {$IFNDEF FPC_REQUIRES_PROPER_ALIGNMENT}
  485. packed
  486. {$ENDIF FPC_REQUIRES_PROPER_ALIGNMENT}
  487. record
  488. name : pshortstring;
  489. addr : codepointer;
  490. end;
  491. tmethodnametable =
  492. {$IFNDEF FPC_REQUIRES_PROPER_ALIGNMENT}
  493. packed
  494. {$ENDIF FPC_REQUIRES_PROPER_ALIGNMENT}
  495. record
  496. count : dword;
  497. entries : packed array[0..0] of tmethodnamerec;
  498. end;
  499. {$POP}
  500. pmethodnametable = ^tmethodnametable;
  501. class function TObject.MethodAddress(const name : shortstring) : codepointer;
  502. var
  503. methodtable : pmethodnametable;
  504. i : longint; // in case count=0
  505. ovmt : PVmt;
  506. begin
  507. ovmt:=PVmt(self);
  508. while assigned(ovmt) do
  509. begin
  510. methodtable:=pmethodnametable(ovmt^.vMethodTable);
  511. if assigned(methodtable) then
  512. begin
  513. for i:=0 to methodtable^.count-1 do
  514. if ShortCompareText(methodtable^.entries[i].name^, name)=0 then
  515. begin
  516. MethodAddress:=methodtable^.entries[i].addr;
  517. exit;
  518. end;
  519. end;
  520. ovmt := ovmt^.vParent;
  521. end;
  522. MethodAddress:=nil;
  523. end;
  524. class function TObject.MethodName(address : codepointer) : shortstring;
  525. var
  526. methodtable : pmethodnametable;
  527. i : longint; // in case count=0
  528. ovmt : PVmt;
  529. begin
  530. ovmt:=PVmt(self);
  531. while assigned(ovmt) do
  532. begin
  533. methodtable:=pmethodnametable(ovmt^.vMethodTable);
  534. if assigned(methodtable) then
  535. begin
  536. for i:=0 to methodtable^.count-1 do
  537. if methodtable^.entries[i].addr=address then
  538. begin
  539. MethodName:=methodtable^.entries[i].name^;
  540. exit;
  541. end;
  542. end;
  543. ovmt := ovmt^.vParent;
  544. end;
  545. MethodName:='';
  546. end;
  547. function TObject.FieldAddress(const name : shortstring) : pointer;
  548. {The following is copied to the typinfo unit. If it is changed here, change it there as well ! }
  549. type
  550. {$PUSH}
  551. {$PACKRECORDS NORMAL}
  552. PFieldInfo = ^TFieldInfo;
  553. TFieldInfo =
  554. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  555. packed
  556. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  557. record
  558. FieldOffset: SizeUInt;
  559. ClassTypeIndex: Word;
  560. Name: ShortString;
  561. end;
  562. PFieldTable = ^TFieldTable;
  563. TFieldTable =
  564. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  565. packed
  566. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  567. record
  568. FieldCount: Word;
  569. ClassTable: Pointer;
  570. { should be array[Word] of TFieldInfo; but
  571. Elements have variant size! force at least proper alignment }
  572. Fields: array[0..0] of TFieldInfo
  573. end;
  574. {$POP}
  575. var
  576. ovmt: PVmt;
  577. FieldTable: PFieldTable;
  578. FieldInfo: PFieldInfo;
  579. i: longint;
  580. begin
  581. if Length(name) > 0 then
  582. begin
  583. ovmt := PVmt(ClassType);
  584. while ovmt <> nil do
  585. begin
  586. FieldTable := PFieldTable(ovmt^.vFieldTable);
  587. if FieldTable <> nil then
  588. begin
  589. FieldInfo := @FieldTable^.Fields[0];
  590. for i := 0 to FieldTable^.FieldCount - 1 do
  591. begin
  592. if ShortCompareText(FieldInfo^.Name, name) = 0 then
  593. begin
  594. fieldaddress := Pointer(Self) + FieldInfo^.FieldOffset;
  595. exit;
  596. end;
  597. FieldInfo := PFieldInfo(PByte(@FieldInfo^.Name) + 1 + Length(FieldInfo^.Name));
  598. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  599. { align to largest field of TFieldInfo }
  600. FieldInfo := Align(FieldInfo, SizeOf(PtrUInt));
  601. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  602. end;
  603. end;
  604. { Try again with the parent class type }
  605. ovmt:=ovmt^.vParent;
  606. end;
  607. end;
  608. fieldaddress:=nil;
  609. end;
  610. function TObject.SafeCallException(exceptobject : tobject;
  611. exceptaddr : codepointer) : HResult;
  612. begin
  613. safecallexception:=E_UNEXPECTED;
  614. end;
  615. class function TObject.ClassInfo : pointer;
  616. begin
  617. ClassInfo := PVmt(Self)^.vTypeInfo;
  618. end;
  619. class function TObject.ClassName : ShortString;
  620. begin
  621. ClassName := PVmt(Self)^.vClassName^;
  622. end;
  623. {$if SIZEOF(CHAR)=2}
  624. class function TObject.ClassNameIs(const name : AnsiString) : boolean;
  625. var
  626. SS : ShortString;
  627. begin
  628. SS:=Name;
  629. ClassNameIs:=ClassNameIs(SS);
  630. end;
  631. {$ENDIF}
  632. class function TObject.ClassNameIs(const name : ShortString) : boolean;
  633. begin
  634. ClassNameIs:=ShortCompareText(PVmt(Self)^.vClassName^, name) = 0;
  635. end;
  636. {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}
  637. class function TObject.ClassNameIs(const name : RTLString) : boolean;
  638. var
  639. SS : ShortString;
  640. begin
  641. {$if SIZEOF(CHAR)=2}
  642. SS:=UTF8Encode(Name);
  643. {$ELSE}
  644. SS:=Name;
  645. {$ENDIF}
  646. ClassNameIs:=ClassNameIs(SS);
  647. end;
  648. {$endif FPC_HAS_FEATURE_ANSISTRINGS}
  649. class function TObject.InheritsFrom(aclass : TClass) : Boolean;
  650. var
  651. vmt: PVmt;
  652. begin
  653. if assigned(aclass) then
  654. begin
  655. vmt:=PVmt(self);
  656. while assigned(vmt) and (vmt <> PVmt(aclass)) do
  657. vmt := vmt^.vParent;
  658. InheritsFrom := (vmt = PVmt(aclass));
  659. end
  660. else
  661. inheritsFrom := False;
  662. end;
  663. class function TObject.stringmessagetable : pstringmessagetable;
  664. begin
  665. stringmessagetable:=PVmt(Self)^.vMsgStrPtr;
  666. end;
  667. type
  668. tmessagehandler = procedure(var msg) of object;
  669. procedure TObject.Dispatch(var message);
  670. type
  671. {$PUSH}
  672. {$PACKRECORDS NORMAL}
  673. PMsgIntTable = ^TMsgIntTable;
  674. TMsgIntTable = record
  675. index : dword;
  676. method : codepointer;
  677. end;
  678. PMsgInt = ^TMsgInt;
  679. TMsgInt = record
  680. count : longint;
  681. msgs : array[0..0] of TMsgIntTable;
  682. end;
  683. {$POP}
  684. var
  685. index : dword;
  686. count,i : longint;
  687. msgtable : PMsgIntTable;
  688. p : PMsgInt;
  689. ovmt : PVmt;
  690. msghandler : tmessagehandler;
  691. begin
  692. index:=dword(message);
  693. ovmt := PVmt(ClassType);
  694. while assigned(ovmt) do
  695. begin
  696. // See if we have messages at all in this class.
  697. p:=PMsgInt(ovmt^.vDynamicTable);
  698. If Assigned(p) then
  699. begin
  700. msgtable:=@p^.msgs;
  701. count:=p^.count;
  702. end
  703. else
  704. Count:=0;
  705. { later, we can implement a binary search here }
  706. for i:=0 to count-1 do
  707. begin
  708. if index=msgtable[i].index then
  709. begin
  710. TMethod(msghandler).Code:=msgtable[i].method;
  711. TMethod(msghandler).Data:=self;
  712. msghandler(message);
  713. exit;
  714. end;
  715. end;
  716. ovmt:=ovmt^.vParent;
  717. end;
  718. DefaultHandler(message);
  719. end;
  720. procedure TObject.DispatchStr(var message);
  721. var
  722. name : shortstring;
  723. count,i : longint;
  724. msgstrtable : pmsgstrtable;
  725. p: pstringmessagetable;
  726. ovmt : PVmt;
  727. msghandler : tmessagehandler;
  728. begin
  729. name:=pshortstring(@message)^;
  730. ovmt:=PVmt(ClassType);
  731. while assigned(ovmt) do
  732. begin
  733. p := ovmt^.vMsgStrPtr;
  734. if (P<>Nil) and (p^.count<>0) then
  735. begin
  736. count:=p^.count;
  737. msgstrtable:=@p^.msgstrtable;
  738. end
  739. else
  740. Count:=0;
  741. { later, we can implement a binary search here }
  742. for i:=0 to count-1 do
  743. begin
  744. if name=msgstrtable[i].name^ then
  745. begin
  746. TMethod(msghandler).Code:=msgstrtable[i].method;
  747. TMethod(msghandler).Data:=self;
  748. msghandler(message);
  749. exit;
  750. end;
  751. end;
  752. ovmt:=ovmt^.vParent;
  753. end;
  754. DefaultHandlerStr(message);
  755. end;
  756. procedure TObject.DefaultHandler(var message);
  757. begin
  758. end;
  759. procedure TObject.DefaultHandlerStr(var message);
  760. begin
  761. end;
  762. procedure TObject.CleanupInstance;
  763. var
  764. vmt : PVmt;
  765. temp : pointer;
  766. begin
  767. vmt := PVmt(ClassType);
  768. while vmt<>nil do
  769. begin
  770. Temp:= vmt^.vInitTable;
  771. {$ifdef FPC_HAS_FEATURE_RTTI}
  772. { The RTTI format matches one for records, except the type is tkClass.
  773. Since RecordRTTI does not check the type, calling it yields the desired result. }
  774. if Assigned(Temp) then
  775. RecordRTTI(Self,aligntoqword(Temp+2+PByte(Temp)[1]),@int_finalize);
  776. {$endif def FPC_HAS_FEATURE_RTTI}
  777. vmt:= vmt^.vParent;
  778. end;
  779. {$IFDEF SYSTEM_HAS_FEATURE_MONITOR}
  780. if Assigned(_MonitorData) then
  781. TMonitor.FreeMonitorData(_MonitorData);
  782. {$ENDIF}
  783. end;
  784. procedure TObject.AfterConstruction;
  785. begin
  786. end;
  787. procedure TObject.BeforeDestruction;
  788. begin
  789. end;
  790. function IsGUIDEqual(const guid1, guid2: tguid): boolean;
  791. begin
  792. IsGUIDEqual:=
  793. (guid1.D1=guid2.D1) and
  794. (PDWORD(@guid1.D2)^=PDWORD(@guid2.D2)^) and
  795. (PDWORD(@guid1.D4[0])^=PDWORD(@guid2.D4[0])^) and
  796. (PDWORD(@guid1.D4[4])^=PDWORD(@guid2.D4[4])^);
  797. end;
  798. // Use of managed types should be avoided here; implicit _Addref/_Release
  799. // will end up in unpredictable behaviour if called on CORBA interfaces.
  800. type
  801. TInterfaceGetter = procedure(out Obj) of object;
  802. TClassGetter = function: TObject of object;
  803. function GetInterfaceByEntry(Instance: pointer; IEntry: pinterfaceentry; out obj): boolean;
  804. var
  805. Getter: TMethod;
  806. begin
  807. Pointer(Obj) := nil;
  808. Getter.Data := Instance;
  809. if Assigned(IEntry) and Assigned(Instance) then
  810. begin
  811. case IEntry^.IType of
  812. etStandard:
  813. Pointer(Obj) := PByte(instance)+IEntry^.IOffset;
  814. etFieldValue, etFieldValueClass:
  815. Pointer(obj) := PPointer(PByte(Instance)+IEntry^.IOffset)^;
  816. etVirtualMethodResult:
  817. begin
  818. // IOffset is relative to the VMT, not to instance.
  819. Getter.code := PCodePointer(PByte(PPointer(Instance)^) + IEntry^.IOffset)^;
  820. TInterfaceGetter(Getter)(obj);
  821. end;
  822. etVirtualMethodClass:
  823. begin
  824. // IOffset is relative to the VMT, not to instance.
  825. Getter.code := PCodePointer(PByte(PPointer(Instance)^) + IEntry^.IOffset)^;
  826. TObject(obj) := TClassGetter(Getter)();
  827. end;
  828. etStaticMethodResult:
  829. begin
  830. Getter.code := IEntry^.IOffsetAsCodePtr;
  831. TInterfaceGetter(Getter)(obj);
  832. end;
  833. etStaticMethodClass:
  834. begin
  835. Getter.code := IEntry^.IOffsetAsCodePtr;
  836. TObject(obj) := TClassGetter(Getter)();
  837. end;
  838. end;
  839. end;
  840. result := assigned(pointer(obj));
  841. end;
  842. function TObject.GetInterface(const iid : tguid;out obj) : boolean;
  843. var
  844. IEntry: PInterfaceEntry;
  845. Instance: TObject;
  846. begin
  847. if IsGUIDEqual(IObjectInstance,iid) then
  848. begin
  849. TObject(Obj) := Self;
  850. Result := True;
  851. Exit;
  852. end;
  853. Instance := self;
  854. repeat
  855. IEntry := Instance.GetInterfaceEntry(iid);
  856. result := GetInterfaceByEntry(Instance, IEntry, obj);
  857. if (not result) or
  858. (IEntry^.IType in [etStandard, etFieldValue,
  859. etStaticMethodResult, etVirtualMethodResult]) then
  860. Break;
  861. { if interface is implemented by a class-type property or field,
  862. continue search }
  863. Instance := TObject(obj);
  864. until False;
  865. { Getter function will normally AddRef, so adding another reference here
  866. will cause memleak. }
  867. if result and (IEntry^.IType in [etStandard, etFieldValue]) then
  868. IInterface(obj)._AddRef;
  869. end;
  870. function TObject.GetInterfaceWeak(const iid : tguid; out obj) : boolean;
  871. var
  872. IEntry: PInterfaceEntry;
  873. Instance: TObject;
  874. begin
  875. if IsGUIDEqual(IObjectInstance,iid) then
  876. begin
  877. TObject(Obj) := Self;
  878. Result := True;
  879. Exit;
  880. end;
  881. Instance := self;
  882. repeat
  883. IEntry := Instance.GetInterfaceEntry(iid);
  884. result := GetInterfaceByEntry(Instance, IEntry, obj);
  885. if (not result) or
  886. (IEntry^.IType in [etStandard, etFieldValue,
  887. etStaticMethodResult, etVirtualMethodResult]) then
  888. Break;
  889. { if interface is implemented by a class-type property or field,
  890. continue search }
  891. Instance := TObject(obj);
  892. until False;
  893. { Getter function will normally AddRef, so we have to release it,
  894. else the ref is not weak. }
  895. if result and not (IEntry^.IType in [etStandard, etFieldValue]) then
  896. IInterface(obj)._Release;
  897. end;
  898. function TObject.GetInterfaceByStr(const iidstr : shortstring;out obj) : boolean;
  899. var
  900. IEntry: PInterfaceEntry;
  901. Instance: TObject;
  902. begin
  903. Instance := self;
  904. repeat
  905. IEntry := Instance.GetInterfaceEntryByStr(iidstr);
  906. result := GetInterfaceByEntry(Instance, IEntry, obj);
  907. if (not result) or
  908. (IEntry^.IType in [etStandard, etFieldValue,
  909. etStaticMethodResult, etVirtualMethodResult]) then
  910. Break;
  911. { if interface is implemented by a class-type property or field,
  912. continue search }
  913. Instance := TObject(obj);
  914. until False;
  915. { Getter function will normally AddRef, so adding another reference here
  916. will cause memleak. (com interfaces only!) }
  917. if result and Assigned(IEntry^.IID) and (IEntry^.IType in [etStandard, etFieldValue]) then
  918. IInterface(obj)._AddRef;
  919. end;
  920. function TObject.GetInterface(const iidstr : shortstring;out obj) : boolean;
  921. begin
  922. Result := GetInterfaceByStr(iidstr,obj);
  923. end;
  924. class function TObject.GetInterfaceEntry(const iid : tguid) : pinterfaceentry;
  925. var
  926. i: sizeuint;
  927. intftable: pinterfacetable;
  928. ovmt: PVmt;
  929. begin
  930. ovmt := PVmt(Self);
  931. while Assigned(ovmt) and Assigned(ovmt^.vIntftable) do
  932. begin
  933. intftable:=ovmt^.vIntfTable;
  934. i:=intftable^.EntryCount;
  935. result:=@intftable^.Entries[0];
  936. while i>0 do
  937. begin
  938. if assigned(Result^.iid) and IsGUIDEqual(Result^.iid^,iid) then
  939. Exit;
  940. inc(Result);
  941. dec(i);
  942. end;
  943. ovmt := ovmt^.vParent;
  944. end;
  945. result := nil;
  946. end;
  947. class function TObject.GetInterfaceEntryByStr(const iidstr : shortstring) : pinterfaceentry;
  948. var
  949. i: sizeuint;
  950. intftable: pinterfacetable;
  951. ovmt: PVmt;
  952. begin
  953. ovmt := PVmt(Self);
  954. while Assigned(ovmt) and Assigned(ovmt^.vIntfTable) do
  955. begin
  956. intftable:=ovmt^.vIntfTable;
  957. i:=intftable^.EntryCount;
  958. result:=@intftable^.Entries[0];
  959. while i>0 do
  960. begin
  961. if assigned(result^.iidstr) and (result^.iidstr^ = iidstr) then
  962. Exit;
  963. inc(Result);
  964. dec(i);
  965. end;
  966. ovmt := ovmt^.vParent;
  967. end;
  968. result:=nil;
  969. end;
  970. class function TObject.GetInterfaceTable : pinterfacetable;
  971. begin
  972. getinterfacetable:=PVmt(Self)^.vIntfTable;
  973. end;
  974. class procedure TObject.GetLastCastErrorInfo(out aFrom,aTo : shortstring);
  975. begin
  976. aFrom:=CastErrorFrom;
  977. aTo:=CastErrorTo;
  978. CastErrorFrom:='';
  979. CastErrorTo:='';
  980. end;
  981. class function TObject.UnitName : RTLString;
  982. {$ifdef FPC_HAS_FEATURE_RTTI}
  983. type
  984. TClassTypeInfo = {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  985. Attributes: Pointer;
  986. case TTypeKind of
  987. tkClass: (
  988. ClassType: TClass;
  989. ParentInfo: Pointer;
  990. PropCount: SmallInt;
  991. UnitName: ShortString;
  992. );
  993. { include for proper alignment }
  994. tkInt64: (
  995. Dummy: Int64;
  996. );
  997. end;
  998. PClassTypeInfo = ^TClassTypeInfo;
  999. var
  1000. classtypeinfo: PClassTypeInfo;
  1001. begin
  1002. classtypeinfo:=ClassInfo;
  1003. if Assigned(classtypeinfo) then
  1004. begin
  1005. // offset PTypeInfo by Length(Name) + 2 (ShortString length byte + SizeOf(Kind))
  1006. inc(Pointer(classtypeinfo), PByte(Pointer(classtypeinfo)+1)^ + 2);
  1007. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  1008. classtypeinfo:=aligntoqword(classtypeinfo);
  1009. {$endif}
  1010. result:=classtypeinfo^.UnitName;
  1011. end
  1012. else
  1013. result:='';
  1014. end;
  1015. {$else not FPC_HAS_FEATURE_RTTI}
  1016. begin
  1017. result:='';
  1018. end;
  1019. {$endif ndef FPC_HAS_FEATURE_RTTI}
  1020. class function TObject.QualifiedClassName: RTLString;
  1021. var
  1022. uname: RTLString;
  1023. begin
  1024. uname := UnitName; //TODO: change 'UnitName' to 'UnitScope' as soon as RTL implement it
  1025. if uname='' then
  1026. result:=ClassName
  1027. else
  1028. result:=Concat(uname, '.', ClassName);
  1029. end;
  1030. function TObject.Equals(Obj: TObject) : boolean;
  1031. begin
  1032. result:=Obj=Self;
  1033. end;
  1034. function TObject.GetHashCode: PtrInt;
  1035. begin
  1036. result:=PtrInt(Self);
  1037. end;
  1038. function TObject.ToString: RTLString;
  1039. begin
  1040. result:=ClassName;
  1041. end;
  1042. procedure TObject.DisposeOf;
  1043. begin
  1044. Free;
  1045. end;
  1046. function TObject.GetDisposed : Boolean;
  1047. begin
  1048. Result:=False;
  1049. end;
  1050. procedure TObject.CheckDisposed;
  1051. begin
  1052. // Do nothing since we have no reference count.
  1053. end;
  1054. {$IFDEF SYSTEM_HAS_FEATURE_MONITOR}
  1055. function TObject.SetMonitorData(aData,aCheckOld : Pointer) : Pointer;
  1056. begin
  1057. Result:=InterlockedCompareExchange(_MonitorData,aData,aCheckOld);
  1058. end;
  1059. function TObject.GetMonitorData: Pointer;
  1060. begin
  1061. Result:=_MonitorData;
  1062. end;
  1063. {$ENDIF}
  1064. {****************************************************************************
  1065. TINTERFACEDOBJECT
  1066. ****************************************************************************}
  1067. function TInterfacedObject.QueryInterface(
  1068. {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  1069. begin
  1070. if getinterface(iid,obj) then
  1071. result:=S_OK
  1072. else
  1073. result:=longint(E_NOINTERFACE);
  1074. end;
  1075. function TInterfacedObject._AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  1076. begin
  1077. _addref:=frefcount;
  1078. if _addref<>0 then
  1079. begin
  1080. if _addref>0 then
  1081. _addref:=interlockedincrement(frefcount);
  1082. exit;
  1083. end;
  1084. frefcount:=1; { Work non-atomically in the common case of refcount = 0 (typical state after the complete object construction). }
  1085. _addref:=1;
  1086. end;
  1087. function TInterfacedObject._Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  1088. begin
  1089. _Release:=frefcount;
  1090. if _Release<>1 then
  1091. begin
  1092. if _Release<=0 then { -1 means recursive call from destructor... 0 is impossible. }
  1093. exit;
  1094. _Release:=interlockeddecrement(frefcount);
  1095. if _Release>0 then
  1096. exit;
  1097. end
  1098. else
  1099. _Release:=0; { Work non-atomically in the common case of refcount = 1 (typical state for the last owner... which is often the only owner). }
  1100. frefcount:=-1; { Prevent recursive _Release from destroying twice (bug 32168). }
  1101. self.destroy;
  1102. end;
  1103. destructor TInterfacedObject.Destroy;
  1104. begin
  1105. // We must explicitly reset. Bug ID 32353
  1106. FRefCount:=0;
  1107. inherited Destroy;
  1108. end;
  1109. procedure TInterfacedObject.AfterConstruction;
  1110. begin
  1111. { we need to fix the refcount we forced in newinstance }
  1112. { further, it must be done in a thread safe way }
  1113. if frefcount=1 then
  1114. frefcount:=0 { Work non-atomically in the common case of refcount = 1 (usual state before AfterConstruction). }
  1115. else
  1116. declocked(frefcount);
  1117. end;
  1118. procedure TInterfacedObject.BeforeDestruction;
  1119. begin
  1120. if frefcount>0 then { Legitimate values: -1 if destroying by _Release, 0 if destroying manually. }
  1121. HandleError(204);
  1122. end;
  1123. class function TInterfacedObject.NewInstance : TObject;
  1124. begin
  1125. NewInstance:=inherited NewInstance;
  1126. if NewInstance<>nil then
  1127. TInterfacedObject(NewInstance).frefcount:=1;
  1128. end;
  1129. {****************************************************************************
  1130. TAGGREGATEDOBJECT
  1131. ****************************************************************************}
  1132. constructor TAggregatedObject.Create(const aController: IUnknown);
  1133. begin
  1134. inherited Create;
  1135. { do not keep a counted reference to the controller! }
  1136. fcontroller := Pointer(aController);
  1137. end;
  1138. function TAggregatedObject.QueryInterface(
  1139. {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  1140. begin
  1141. Result := IUnknown(fcontroller).QueryInterface(iid, obj);
  1142. end;
  1143. function TAggregatedObject._AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  1144. begin
  1145. Result := IUnknown(fcontroller)._AddRef;
  1146. end;
  1147. function TAggregatedObject._Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  1148. begin
  1149. Result := IUnknown(fcontroller)._Release;
  1150. end;
  1151. function TAggregatedObject.GetController : IUnknown;
  1152. begin
  1153. Result := IUnknown(fcontroller);
  1154. end;
  1155. {****************************************************************************
  1156. TContainedOBJECT
  1157. ****************************************************************************}
  1158. function TContainedObject.QueryInterface(
  1159. {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  1160. begin
  1161. if getinterface(iid,obj) then
  1162. result:=S_OK
  1163. else
  1164. result:=longint(E_NOINTERFACE);
  1165. end;
  1166. {****************************************************************************
  1167. TNoRefCountObject
  1168. ****************************************************************************}
  1169. function TNoRefCountObject.QueryInterface( {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  1170. begin
  1171. if getinterface(iid,obj) then
  1172. result:=S_OK
  1173. else
  1174. result:=longint(E_NOINTERFACE);
  1175. end;
  1176. function TNoRefCountObject._AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  1177. begin
  1178. Result:=-1;
  1179. end;
  1180. function TNoRefCountObject._Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  1181. begin
  1182. Result:=-1;
  1183. end;
  1184. {****************************************************************************
  1185. TCustomAttribute
  1186. ****************************************************************************}
  1187. constructor TCustomAttribute.Create;
  1188. begin
  1189. inherited;
  1190. end;
  1191. {****************************************************************************
  1192. TUnimplementedAttribute
  1193. ****************************************************************************}
  1194. constructor TUnimplementedAttribute.Create;
  1195. begin
  1196. inherited;
  1197. end;
  1198. {****************************************************************************
  1199. TCustomStoredAttribute
  1200. ****************************************************************************}
  1201. constructor StoredAttribute.Create;
  1202. begin
  1203. end;
  1204. constructor StoredAttribute.Create(Const aFlag : Boolean);
  1205. begin
  1206. FFlag:=aFlag;
  1207. end;
  1208. constructor StoredAttribute.Create(Const aName : shortstring);
  1209. begin
  1210. FName:=aName;
  1211. end;
  1212. {****************************************************************************
  1213. TInterfaceThunk
  1214. ****************************************************************************}
  1215. Constructor TInterfaceThunk.Create(aCallback : TThunkCallback);
  1216. begin
  1217. FCallBack:=aCallBack;
  1218. end;
  1219. Procedure TInterfaceThunk.Thunk(aMethod: Longint; aCount : Longint; aData : PArgData);
  1220. begin
  1221. if Assigned(FCallBack) then
  1222. FCallBack(Self,aMethod,aCount,aData);
  1223. end;
  1224. function TInterfaceThunk.QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  1225. begin
  1226. result:=longint(E_NOINTERFACE);
  1227. if (TMethod(FCallBack).Data<>Nil) then
  1228. // Query the object that created us, this is normally TVirtualInterface
  1229. // Take care: do not call QueryInterface, that would create a never-ending loop !!
  1230. if TObject(TMethod(FCallBack).Data).GetInterface(iid,obj) then
  1231. result:=S_OK;
  1232. if (Result<>S_OK) then
  1233. Result:=Inherited QueryInterface(iid,obj);
  1234. if (Result<>S_OK) and Assigned(OnQueryInterface) then
  1235. OnQueryInterface(iid,Result,obj);
  1236. end;
  1237. function TInterfaceThunk.InterfaceVMTOffset : word;
  1238. begin
  1239. Result:=0;
  1240. end;
  1241. {****************************************************************************
  1242. Exception Support
  1243. ****************************************************************************}
  1244. {$ifdef FPC_HAS_FEATURE_EXCEPTIONS}
  1245. {$if defined(FPC_WASM_EXNREF_EXCEPTIONS)}
  1246. {$I except_exnref.inc}
  1247. {$elseif defined(FPC_WASM_LEGACY_EXCEPTIONS)}
  1248. {$I except_legacy.inc}
  1249. {$elseif defined(FPC_WASM_BRANCHFUL_EXCEPTIONS)}
  1250. {$I except_branchful.inc}
  1251. {$else}
  1252. {$i except.inc}
  1253. {$endif}
  1254. {$endif FPC_HAS_FEATURE_EXCEPTIONS}
  1255. {****************************************************************************
  1256. Various Delphi constructs
  1257. ****************************************************************************}
  1258. class operator TMethod.=(const aLeft, aRight: TMethod): Boolean; inline;
  1259. begin
  1260. Result:=(aLeft.Data=aRight.Data) and (aLeft.Code=aRight.Code);
  1261. end;
  1262. class operator TMethod.<>(const aLeft, aRight: TMethod): Boolean; inline;
  1263. begin
  1264. Result:=(aLeft.Data<>aRight.Data) or (aLeft.Code<>aRight.Code);
  1265. end;
  1266. class operator TMethod.>(const aLeft, aRight: TMethod): Boolean; inline;
  1267. begin
  1268. Result:=(PtrUInt(aLeft.Data)>PtrUInt(aRight.Data))
  1269. or
  1270. ((aLeft.Data=aRight.Data) and (PtrUInt(aLeft.Code)>PtrUint(aRight.Code)));
  1271. end;
  1272. class operator TMethod.>=(const aLeft, aRight: TMethod): Boolean; inline;
  1273. begin
  1274. Result:=(aLeft>aRight) or (aLeft=aRight);
  1275. end;
  1276. class operator TMethod.<(const aLeft, aRight: TMethod): Boolean; inline;
  1277. begin
  1278. Result:=(PtrUInt(aLeft.Data)<PtrUInt(aRight.Data))
  1279. or
  1280. ((aLeft.Data=aRight.Data) and (PtrUInt(aLeft.Code)<PtrUint(aRight.Code)));
  1281. end;
  1282. class operator TMethod.<=(const aLeft, aRight: TMethod): Boolean; inline;
  1283. begin
  1284. Result:=(aLeft<aRight) or (aLeft=aRight);
  1285. end;
  1286. function TPtrWrapper.ToPointer: Pointer;
  1287. begin
  1288. Result:=FValue;
  1289. end;
  1290. class function TPtrWrapper.GetNilValue: TPtrWrapper;
  1291. begin
  1292. Result.FValue:=Nil;
  1293. end;
  1294. constructor TPtrWrapper.Create(AValue: PtrInt);
  1295. begin
  1296. FValue:=Pointer(aValue);
  1297. end;
  1298. constructor TPtrWrapper.Create(AValue: Pointer);
  1299. begin
  1300. FValue:=aValue;
  1301. end;
  1302. function TPtrWrapper.ToInteger: PtrInt;
  1303. begin
  1304. Result:=PtrInt(FValue);
  1305. end;
  1306. class operator TPtrWrapper.=(Left, Right: TPtrWrapper): Boolean;
  1307. begin
  1308. Result:=Left.FValue=Right.FValue;
  1309. end;
  1310. constructor TMarshal.Create;
  1311. begin
  1312. System.Error(reInvalidPtr);
  1313. end;
  1314. class function TMarshal.AllocMem(Size: SizeInt): TPtrWrapper;
  1315. begin
  1316. Result.Value := System.AllocMem(Size);
  1317. end;
  1318. class function TMarshal.ReallocMem(OldPtr: TPtrWrapper; NewSize: SizeInt): TPtrWrapper;
  1319. var
  1320. P: Pointer;
  1321. begin
  1322. P := OldPtr.Value;
  1323. Result.Value := System.ReallocMem(P, NewSize);
  1324. end;
  1325. class procedure TMarshal.FreeMem(Ptr: TPtrWrapper);
  1326. begin
  1327. System.FreeMem(Ptr.Value);
  1328. end;
  1329. class procedure TMarshal.Move(Src, Dest: TPtrWrapper; Count: SizeInt); static;
  1330. begin
  1331. System.Move(Src.Value^, Dest.Value^, Count);
  1332. end;
  1333. class function TMarshal.UnsafeAddrOf(var Value): TPtrWrapper;
  1334. begin
  1335. Result.Value := @Value;
  1336. end;
  1337. class procedure TMarshal.Copy(const Src: TUint8Array; StartIndex: SizeInt; Dest: TPtrWrapper; Count: SizeInt);
  1338. begin
  1339. System.Move(PUInt8(Src)[StartIndex], Dest.Value^, Count * SizeOf(UInt8));
  1340. end;
  1341. class procedure TMarshal.Copy(Src: TPtrWrapper; var Dest: TUint8Array; StartIndex: SizeInt; Count: SizeInt);
  1342. begin
  1343. System.Move(Src.Value^, PUInt8(Dest)[StartIndex], Count * SizeOf(UInt8));
  1344. end;
  1345. class procedure TMarshal.Copy(const Src: TInt8Array; StartIndex: SizeInt; Dest: TPtrWrapper; Count: SizeInt);
  1346. begin
  1347. System.Move(PInt8(Src)[StartIndex], Dest.Value^, Count * SizeOf(Int8));
  1348. end;
  1349. class procedure TMarshal.Copy(Src: TPtrWrapper; var Dest: TInt8Array ; StartIndex: SizeInt; Count: SizeInt);
  1350. begin
  1351. System.Move(Src.Value^, PInt8(Dest)[StartIndex], Count * SizeOf(Int8));
  1352. end;
  1353. class procedure TMarshal.Copy(const Src: TUInt16Array; StartIndex: SizeInt; Dest: TPtrWrapper; Count: SizeInt);
  1354. begin
  1355. System.Move(PUInt16(Src)[StartIndex], Dest.Value^, Count * SizeOf(UInt16));
  1356. end;
  1357. class procedure TMarshal.Copy(Src: TPtrWrapper; var Dest: TUint16Array; StartIndex: SizeInt; Count: SizeInt);
  1358. begin
  1359. System.Move(Src.Value^, PUInt16(Dest)[StartIndex], Count * SizeOf(UInt16));
  1360. end;
  1361. class procedure TMarshal.Copy(const Src: TInt16Array; StartIndex: SizeInt; Dest: TPtrWrapper; Count: SizeInt);
  1362. begin
  1363. System.Move(PInt16(Src)[StartIndex], Dest.Value^, Count * SizeOf(Int16));
  1364. end;
  1365. class procedure TMarshal.Copy(Src: TPtrWrapper; var Dest: TInt16Array; StartIndex: SizeInt; Count: SizeInt);
  1366. begin
  1367. System.Move(Src.Value^, PInt16(Dest)[StartIndex], Count * SizeOf(Int16));
  1368. end;
  1369. class procedure TMarshal.Copy(const Src: TInt32Array; StartIndex: SizeInt; Dest: TPtrWrapper; Count: SizeInt);
  1370. begin
  1371. System.Move(PInt32(Src)[StartIndex], Dest.Value^, Count * SizeOf(Int32));
  1372. end;
  1373. class procedure TMarshal.Copy(Src: TPtrWrapper; var Dest: TInt32Array; StartIndex: SizeInt; Count: SizeInt);
  1374. begin
  1375. System.Move(Src.Value^, PInt32(Dest)[StartIndex], Count * SizeOf(Int32));
  1376. end;
  1377. class procedure TMarshal.Copy(const Src: TInt64Array; StartIndex: SizeInt; Dest: TPtrWrapper; Count: SizeInt);
  1378. begin
  1379. System.Move(PInt64(Src)[StartIndex], Dest.Value^, Count * SizeOf(Int64));
  1380. end;
  1381. class procedure TMarshal.Copy(Src: TPtrWrapper; var Dest: TInt64Array; StartIndex: SizeInt; Count: SizeInt);
  1382. begin
  1383. System.Move(Src.Value^, PInt64(Dest)[StartIndex], Count * SizeOf(Int64));
  1384. end;
  1385. class procedure TMarshal.Copy(const Src: TPtrWrapperArray; StartIndex: SizeInt; Dest: TPtrWrapper; Count: SizeInt);
  1386. begin
  1387. System.Move(PPointer(Src)[StartIndex], Dest.Value^, Count * SizeOf(TPtrWrapper));
  1388. end;
  1389. class procedure TMarshal.Copy(Src: TPtrWrapper; var Dest: TPtrWrapperArray; StartIndex: SizeInt; Count: SizeInt);
  1390. begin
  1391. System.Move(Src.Value^, PPointer(Dest)[StartIndex], Count * SizeOf(TPtrWrapper));
  1392. end;
  1393. generic class function TMarshal.FixArray<T>(const Arr: specialize TArray<T>): TPtrWrapper;
  1394. begin
  1395. Result.Value := nil;
  1396. specialize TArray<T>(Result) := Arr;
  1397. end;
  1398. generic class procedure TMarshal.UnfixArray<T>(ArrPtr: TPtrWrapper);
  1399. begin
  1400. Finalize(specialize TArray<T>(ArrPtr));
  1401. end;
  1402. class function TMarshal.ReadByte(Ptr: TPtrWrapper; Ofs: SizeInt = 0): Byte;
  1403. begin
  1404. Result := PByte(Ptr.Value + Ofs)^;
  1405. end;
  1406. class procedure TMarshal.WriteByte(Ptr: TPtrWrapper; Ofs: SizeInt; Value: Byte);
  1407. begin
  1408. PByte(Ptr.Value + Ofs)^ := Value;
  1409. end;
  1410. class procedure TMarshal.WriteByte(Ptr: TPtrWrapper; Value: Byte);
  1411. begin
  1412. PByte(Ptr.Value)^ := Value;
  1413. end;
  1414. class function TMarshal.ReadInt16(Ptr: TPtrWrapper; Ofs: SizeInt = 0): Int16;
  1415. begin
  1416. Result := PInt16(Ptr.Value + Ofs)^;
  1417. end;
  1418. class procedure TMarshal.WriteInt16(Ptr: TPtrWrapper; Ofs: SizeInt; Value: Int16);
  1419. begin
  1420. PInt16(Ptr.Value + Ofs)^ := Value;
  1421. end;
  1422. class procedure TMarshal.WriteInt16(Ptr: TPtrWrapper; Value: Int16);
  1423. begin
  1424. PInt16(Ptr.Value)^ := Value;
  1425. end;
  1426. class function TMarshal.ReadInt32(Ptr: TPtrWrapper; Ofs: SizeInt = 0): Int32;
  1427. begin
  1428. Result := PInt32(Ptr.Value + Ofs)^;
  1429. end;
  1430. class procedure TMarshal.WriteInt32(Ptr: TPtrWrapper; Ofs: SizeInt; Value: Int32);
  1431. begin
  1432. PInt32(Ptr.Value + Ofs)^ := Value;
  1433. end;
  1434. class procedure TMarshal.WriteInt32(Ptr: TPtrWrapper; Value: Int32);
  1435. begin
  1436. PInt32(Ptr.Value)^ := Value;
  1437. end;
  1438. class function TMarshal.ReadInt64(Ptr: TPtrWrapper; Ofs: SizeInt = 0): Int64;
  1439. begin
  1440. Result := PInt64(Ptr.Value + Ofs)^;
  1441. end;
  1442. class procedure TMarshal.WriteInt64(Ptr: TPtrWrapper; Ofs: SizeInt; Value: Int64);
  1443. begin
  1444. PInt64(Ptr.Value + Ofs)^ := Value;
  1445. end;
  1446. class procedure TMarshal.WriteInt64(Ptr: TPtrWrapper; Value: Int64);
  1447. begin
  1448. PInt64(Ptr.Value)^ := Value;
  1449. end;
  1450. class function TMarshal.ReadPtr(Ptr: TPtrWrapper; Ofs: SizeInt = 0): TPtrWrapper;
  1451. begin
  1452. Result.Value := PPointer(Ptr.Value + Ofs)^;
  1453. end;
  1454. class procedure TMarshal.WritePtr(Ptr: TPtrWrapper; Ofs: SizeInt; Value: TPtrWrapper);
  1455. begin
  1456. PPointer(Ptr.Value + Ofs)^ := Value.Value;
  1457. end;
  1458. class procedure TMarshal.WritePtr(Ptr, Value: TPtrWrapper);
  1459. begin
  1460. PPointer(Ptr.Value)^ := Value.Value;
  1461. end;
  1462. {$IFDEF FPC_HAS_FEATURE_UNICODESTRINGS}
  1463. class function TMarshal.AsAnsi(const S: UnicodeString): AnsiString;
  1464. begin
  1465. Result := AnsiString(S);
  1466. end;
  1467. class function TMarshal.AsAnsi(S: PUnicodeChar): AnsiString;
  1468. begin
  1469. result := AnsiString(S);
  1470. end;
  1471. class function TMarshal.InOutString(const S: UnicodeString): PUnicodeChar;
  1472. begin
  1473. Result := PUnicodeChar(S);
  1474. end;
  1475. class function TMarshal.InString(const S: UnicodeString): PUnicodeChar;
  1476. begin
  1477. Result := PUnicodeChar(S);
  1478. end;
  1479. class function TMarshal.OutString(const S: UnicodeString): PUnicodeChar;
  1480. begin
  1481. Result := PUnicodeChar(S);
  1482. end;
  1483. class function TMarshal.FixString(var Str: UnicodeString): TPtrWrapper;
  1484. begin
  1485. UniqueString(Str);
  1486. Result := UnsafeFixString(Str);
  1487. end;
  1488. class procedure TMarshal.UnfixString(Ptr: TPtrWrapper);
  1489. begin
  1490. if Ptr.Value <> PUnicodeChar('') then
  1491. Finalize(UnicodeString(Ptr));
  1492. end;
  1493. class function TMarshal.UnsafeFixString(const Str: UnicodeString): TPtrWrapper;
  1494. begin
  1495. if Length(Str) = 0 then
  1496. begin
  1497. Result.Value := PUnicodeChar('');
  1498. Exit;
  1499. end;
  1500. Result.Value := nil;
  1501. UnicodeString(Result) := Str;
  1502. end;
  1503. class function TMarshal.AllocStringAsAnsi(const Str: UnicodeString): TPtrWrapper;
  1504. begin
  1505. Result := AllocStringAsAnsi(PUnicodeChar(Pointer(Str)), Length(Str), DefaultSystemCodePage);
  1506. end;
  1507. class function TMarshal.AllocStringAsAnsi(const Str: UnicodeString; CodePage: Word): TPtrWrapper;
  1508. begin
  1509. Result := AllocStringAsAnsi(PUnicodeChar(Pointer(Str)), Length(Str), CodePage);
  1510. end;
  1511. class function TMarshal.AllocStringAsAnsi(S: PUnicodeChar): TPtrWrapper;
  1512. begin
  1513. Result := AllocStringAsAnsi(S, Length(S), DefaultSystemCodePage);
  1514. end;
  1515. class function TMarshal.AllocStringAsAnsi(S: PUnicodeChar; CodePage: Word): TPtrWrapper;
  1516. begin
  1517. Result := AllocStringAsAnsi(S, Length(S), CodePage);
  1518. end;
  1519. class function TMarshal.AllocStringAsUnicode(const Str: UnicodeString): TPtrWrapper;
  1520. var
  1521. NBytes: SizeUint;
  1522. begin
  1523. NBytes := (Length(Str) + 1) * SizeOf(UnicodeChar);
  1524. Result.Value := System.GetMem(NBytes);
  1525. System.Move(PUnicodeChar(Str)^, Result.Value^, NBytes);
  1526. end;
  1527. class function TMarshal.AllocStringAsUtf8(const Str: UnicodeString): TPtrWrapper;
  1528. begin
  1529. Result := AllocStringAsAnsi(PUnicodeChar(Pointer(Str)), Length(Str), CP_UTF8);
  1530. end;
  1531. class function TMarshal.AllocStringAsUtf8(S: PUnicodeChar): TPtrWrapper;
  1532. begin
  1533. Result := AllocStringAsAnsi(S, Length(S), CP_UTF8);
  1534. end;
  1535. class function TMarshal.AllocStringAsAnsi(S: PUnicodeChar; Len: SizeInt; CodePage: Word): TPtrWrapper;
  1536. var
  1537. U2ARes: AnsiString;
  1538. NBytes: SizeInt;
  1539. begin
  1540. U2ARes := ''; { Suppress warning. }
  1541. WideStringManager.Unicode2AnsiMoveProc(S, U2ARes, CodePage, Len);
  1542. if Length(U2ARes) = 0 then
  1543. begin
  1544. Result.Value := nil;
  1545. Exit;
  1546. end;
  1547. { Could instead avoid the second allocation, assuming U2ARes.RefCount = 1:
  1548. System.Move(Pointer(U2ARes)^, (Pointer(U2ARes) - AnsiStringHeaderSize)^, (Length(U2ARes) + 1) * SizeOf(AnsiChar));
  1549. Result.FValue := Pointer(U2ARes) - AnsiStringHeaderSize;
  1550. Pointer(U2ARes) := nil; }
  1551. NBytes := (Length(U2ARes) + 1) * SizeOf(AnsiChar);
  1552. Result.Value := System.GetMem(NBytes);
  1553. System.Move(PAnsiChar(U2ARes)^, Result.Value^, NBytes);
  1554. end;
  1555. class procedure TMarshal.Copy(const Src: TUnicodeCharArray; StartIndex: SizeInt; Dest: TPtrWrapper; Count: SizeInt);
  1556. begin
  1557. System.Move(PUnicodeChar(Src)[StartIndex], Dest.Value^, Count * SizeOf(UnicodeChar));
  1558. end;
  1559. class procedure TMarshal.Copy(Src: TPtrWrapper; var Dest: TUnicodeCharArray; StartIndex: SizeInt; Count: SizeInt);
  1560. begin
  1561. System.Move(Src.Value^, PUnicodeChar(Dest)[StartIndex], Count * SizeOf(UnicodeChar));
  1562. end;
  1563. class function TMarshal.ReadStringAsAnsi(Ptr: TPtrWrapper; Len: SizeInt = -1): UnicodeString;
  1564. begin
  1565. Result := ReadStringAsAnsi(DefaultSystemCodePage, Ptr, Len);
  1566. end;
  1567. class function TMarshal.ReadStringAsAnsi(CodePage: Word; Ptr: TPtrWrapper; Len: SizeInt = -1): UnicodeString;
  1568. begin
  1569. { Here and below, IndexByte/Word assume that, when Len >= 0, either:
  1570. - Up to Len characters are accessible in Ptr;
  1571. - IndexByte/Word cannot access invalid memory past the searched character
  1572. (e.g. i386.inc and x86_64.inc IndexByte/Word versions are specifically designed not to). }
  1573. if Len < 0 then
  1574. Len := IndexByte(Ptr.Value^, Len, 0);
  1575. Result := ''; { Suppress warning. }
  1576. WideStringManager.Ansi2UnicodeMoveProc(Ptr.Value, CodePage, Result, Len);
  1577. end;
  1578. class function TMarshal.ReadStringAsAnsiUpTo(CodePage: Word; Ptr: TPtrWrapper; MaxLen: SizeInt): UnicodeString;
  1579. var
  1580. Len: SizeInt;
  1581. begin
  1582. Len := IndexByte(Ptr.Value^, MaxLen, 0);
  1583. if Len < 0 then
  1584. Len := MaxLen;
  1585. Result := ReadStringAsAnsi(CodePage, Ptr, Len);
  1586. end;
  1587. class procedure TMarshal.WriteStringAsAnsi(Ptr: TPtrWrapper; const Value: UnicodeString; MaxCharsIncNull: SizeInt);
  1588. begin
  1589. WriteStringAsAnsi(Ptr, 0, Value, MaxCharsIncNull, DefaultSystemCodePage);
  1590. end;
  1591. class procedure TMarshal.WriteStringAsAnsi(Ptr: TPtrWrapper; const Value: UnicodeString; MaxCharsIncNull: SizeInt; CodePage: Word);
  1592. begin
  1593. WriteStringAsAnsi(Ptr, 0, Value, MaxCharsIncNull, CodePage);
  1594. end;
  1595. class procedure TMarshal.WriteStringAsAnsi(Ptr: TPtrWrapper; Ofs: SizeInt; const Value: UnicodeString; MaxCharsIncNull: SizeInt);
  1596. begin
  1597. WriteStringAsAnsi(Ptr, Ofs, Value, MaxCharsIncNull, DefaultSystemCodePage);
  1598. end;
  1599. class procedure TMarshal.WriteStringAsAnsi(Ptr: TPtrWrapper; Ofs: SizeInt; const Value: UnicodeString; MaxCharsIncNull: SizeInt; CodePage: Word);
  1600. var
  1601. U2ARes: AnsiString;
  1602. ValueLen, U2AResLen: SizeInt;
  1603. begin
  1604. U2ARes := ''; { Suppress warning. }
  1605. ValueLen := Length(Value);
  1606. { Delphi null-terminates iff MaxCharsIncNull < 0, so MaxCharsIncNull is actually just MaxChars. }
  1607. if (MaxCharsIncNull > 0) and (MaxCharsIncNull < ValueLen) then
  1608. ValueLen := MaxCharsIncNull; { UTF-16 → ANSI should never shrink element count, so limit the number of characters analyzed. }
  1609. WideStringManager.Unicode2AnsiMoveProc(PUnicodeChar(Pointer(Value)), U2ARes, CodePage, ValueLen);
  1610. U2AResLen := Length(U2ARes);
  1611. if (MaxCharsIncNull >= 0) and (MaxCharsIncNull < U2AResLen) then
  1612. U2AResLen := MaxCharsIncNull;
  1613. System.Move(PAnsiChar(Pointer(U2ARes))^, (Ptr.Value + Ofs)^, U2AResLen * SizeOf(AnsiChar));
  1614. if MaxCharsIncNull < 0 then
  1615. PAnsiChar(Ptr.Value + Ofs)[U2AResLen] := #0;
  1616. end;
  1617. class function TMarshal.ReadStringAsUnicode(Ptr: TPtrWrapper; Len: SizeInt = -1): UnicodeString;
  1618. begin
  1619. if Len < 0 then
  1620. Len := Length(PUnicodeChar(Ptr.Value));
  1621. Result := ''; { Suppress warning. }
  1622. SetLength(Result, Len);
  1623. System.Move(Ptr.Value^, Pointer(Result)^, Len * SizeOf(UnicodeChar));
  1624. end;
  1625. class function TMarshal.ReadStringAsUnicodeUpTo(Ptr: TPtrWrapper; MaxLen: SizeInt): UnicodeString;
  1626. var
  1627. Len: SizeInt;
  1628. begin
  1629. Len := IndexWord(Ptr.Value^, MaxLen, 0);
  1630. if Len < 0 then
  1631. Len := MaxLen;
  1632. Result := ReadStringAsUnicode(Ptr, Len);
  1633. end;
  1634. class procedure TMarshal.WriteStringAsUnicode(Ptr: TPtrWrapper; const Value: UnicodeString; MaxCharsIncNull: SizeInt);
  1635. begin
  1636. WriteStringAsUnicode(Ptr, 0, Value, MaxCharsIncNull);
  1637. end;
  1638. class procedure TMarshal.WriteStringAsUnicode(Ptr: TPtrWrapper; Ofs: SizeInt; const Value: UnicodeString; MaxCharsIncNull: SizeInt);
  1639. var
  1640. Len: SizeInt;
  1641. begin
  1642. { Again, Delphi null-terminates iff MaxCharsIncNull < 0, so MaxCharsIncNull is actually just MaxChars. }
  1643. Len := Length(Value);
  1644. if (MaxCharsIncNull >= 0) and (MaxCharsIncNull < Len) then
  1645. Len := MaxCharsIncNull;
  1646. System.Move(Pointer(Value)^, (Ptr.Value + Ofs)^, Len * SizeOf(UnicodeChar));
  1647. if MaxCharsIncNull < 0 then
  1648. PUnicodeChar(Ptr.Value + Ofs)[Len] := #0;
  1649. end;
  1650. class function TMarshal.ReadStringAsUtf8(Ptr: TPtrWrapper; Len: SizeInt = -1): UnicodeString;
  1651. begin
  1652. Result := ReadStringAsAnsi(CP_UTF8, Ptr, Len);
  1653. end;
  1654. class function TMarshal.ReadStringAsUtf8UpTo(Ptr: TPtrWrapper; MaxLen: SizeInt): UnicodeString;
  1655. begin
  1656. Result := ReadStringAsAnsiUpTo(CP_UTF8, Ptr, MaxLen);
  1657. end;
  1658. class procedure TMarshal.WriteStringAsUtf8(Ptr: TPtrWrapper; const Value: UnicodeString; MaxCharsIncNull: SizeInt);
  1659. begin
  1660. WriteStringAsAnsi(Ptr, Value, MaxCharsIncNull, CP_UTF8);
  1661. end;
  1662. class procedure TMarshal.WriteStringAsUtf8(Ptr: TPtrWrapper; Ofs: SizeInt; const Value: UnicodeString; MaxCharsIncNull: SizeInt);
  1663. begin
  1664. WriteStringAsAnsi(Ptr, Ofs, Value, MaxCharsIncNull, CP_UTF8);
  1665. end;
  1666. {$ENDIF}
  1667. {$IFDEF SYSTEM_HAS_FEATURE_MONITOR}
  1668. {$i monitor.inc}
  1669. {$ENDIF}