objpas.inc 33 KB

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