objpas.inc 57 KB

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