objpas.inc 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213
  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. {$ifdef VER3_0}
  231. GetvParent:=vParentRef;
  232. {$else VER3_0}
  233. if Assigned(vParentRef) then
  234. GetvParent:=vParentRef^
  235. else
  236. GetvParent:=Nil;
  237. {$endif VER3_0}
  238. end;
  239. {****************************************************************************
  240. TINTERFACEENTRY
  241. ****************************************************************************}
  242. function tinterfaceentry.GetIID: pguid;
  243. begin
  244. {$ifdef VER3_0}
  245. GetIID:=IIDRef;
  246. {$else VER3_0}
  247. if Assigned(IIDRef) then
  248. GetIID:=IIDRef^
  249. else
  250. GetIID:=Nil;
  251. {$endif VER3_0}
  252. end;
  253. function tinterfaceentry.GetIIDStr: pshortstring;
  254. begin
  255. {$ifdef VER3_0}
  256. GetIIDStr:=IIDStrRef;
  257. {$else VER3_0}
  258. if Assigned(IIDStrRef) then
  259. GetIIDStr:=IIDStrRef^
  260. else
  261. GetIIDStr:=Nil;
  262. {$endif VER3_0}
  263. end;
  264. {****************************************************************************
  265. TOBJECT
  266. ****************************************************************************}
  267. constructor TObject.Create;
  268. begin
  269. end;
  270. destructor TObject.Destroy;
  271. begin
  272. end;
  273. procedure TObject.Free;
  274. begin
  275. // the call via self avoids a warning
  276. if self<>nil then
  277. self.destroy;
  278. end;
  279. class function TObject.InstanceSize : SizeInt;
  280. begin
  281. InstanceSize := PVmt(Self)^.vInstanceSize;
  282. end;
  283. {$ifdef VER3_0}
  284. var
  285. emptyintf: ptruint; public name 'FPC_EMPTYINTF';
  286. {$endif VER3_0}
  287. procedure InitInterfacePointers(objclass: tclass;instance : pointer);
  288. var
  289. ovmt: PVmt;
  290. i: longint;
  291. intftable: pinterfacetable;
  292. Res: pinterfaceentry;
  293. begin
  294. ovmt := PVmt(objclass);
  295. while assigned(ovmt) and {$ifdef VER3_0}(ovmt^.vIntfTable <> @emptyintf){$else}assigned(ovmt^.vIntfTable){$endif} do
  296. begin
  297. intftable:=ovmt^.vIntfTable;
  298. {$ifdef VER3_0}
  299. if assigned(intftable) then
  300. {$endif VER3_0}
  301. begin
  302. i:=intftable^.EntryCount;
  303. Res:=@intftable^.Entries[0];
  304. while i>0 do begin
  305. if Res^.IType = etStandard then
  306. ppointer(@(pbyte(instance)[Res^.IOffset]))^:=
  307. pointer(Res^.VTable);
  308. inc(Res);
  309. dec(i);
  310. end;
  311. end;
  312. ovmt:=ovmt^.vParent;
  313. end;
  314. end;
  315. class function TObject.InitInstance(instance : pointer) : tobject;
  316. {$ifndef VER3_0}
  317. var
  318. vmt : PVmt;
  319. inittable : pointer;
  320. {$ifdef FPC_HAS_FEATURE_RTTI}
  321. mopinittable : PRTTIRecordOpOffsetTable;
  322. {$endif def FPC_HAS_FEATURE_RTTI}
  323. i : longint;
  324. {$endif VER3_0}
  325. begin
  326. { the size is saved at offset 0 }
  327. fillchar(instance^, InstanceSize, 0);
  328. { insert VMT pointer into the new created memory area }
  329. { (in class methods self contains the VMT!) }
  330. ppointer(instance)^:=pointer(self);
  331. if {$ifdef VER3_0}PVmt(self)^.vIntfTable <> @emptyintf{$else}assigned(PVmt(self)^.vIntfTable){$endif} then
  332. InitInterfacePointers(self,instance);
  333. {$ifndef VER3_0}
  334. {$ifdef FPC_HAS_FEATURE_RTTI}
  335. { for management operators like initialize call int_initialize }
  336. vmt := PVmt(self);
  337. if assigned(vmt) then
  338. begin
  339. inittable:=vmt^.vInitTable;
  340. if assigned(inittable) then
  341. begin
  342. mopinittable:=RTTIRecordMopInitTable(inittable);
  343. if assigned(mopinittable) then
  344. begin
  345. {$push}
  346. { ensure that no range check errors pop up with the [0..0] array }
  347. {$R-}
  348. for i:=0 to mopinittable^.Count-1 do
  349. TRTTIRecVarOp(mopinittable^.Entries[i].ManagmentOperator)(PByte(Instance)+mopinittable^.Entries[i].FieldOffset);
  350. {$pop}
  351. end;
  352. end;
  353. end;
  354. {$endif def FPC_HAS_FEATURE_RTTI}
  355. {$endif VER3_0}
  356. InitInstance:=TObject(Instance);
  357. end;
  358. class function TObject.ClassParent : tclass;
  359. begin
  360. { type of self is class of tobject => it points to the vmt }
  361. { the parent vmt is saved at offset vmtParent }
  362. classparent:=tclass(PVmt(Self)^.vParent);
  363. end;
  364. class function TObject.NewInstance : tobject;
  365. var
  366. p : pointer;
  367. begin
  368. getmem(p, InstanceSize);
  369. if p <> nil then
  370. InitInstance(p);
  371. NewInstance:=TObject(p);
  372. end;
  373. procedure TObject.FreeInstance;
  374. begin
  375. CleanupInstance;
  376. FreeMem(Pointer(Self));
  377. end;
  378. class function TObject.ClassType : TClass;
  379. begin
  380. ClassType:=TClass(Pointer(Self))
  381. end;
  382. type
  383. tmethodnamerec = packed record
  384. name : pshortstring;
  385. addr : codepointer;
  386. end;
  387. tmethodnametable = packed record
  388. count : dword;
  389. entries : packed array[0..0] of tmethodnamerec;
  390. end;
  391. pmethodnametable = ^tmethodnametable;
  392. class function TObject.MethodAddress(const name : shortstring) : codepointer;
  393. var
  394. methodtable : pmethodnametable;
  395. i : dword;
  396. ovmt : PVmt;
  397. begin
  398. ovmt:=PVmt(self);
  399. while assigned(ovmt) do
  400. begin
  401. methodtable:=pmethodnametable(ovmt^.vMethodTable);
  402. if assigned(methodtable) then
  403. begin
  404. for i:=0 to methodtable^.count-1 do
  405. if ShortCompareText(methodtable^.entries[i].name^, name)=0 then
  406. begin
  407. MethodAddress:=methodtable^.entries[i].addr;
  408. exit;
  409. end;
  410. end;
  411. ovmt := ovmt^.vParent;
  412. end;
  413. MethodAddress:=nil;
  414. end;
  415. class function TObject.MethodName(address : codepointer) : shortstring;
  416. var
  417. methodtable : pmethodnametable;
  418. i : dword;
  419. ovmt : PVmt;
  420. begin
  421. ovmt:=PVmt(self);
  422. while assigned(ovmt) do
  423. begin
  424. methodtable:=pmethodnametable(ovmt^.vMethodTable);
  425. if assigned(methodtable) then
  426. begin
  427. for i:=0 to methodtable^.count-1 do
  428. if methodtable^.entries[i].addr=address then
  429. begin
  430. MethodName:=methodtable^.entries[i].name^;
  431. exit;
  432. end;
  433. end;
  434. ovmt := ovmt^.vParent;
  435. end;
  436. MethodName:='';
  437. end;
  438. function TObject.FieldAddress(const name : shortstring) : pointer;
  439. {The following is copied to the typinfo unit. If it is changed here, change it there as well ! }
  440. type
  441. PFieldInfo = ^TFieldInfo;
  442. TFieldInfo =
  443. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  444. packed
  445. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  446. record
  447. FieldOffset: SizeUInt;
  448. ClassTypeIndex: Word;
  449. Name: ShortString;
  450. end;
  451. PFieldTable = ^TFieldTable;
  452. TFieldTable =
  453. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  454. packed
  455. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  456. record
  457. FieldCount: Word;
  458. ClassTable: Pointer;
  459. { should be array[Word] of TFieldInfo; but
  460. Elements have variant size! force at least proper alignment }
  461. Fields: array[0..0] of TFieldInfo
  462. end;
  463. var
  464. ovmt: PVmt;
  465. FieldTable: PFieldTable;
  466. FieldInfo: PFieldInfo;
  467. i: longint;
  468. begin
  469. if Length(name) > 0 then
  470. begin
  471. ovmt := PVmt(ClassType);
  472. while ovmt <> nil do
  473. begin
  474. FieldTable := PFieldTable(ovmt^.vFieldTable);
  475. if FieldTable <> nil then
  476. begin
  477. FieldInfo := @FieldTable^.Fields[0];
  478. for i := 0 to FieldTable^.FieldCount - 1 do
  479. begin
  480. if ShortCompareText(FieldInfo^.Name, name) = 0 then
  481. begin
  482. fieldaddress := Pointer(Self) + FieldInfo^.FieldOffset;
  483. exit;
  484. end;
  485. FieldInfo := PFieldInfo(PByte(@FieldInfo^.Name) + 1 + Length(FieldInfo^.Name));
  486. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  487. { align to largest field of TFieldInfo }
  488. FieldInfo := Align(FieldInfo, SizeOf(PtrUInt));
  489. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  490. end;
  491. end;
  492. { Try again with the parent class type }
  493. ovmt:=ovmt^.vParent;
  494. end;
  495. end;
  496. fieldaddress:=nil;
  497. end;
  498. function TObject.SafeCallException(exceptobject : tobject;
  499. exceptaddr : codepointer) : HResult;
  500. begin
  501. safecallexception:=E_UNEXPECTED;
  502. end;
  503. class function TObject.ClassInfo : pointer;
  504. begin
  505. ClassInfo := PVmt(Self)^.vTypeInfo;
  506. end;
  507. class function TObject.ClassName : ShortString;
  508. begin
  509. ClassName := PVmt(Self)^.vClassName^;
  510. end;
  511. class function TObject.ClassNameIs(const name : string) : boolean;
  512. begin
  513. // call to ClassName inlined here, this eliminates stack and string copying.
  514. ClassNameIs:=ShortCompareText(PVmt(Self)^.vClassName^, name) = 0;
  515. end;
  516. class function TObject.InheritsFrom(aclass : TClass) : Boolean;
  517. var
  518. vmt: PVmt;
  519. begin
  520. if assigned(aclass) then
  521. begin
  522. vmt:=PVmt(self);
  523. while assigned(vmt) and (vmt <> PVmt(aclass)) do
  524. vmt := vmt^.vParent;
  525. InheritsFrom := (vmt = PVmt(aclass));
  526. end
  527. else
  528. inheritsFrom := False;
  529. end;
  530. class function TObject.stringmessagetable : pstringmessagetable;
  531. begin
  532. stringmessagetable:=PVmt(Self)^.vMsgStrPtr;
  533. end;
  534. type
  535. tmessagehandler = procedure(var msg) of object;
  536. procedure TObject.Dispatch(var message);
  537. type
  538. {$PUSH}
  539. {$PACKRECORDS NORMAL}
  540. PMsgIntTable = ^TMsgIntTable;
  541. TMsgIntTable = record
  542. index : dword;
  543. method : codepointer;
  544. end;
  545. PMsgInt = ^TMsgInt;
  546. TMsgInt = record
  547. count : longint;
  548. msgs : array[0..0] of TMsgIntTable;
  549. end;
  550. {$POP}
  551. var
  552. index : dword;
  553. count,i : longint;
  554. msgtable : PMsgIntTable;
  555. p : PMsgInt;
  556. ovmt : PVmt;
  557. msghandler : tmessagehandler;
  558. begin
  559. index:=dword(message);
  560. ovmt := PVmt(ClassType);
  561. while assigned(ovmt) do
  562. begin
  563. // See if we have messages at all in this class.
  564. p:=PMsgInt(ovmt^.vDynamicTable);
  565. If Assigned(p) then
  566. begin
  567. msgtable:=@p^.msgs;
  568. count:=p^.count;
  569. end
  570. else
  571. Count:=0;
  572. { later, we can implement a binary search here }
  573. for i:=0 to count-1 do
  574. begin
  575. if index=msgtable[i].index then
  576. begin
  577. TMethod(msghandler).Code:=msgtable[i].method;
  578. TMethod(msghandler).Data:=self;
  579. msghandler(message);
  580. exit;
  581. end;
  582. end;
  583. ovmt:=ovmt^.vParent;
  584. end;
  585. DefaultHandler(message);
  586. end;
  587. procedure TObject.DispatchStr(var message);
  588. var
  589. name : shortstring;
  590. count,i : longint;
  591. msgstrtable : pmsgstrtable;
  592. p: pstringmessagetable;
  593. ovmt : PVmt;
  594. msghandler : tmessagehandler;
  595. begin
  596. name:=pshortstring(@message)^;
  597. ovmt:=PVmt(ClassType);
  598. while assigned(ovmt) do
  599. begin
  600. p := ovmt^.vMsgStrPtr;
  601. if (P<>Nil) and (p^.count<>0) then
  602. begin
  603. count:=p^.count;
  604. msgstrtable:=@p^.msgstrtable;
  605. end
  606. else
  607. Count:=0;
  608. { later, we can implement a binary search here }
  609. for i:=0 to count-1 do
  610. begin
  611. if name=msgstrtable[i].name^ then
  612. begin
  613. TMethod(msghandler).Code:=msgstrtable[i].method;
  614. TMethod(msghandler).Data:=self;
  615. msghandler(message);
  616. exit;
  617. end;
  618. end;
  619. ovmt:=ovmt^.vParent;
  620. end;
  621. DefaultHandlerStr(message);
  622. end;
  623. procedure TObject.DefaultHandler(var message);
  624. begin
  625. end;
  626. procedure TObject.DefaultHandlerStr(var message);
  627. begin
  628. end;
  629. procedure TObject.CleanupInstance;
  630. var
  631. vmt : PVmt;
  632. temp : pointer;
  633. begin
  634. vmt := PVmt(ClassType);
  635. while vmt<>nil do
  636. begin
  637. Temp:= vmt^.vInitTable;
  638. {$ifdef FPC_HAS_FEATURE_RTTI}
  639. { The RTTI format matches one for records, except the type is tkClass.
  640. Since RecordRTTI does not check the type, calling it yields the desired result. }
  641. if Assigned(Temp) then
  642. RecordRTTI(Self,Temp,@int_finalize);
  643. {$endif def FPC_HAS_FEATURE_RTTI}
  644. vmt:= vmt^.vParent;
  645. end;
  646. end;
  647. procedure TObject.AfterConstruction;
  648. begin
  649. end;
  650. procedure TObject.BeforeDestruction;
  651. begin
  652. end;
  653. function IsGUIDEqual(const guid1, guid2: tguid): boolean;
  654. begin
  655. IsGUIDEqual:=
  656. (guid1.D1=guid2.D1) and
  657. (PDWORD(@guid1.D2)^=PDWORD(@guid2.D2)^) and
  658. (PDWORD(@guid1.D4[0])^=PDWORD(@guid2.D4[0])^) and
  659. (PDWORD(@guid1.D4[4])^=PDWORD(@guid2.D4[4])^);
  660. end;
  661. // Use of managed types should be avoided here; implicit _Addref/_Release
  662. // will end up in unpredictable behaviour if called on CORBA interfaces.
  663. type
  664. TInterfaceGetter = procedure(out Obj) of object;
  665. TClassGetter = function: TObject of object;
  666. function GetInterfaceByEntry(Instance: pointer; IEntry: pinterfaceentry; out obj): boolean;
  667. var
  668. Getter: TMethod;
  669. begin
  670. Pointer(Obj) := nil;
  671. Getter.Data := Instance;
  672. if Assigned(IEntry) and Assigned(Instance) then
  673. begin
  674. case IEntry^.IType of
  675. etStandard:
  676. Pointer(Obj) := PByte(instance)+IEntry^.IOffset;
  677. etFieldValue, etFieldValueClass:
  678. Pointer(obj) := PPointer(PByte(Instance)+IEntry^.IOffset)^;
  679. etVirtualMethodResult:
  680. begin
  681. // IOffset is relative to the VMT, not to instance.
  682. Getter.code := PCodePointer(PByte(PPointer(Instance)^) + IEntry^.IOffset)^;
  683. TInterfaceGetter(Getter)(obj);
  684. end;
  685. etVirtualMethodClass:
  686. begin
  687. // IOffset is relative to the VMT, not to instance.
  688. Getter.code := PCodePointer(PByte(PPointer(Instance)^) + IEntry^.IOffset)^;
  689. TObject(obj) := TClassGetter(Getter)();
  690. end;
  691. etStaticMethodResult:
  692. begin
  693. Getter.code := IEntry^.IOffsetAsCodePtr;
  694. TInterfaceGetter(Getter)(obj);
  695. end;
  696. etStaticMethodClass:
  697. begin
  698. Getter.code := IEntry^.IOffsetAsCodePtr;
  699. TObject(obj) := TClassGetter(Getter)();
  700. end;
  701. end;
  702. end;
  703. result := assigned(pointer(obj));
  704. end;
  705. function TObject.GetInterface(const iid : tguid;out obj) : boolean;
  706. var
  707. IEntry: PInterfaceEntry;
  708. Instance: TObject;
  709. begin
  710. if IsGUIDEqual(IObjectInstance,iid) then
  711. begin
  712. TObject(Obj) := Self;
  713. Result := True;
  714. Exit;
  715. end;
  716. Instance := self;
  717. repeat
  718. IEntry := Instance.GetInterfaceEntry(iid);
  719. result := GetInterfaceByEntry(Instance, IEntry, obj);
  720. if (not result) or
  721. (IEntry^.IType in [etStandard, etFieldValue,
  722. etStaticMethodResult, etVirtualMethodResult]) then
  723. Break;
  724. { if interface is implemented by a class-type property or field,
  725. continue search }
  726. Instance := TObject(obj);
  727. until False;
  728. { Getter function will normally AddRef, so adding another reference here
  729. will cause memleak. }
  730. if result and (IEntry^.IType in [etStandard, etFieldValue]) then
  731. IInterface(obj)._AddRef;
  732. end;
  733. function TObject.GetInterfaceWeak(const iid : tguid; out obj) : boolean;
  734. var
  735. IEntry: PInterfaceEntry;
  736. Instance: TObject;
  737. begin
  738. if IsGUIDEqual(IObjectInstance,iid) then
  739. begin
  740. TObject(Obj) := Self;
  741. Result := True;
  742. Exit;
  743. end;
  744. Instance := self;
  745. repeat
  746. IEntry := Instance.GetInterfaceEntry(iid);
  747. result := GetInterfaceByEntry(Instance, IEntry, obj);
  748. if (not result) or
  749. (IEntry^.IType in [etStandard, etFieldValue,
  750. etStaticMethodResult, etVirtualMethodResult]) then
  751. Break;
  752. { if interface is implemented by a class-type property or field,
  753. continue search }
  754. Instance := TObject(obj);
  755. until False;
  756. { Getter function will normally AddRef, so we have to release it,
  757. else the ref is not weak. }
  758. if result and not (IEntry^.IType in [etStandard, etFieldValue]) then
  759. IInterface(obj)._Release;
  760. end;
  761. function TObject.GetInterfaceByStr(const iidstr : shortstring;out obj) : boolean;
  762. var
  763. IEntry: PInterfaceEntry;
  764. Instance: TObject;
  765. begin
  766. Instance := self;
  767. repeat
  768. IEntry := Instance.GetInterfaceEntryByStr(iidstr);
  769. result := GetInterfaceByEntry(Instance, IEntry, obj);
  770. if (not result) or
  771. (IEntry^.IType in [etStandard, etFieldValue,
  772. etStaticMethodResult, etVirtualMethodResult]) then
  773. Break;
  774. { if interface is implemented by a class-type property or field,
  775. continue search }
  776. Instance := TObject(obj);
  777. until False;
  778. { Getter function will normally AddRef, so adding another reference here
  779. will cause memleak. (com interfaces only!) }
  780. if result and Assigned(IEntry^.IID) and (IEntry^.IType in [etStandard, etFieldValue]) then
  781. IInterface(obj)._AddRef;
  782. end;
  783. function TObject.GetInterface(const iidstr : shortstring;out obj) : boolean;
  784. begin
  785. Result := GetInterfaceByStr(iidstr,obj);
  786. end;
  787. class function TObject.GetInterfaceEntry(const iid : tguid) : pinterfaceentry;
  788. var
  789. i: longint;
  790. intftable: pinterfacetable;
  791. ovmt: PVmt;
  792. begin
  793. ovmt := PVmt(Self);
  794. while Assigned(ovmt) and {$ifdef VER3_0}(ovmt^.vIntfTable <> @emptyintf){$else}Assigned(ovmt^.vIntftable){$endif} do
  795. begin
  796. intftable:=ovmt^.vIntfTable;
  797. {$ifdef VER3_0}
  798. if assigned(intftable) then
  799. {$endif VER3_0}
  800. begin
  801. for i:=0 to intftable^.EntryCount-1 do
  802. begin
  803. result:=@intftable^.Entries[i];
  804. if assigned(Result^.iid) and IsGUIDEqual(Result^.iid^,iid) then
  805. Exit;
  806. end;
  807. end;
  808. ovmt := ovmt^.vParent;
  809. end;
  810. result := nil;
  811. end;
  812. class function TObject.GetInterfaceEntryByStr(const iidstr : shortstring) : pinterfaceentry;
  813. var
  814. i: longint;
  815. intftable: pinterfacetable;
  816. ovmt: PVmt;
  817. begin
  818. ovmt := PVmt(Self);
  819. while Assigned(ovmt) and {$ifdef VER3_0}(ovmt^.vIntfTable <> @emptyintf){$else}Assigned(ovmt^.vIntfTable){$endif} do
  820. begin
  821. intftable:=ovmt^.vIntfTable;
  822. {$ifdef VER3_0}
  823. if assigned(intftable) then
  824. {$endif VER3_0}
  825. begin
  826. for i:=0 to intftable^.EntryCount-1 do
  827. begin
  828. result:=@intftable^.Entries[i];
  829. if assigned(result^.iidstr) and (result^.iidstr^ = iidstr) then
  830. Exit;
  831. end;
  832. end;
  833. ovmt := ovmt^.vParent;
  834. end;
  835. result:=nil;
  836. end;
  837. class function TObject.GetInterfaceTable : pinterfacetable;
  838. begin
  839. getinterfacetable:=PVmt(Self)^.vIntfTable;
  840. end;
  841. class function TObject.UnitName : {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}ansistring{$else FPC_HAS_FEATURE_ANSISTRINGS}shortstring{$endif FPC_HAS_FEATURE_ANSISTRINGS};
  842. {$ifdef FPC_HAS_FEATURE_RTTI}
  843. type
  844. TClassTypeInfo = {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  845. Attributes: Pointer;
  846. case TTypeKind of
  847. tkClass: (
  848. ClassType: TClass;
  849. ParentInfo: Pointer;
  850. PropCount: SmallInt;
  851. UnitName: ShortString;
  852. );
  853. { include for proper alignment }
  854. tkInt64: (
  855. Dummy: Int64;
  856. );
  857. end;
  858. PClassTypeInfo = ^TClassTypeInfo;
  859. var
  860. classtypeinfo: PClassTypeInfo;
  861. begin
  862. classtypeinfo:=ClassInfo;
  863. if Assigned(classtypeinfo) then
  864. begin
  865. // offset PTypeInfo by Length(Name) + 2 (ShortString length byte + SizeOf(Kind))
  866. inc(Pointer(classtypeinfo), PByte(Pointer(classtypeinfo)+1)^ + 2);
  867. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  868. classtypeinfo:=aligntoqword(classtypeinfo);
  869. {$endif}
  870. result:=classtypeinfo^.UnitName;
  871. end
  872. else
  873. result:='';
  874. end;
  875. {$else not FPC_HAS_FEATURE_RTTI}
  876. begin
  877. result:='';
  878. end;
  879. {$endif ndef FPC_HAS_FEATURE_RTTI}
  880. class function TObject.QualifiedClassName: {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}ansistring{$else FPC_HAS_FEATURE_ANSISTRINGS}shortstring{$endif FPC_HAS_FEATURE_ANSISTRINGS};
  881. var
  882. uname: {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}ansistring{$else FPC_HAS_FEATURE_ANSISTRINGS}shortstring{$endif FPC_HAS_FEATURE_ANSISTRINGS};
  883. begin
  884. uname := UnitName; //TODO: change 'UnitName' to 'UnitScope' as soon as RTL implement it
  885. if uname='' then
  886. result:=ClassName
  887. else
  888. result:=Concat(uname, '.', ClassName);
  889. end;
  890. function TObject.Equals(Obj: TObject) : boolean;
  891. begin
  892. result:=Obj=Self;
  893. end;
  894. function TObject.GetHashCode: PtrInt;
  895. begin
  896. result:=PtrInt(Self);
  897. end;
  898. function TObject.ToString: {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}ansistring{$else FPC_HAS_FEATURE_ANSISTRINGS}shortstring{$endif FPC_HAS_FEATURE_ANSISTRINGS};
  899. begin
  900. result:=ClassName;
  901. end;
  902. {****************************************************************************
  903. TINTERFACEDOBJECT
  904. ****************************************************************************}
  905. function TInterfacedObject.QueryInterface(
  906. {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  907. begin
  908. if getinterface(iid,obj) then
  909. result:=S_OK
  910. else
  911. result:=longint(E_NOINTERFACE);
  912. end;
  913. function TInterfacedObject._AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  914. begin
  915. _addref:=interlockedincrement(frefcount);
  916. end;
  917. function TInterfacedObject._Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  918. begin
  919. _Release:=interlockeddecrement(frefcount);
  920. if _Release=0 then
  921. begin
  922. if interlockedincrement(fdestroycount)=1 then
  923. self.destroy;
  924. end;
  925. end;
  926. destructor TInterfacedObject.Destroy;
  927. begin
  928. // We must explicitly reset. Bug ID 32353
  929. FRefCount:=0;
  930. FDestroyCount:=0;
  931. inherited Destroy;
  932. end;
  933. procedure TInterfacedObject.AfterConstruction;
  934. begin
  935. { we need to fix the refcount we forced in newinstance }
  936. { further, it must be done in a thread safe way }
  937. declocked(frefcount);
  938. end;
  939. procedure TInterfacedObject.BeforeDestruction;
  940. begin
  941. if frefcount<>0 then
  942. HandleError(204);
  943. end;
  944. class function TInterfacedObject.NewInstance : TObject;
  945. begin
  946. NewInstance:=inherited NewInstance;
  947. if NewInstance<>nil then
  948. TInterfacedObject(NewInstance).frefcount:=1;
  949. end;
  950. {****************************************************************************
  951. TAGGREGATEDOBJECT
  952. ****************************************************************************}
  953. constructor TAggregatedObject.Create(const aController: IUnknown);
  954. begin
  955. inherited Create;
  956. { do not keep a counted reference to the controller! }
  957. fcontroller := Pointer(aController);
  958. end;
  959. function TAggregatedObject.QueryInterface(
  960. {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  961. begin
  962. Result := IUnknown(fcontroller).QueryInterface(iid, obj);
  963. end;
  964. function TAggregatedObject._AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  965. begin
  966. Result := IUnknown(fcontroller)._AddRef;
  967. end;
  968. function TAggregatedObject._Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  969. begin
  970. Result := IUnknown(fcontroller)._Release;
  971. end;
  972. function TAggregatedObject.GetController : IUnknown;
  973. begin
  974. Result := IUnknown(fcontroller);
  975. end;
  976. {****************************************************************************
  977. TContainedOBJECT
  978. ****************************************************************************}
  979. function TContainedObject.QueryInterface(
  980. {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  981. begin
  982. if getinterface(iid,obj) then
  983. result:=S_OK
  984. else
  985. result:=longint(E_NOINTERFACE);
  986. end;
  987. {****************************************************************************
  988. TCustomAttribute
  989. ****************************************************************************}
  990. constructor TCustomAttribute.Create;
  991. begin
  992. inherited;
  993. end;
  994. {****************************************************************************
  995. TCustomStoredAttribute
  996. ****************************************************************************}
  997. constructor StoredAttribute.Create;
  998. begin
  999. end;
  1000. constructor StoredAttribute.Create(Const aFlag : Boolean);
  1001. begin
  1002. FFlag:=aFlag;
  1003. end;
  1004. constructor StoredAttribute.Create(Const aName : string);
  1005. begin
  1006. FName:=aName;
  1007. end;
  1008. {****************************************************************************
  1009. Exception Support
  1010. ****************************************************************************}
  1011. {$ifdef FPC_HAS_FEATURE_EXCEPTIONS}
  1012. {$if defined(FPC_WASM_NATIVE_EXCEPTIONS)}
  1013. {$I except_native.inc}
  1014. {$elseif defined(FPC_WASM_BRANCHFUL_EXCEPTIONS)}
  1015. {$I except_branchful.inc}
  1016. {$else}
  1017. {$i except.inc}
  1018. {$endif}
  1019. {$endif FPC_HAS_FEATURE_EXCEPTIONS}