objpas.inc 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081
  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. handleerrorframe(RuntimeErrorExitCodes[reVarDispatch],get_frame);
  15. end;
  16. procedure fpc_dispatch_by_id(Result: Pointer; const Dispatch: pointer;
  17. DispDesc: Pointer; Params: Pointer); compilerproc;
  18. type
  19. TDispProc = procedure(res : Pointer; const disp : IDispatch;desc : PDispDesc; params : Pointer);
  20. begin
  21. TDispProc(DispCallByIDProc)(Result,IDispatch(Dispatch),DispDesc,Params);
  22. end;
  23. {$endif FPC_HAS_FEATURE_VARIANTS}
  24. {****************************************************************************
  25. Internal Routines called from the Compiler
  26. ****************************************************************************}
  27. { the reverse order of the parameters make code generation easier }
  28. function fpc_do_is(aclass : tclass;aobject : tobject) : boolean;[public,alias: 'FPC_DO_IS']; compilerproc;
  29. begin
  30. fpc_do_is:=assigned(aobject) and assigned(aclass) and
  31. aobject.inheritsfrom(aclass);
  32. end;
  33. { the reverse order of the parameters make code generation easier }
  34. function fpc_do_as(aclass : tclass;aobject : tobject): tobject;[public,alias: 'FPC_DO_AS']; compilerproc;
  35. begin
  36. if assigned(aobject) and not(aobject.inheritsfrom(aclass)) then
  37. handleerrorframe(219,get_frame);
  38. result := aobject;
  39. end;
  40. { interface helpers }
  41. procedure fpc_intf_decr_ref(var i: pointer);[public,alias: 'FPC_INTF_DECR_REF']; compilerproc;
  42. begin
  43. if assigned(i) then
  44. begin
  45. IUnknown(i)._Release;
  46. i:=nil;
  47. end;
  48. end;
  49. { local declaration for intf_decr_ref for local access }
  50. procedure intf_decr_ref(var i: pointer); [external name 'FPC_INTF_DECR_REF'];
  51. procedure fpc_intf_incr_ref(i: pointer);[public,alias: 'FPC_INTF_INCR_REF']; compilerproc;
  52. begin
  53. if assigned(i) then
  54. IUnknown(i)._AddRef;
  55. end;
  56. { local declaration of intf_incr_ref for local access }
  57. procedure intf_incr_ref(i: pointer); [external name 'FPC_INTF_INCR_REF'];
  58. procedure fpc_intf_assign(var D: pointer; const S: pointer);[public,alias: 'FPC_INTF_ASSIGN']; compilerproc;
  59. begin
  60. if assigned(S) then
  61. IUnknown(S)._AddRef;
  62. if assigned(D) then
  63. IUnknown(D)._Release;
  64. D:=S;
  65. end;
  66. procedure fpc_intf_assign(var D: pointer; const s: pointer); [external name 'FPC_INTF_ASSIGN'];
  67. {procedure fpc_intf_assign_by_iid(var D: pointer; const S: pointer; const iid: TGUID);[public,alias: 'FPC_INTF_ASSIGN2']; compilerproc;
  68. var
  69. tmp : pointer;
  70. begin
  71. if assigned(S) then
  72. begin
  73. tmp:=nil;
  74. if IUnknown(S).QueryInterface(iid,tmp)<>S_OK then
  75. handleerror(219);
  76. if assigned(D) then
  77. IUnknown(D)._Release;
  78. D:=tmp;
  79. end
  80. else
  81. begin
  82. if assigned(D) then
  83. IUnknown(D)._Release;
  84. D:=nil;
  85. end;
  86. end;}
  87. function fpc_intf_is(const S: pointer; const iid: TGUID): Boolean;[public,alias: 'FPC_INTF_IS']; compilerproc;
  88. var
  89. tmpi: pointer;
  90. begin
  91. tmpi:=nil;
  92. fpc_intf_is:=Assigned(S) and (IUnknown(S).QueryInterface(iid,tmpi)=S_OK);
  93. if Assigned(tmpi) then
  94. IUnknown(tmpi)._Release;
  95. end;
  96. function fpc_intf_is_class(const S: pointer; const aclass: tclass): Boolean;[public,alias: 'FPC_INTF_IS_CLASS']; compilerproc;
  97. var
  98. tmpo: tobject;
  99. begin
  100. fpc_intf_is_class:=Assigned(S) and (IUnknown(S).QueryInterface(IObjectInstance,tmpo)=S_OK) and tmpo.InheritsFrom(aclass);
  101. end;
  102. function fpc_class_is_intf(const S: pointer; const iid: TGUID): Boolean;[public,alias: 'FPC_CLASS_IS_INTF']; compilerproc;
  103. var
  104. tmpi: pointer;
  105. tmpi2: pointer; // weak!
  106. begin
  107. tmpi:=nil;
  108. tmpi2:=nil;
  109. fpc_class_is_intf:=Assigned(S) and ((TObject(S).GetInterfaceWeak(IUnknown,tmpi2) and (IUnknown(tmpi2).QueryInterface(IID,tmpi)=S_OK)) or
  110. TObject(S).GetInterface(IID,tmpi));
  111. if Assigned(tmpi) then
  112. IUnknown(tmpi)._Release;
  113. end;
  114. function fpc_class_is_corbaintf(const S: pointer; const iid: Shortstring): Boolean;[public,alias: 'FPC_CLASS_IS_CORBAINTF']; compilerproc;
  115. begin
  116. fpc_class_is_corbaintf:=Assigned(S) and Assigned(TObject(S).GetInterfaceEntryByStr(iid));
  117. end;
  118. function fpc_intf_cast(const S: pointer; const iid: TGUID): IInterface;[public,alias: 'FPC_INTF_CAST']; compilerproc;
  119. var
  120. tmpi: pointer;
  121. begin
  122. tmpi:=nil;
  123. if Assigned(S) and (IUnknown(S).QueryInterface(iid,tmpi)=S_OK) then
  124. pointer(fpc_intf_cast):=tmpi
  125. else
  126. fpc_intf_cast:= nil;
  127. end;
  128. function fpc_intf_cast_class(const S: pointer; const aclass: tclass): pointer;[public,alias: 'FPC_INTF_CAST_CLASS']; compilerproc;
  129. var
  130. tmpo: tobject;
  131. begin
  132. if Assigned(S) and (IUnknown(S).QueryInterface(IObjectInstance,tmpo)=S_OK) and tmpo.InheritsFrom(aclass) then
  133. fpc_intf_cast_class:=tmpo
  134. else
  135. fpc_intf_cast_class:=nil;
  136. end;
  137. function fpc_class_cast_intf(const S: pointer; const iid: TGUID): IInterface;[public,alias: 'FPC_CLASS_CAST_INTF']; compilerproc;
  138. var
  139. tmpi: pointer;
  140. tmpi2: pointer; // weak!
  141. begin
  142. tmpi:=nil;
  143. tmpi2:=nil;
  144. if Assigned(S) and ((TObject(S).GetInterfaceWeak(IUnknown,tmpi2) and (IUnknown(tmpi2).QueryInterface(IID,tmpi)=S_OK)) or
  145. TObject(S).GetInterface(IID,tmpi)) then
  146. pointer(fpc_class_cast_intf):=tmpi
  147. else
  148. fpc_class_cast_intf:=nil;
  149. end;
  150. function fpc_class_cast_corbaintf(const S: pointer; const iid: Shortstring): Pointer;[public,alias: 'FPC_CLASS_CAST_CORBAINTF']; compilerproc;
  151. var
  152. tmpi: pointer;
  153. begin
  154. if Assigned(S) and TObject(S).GetInterface(iid,tmpi) then
  155. fpc_class_cast_corbaintf:=tmpi
  156. else
  157. fpc_class_cast_corbaintf:=nil;
  158. end;
  159. function fpc_intf_as(const S: pointer; const iid: TGUID): IInterface;[public,alias: 'FPC_INTF_AS']; compilerproc;
  160. var
  161. tmpi: pointer; // _AddRef before _Release
  162. begin
  163. if assigned(S) then
  164. begin
  165. tmpi:=nil;
  166. if IUnknown(S).QueryInterface(iid,tmpi)<>S_OK then
  167. handleerror(219);
  168. pointer(fpc_intf_as):=tmpi;
  169. end
  170. else
  171. fpc_intf_as:=nil;
  172. end;
  173. function fpc_intf_as_class(const S: pointer; const aclass: tclass): pointer;[public,alias: 'FPC_INTF_AS_CLASS']; compilerproc;
  174. var
  175. tmpo: tobject;
  176. begin
  177. if assigned(S) then
  178. begin
  179. if not ((IUnknown(S).QueryInterface(IObjectInstance,tmpo)=S_OK) and tmpo.inheritsfrom(aclass)) then
  180. handleerror(219);
  181. fpc_intf_as_class:=tmpo;
  182. end
  183. else
  184. fpc_intf_as_class:=nil;
  185. end;
  186. function fpc_class_as_intf(const S: pointer; const iid: TGUID): IInterface;[public,alias: 'FPC_CLASS_AS_INTF']; compilerproc;
  187. var
  188. tmpi: pointer; // _AddRef before _Release
  189. tmpi2: pointer; // weak!
  190. begin
  191. if assigned(S) then
  192. begin
  193. tmpi:=nil;
  194. tmpi2:=nil;
  195. if not ((TObject(S).GetInterfaceWeak(IUnknown,tmpi2) and (IUnknown(tmpi2).QueryInterface(IID,tmpi)=S_OK)) or TObject(S).GetInterface(IID,tmpi)) then
  196. handleerror(219);
  197. pointer(fpc_class_as_intf):=tmpi;
  198. end
  199. else
  200. fpc_class_as_intf:=nil;
  201. end;
  202. function fpc_class_as_corbaintf(const S: pointer; const iid: Shortstring): Pointer;[public,alias: 'FPC_CLASS_AS_CORBAINTF']; compilerproc;
  203. var
  204. tmpi: pointer; // _AddRef before _Release
  205. begin
  206. if assigned(S) then
  207. begin
  208. tmpi:=nil;
  209. if not TObject(S).GetInterface(iid,tmpi) then
  210. handleerror(219);
  211. fpc_class_as_corbaintf:=tmpi;
  212. end
  213. else
  214. fpc_class_as_corbaintf:=nil;
  215. end;
  216. {****************************************************************************
  217. TOBJECT
  218. ****************************************************************************}
  219. constructor TObject.Create;
  220. begin
  221. end;
  222. destructor TObject.Destroy;
  223. begin
  224. end;
  225. procedure TObject.Free;
  226. begin
  227. // the call via self avoids a warning
  228. if self<>nil then
  229. self.destroy;
  230. end;
  231. class function TObject.InstanceSize : SizeInt;
  232. begin
  233. InstanceSize := PVmt(Self)^.vInstanceSize;
  234. end;
  235. var
  236. emptyintf: ptruint; public name 'FPC_EMPTYINTF';
  237. procedure InitInterfacePointers(objclass: tclass;instance : pointer);
  238. var
  239. ovmt: PVmt;
  240. i: longint;
  241. intftable: pinterfacetable;
  242. Res: pinterfaceentry;
  243. begin
  244. ovmt := PVmt(objclass);
  245. while assigned(ovmt) and (ovmt^.vIntfTable <> @emptyintf) do
  246. begin
  247. intftable:=ovmt^.vIntfTable;
  248. if assigned(intftable) then
  249. begin
  250. i:=intftable^.EntryCount;
  251. Res:=@intftable^.Entries[0];
  252. while i>0 do begin
  253. if Res^.IType = etStandard then
  254. ppointer(@(pbyte(instance)[Res^.IOffset]))^:=
  255. pointer(Res^.VTable);
  256. inc(Res);
  257. dec(i);
  258. end;
  259. end;
  260. ovmt:=ovmt^.vParent;
  261. end;
  262. end;
  263. class function TObject.InitInstance(instance : pointer) : tobject; {$ifdef SYSTEMINLINE} inline; {$ENDIF}
  264. begin
  265. { the size is saved at offset 0 }
  266. fillchar(instance^, InstanceSize, 0);
  267. { insert VMT pointer into the new created memory area }
  268. { (in class methods self contains the VMT!) }
  269. ppointer(instance)^:=pointer(self);
  270. if PVmt(self)^.vIntfTable <> @emptyintf then
  271. InitInterfacePointers(self,instance);
  272. InitInstance:=TObject(Instance);
  273. end;
  274. class function TObject.ClassParent : tclass;
  275. begin
  276. { type of self is class of tobject => it points to the vmt }
  277. { the parent vmt is saved at offset vmtParent }
  278. classparent:=tclass(PVmt(Self)^.vParent);
  279. end;
  280. class function TObject.NewInstance : tobject;
  281. var
  282. p : pointer;
  283. begin
  284. getmem(p, InstanceSize);
  285. if p <> nil then
  286. InitInstance(p);
  287. NewInstance:=TObject(p);
  288. end;
  289. procedure TObject.FreeInstance;
  290. begin
  291. CleanupInstance;
  292. FreeMem(Pointer(Self));
  293. end;
  294. class function TObject.ClassType : TClass;
  295. begin
  296. ClassType:=TClass(Pointer(Self))
  297. end;
  298. type
  299. tmethodnamerec = packed record
  300. name : pshortstring;
  301. addr : pointer;
  302. end;
  303. tmethodnametable = packed record
  304. count : dword;
  305. entries : packed array[0..0] of tmethodnamerec;
  306. end;
  307. pmethodnametable = ^tmethodnametable;
  308. class function TObject.MethodAddress(const name : shortstring) : pointer;
  309. var
  310. methodtable : pmethodnametable;
  311. i : dword;
  312. ovmt : PVmt;
  313. begin
  314. ovmt:=PVmt(self);
  315. while assigned(ovmt) do
  316. begin
  317. methodtable:=pmethodnametable(ovmt^.vMethodTable);
  318. if assigned(methodtable) then
  319. begin
  320. for i:=0 to methodtable^.count-1 do
  321. if ShortCompareText(methodtable^.entries[i].name^, name)=0 then
  322. begin
  323. MethodAddress:=methodtable^.entries[i].addr;
  324. exit;
  325. end;
  326. end;
  327. ovmt := ovmt^.vParent;
  328. end;
  329. MethodAddress:=nil;
  330. end;
  331. class function TObject.MethodName(address : pointer) : shortstring;
  332. var
  333. methodtable : pmethodnametable;
  334. i : dword;
  335. ovmt : PVmt;
  336. begin
  337. ovmt:=PVmt(self);
  338. while assigned(ovmt) do
  339. begin
  340. methodtable:=pmethodnametable(ovmt^.vMethodTable);
  341. if assigned(methodtable) then
  342. begin
  343. for i:=0 to methodtable^.count-1 do
  344. if methodtable^.entries[i].addr=address then
  345. begin
  346. MethodName:=methodtable^.entries[i].name^;
  347. exit;
  348. end;
  349. end;
  350. ovmt := ovmt^.vParent;
  351. end;
  352. MethodName:='';
  353. end;
  354. function TObject.FieldAddress(const name : shortstring) : pointer;
  355. type
  356. PFieldInfo = ^TFieldInfo;
  357. TFieldInfo =
  358. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  359. packed
  360. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  361. record
  362. FieldOffset: PtrUInt;
  363. ClassTypeIndex: Word;
  364. Name: ShortString;
  365. end;
  366. PFieldTable = ^TFieldTable;
  367. TFieldTable =
  368. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  369. packed
  370. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  371. record
  372. FieldCount: Word;
  373. ClassTable: Pointer;
  374. { should be array[Word] of TFieldInfo; but
  375. Elements have variant size! force at least proper alignment }
  376. Fields: array[0..0] of TFieldInfo
  377. end;
  378. var
  379. ovmt: PVmt;
  380. FieldTable: PFieldTable;
  381. FieldInfo: PFieldInfo;
  382. i: longint;
  383. begin
  384. if Length(name) > 0 then
  385. begin
  386. ovmt := PVmt(ClassType);
  387. while ovmt <> nil do
  388. begin
  389. FieldTable := PFieldTable(ovmt^.vFieldTable);
  390. if FieldTable <> nil then
  391. begin
  392. FieldInfo := @FieldTable^.Fields[0];
  393. for i := 0 to FieldTable^.FieldCount - 1 do
  394. begin
  395. if ShortCompareText(FieldInfo^.Name, name) = 0 then
  396. begin
  397. fieldaddress := Pointer(Self) + FieldInfo^.FieldOffset;
  398. exit;
  399. end;
  400. FieldInfo := PFieldInfo(PByte(@FieldInfo^.Name) + 1 + Length(FieldInfo^.Name));
  401. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  402. { align to largest field of TFieldInfo }
  403. FieldInfo := Align(FieldInfo, SizeOf(PtrUInt));
  404. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  405. end;
  406. end;
  407. { Try again with the parent class type }
  408. ovmt:=ovmt^.vParent;
  409. end;
  410. end;
  411. fieldaddress:=nil;
  412. end;
  413. function TObject.SafeCallException(exceptobject : tobject;
  414. exceptaddr : pointer) : HResult;
  415. begin
  416. safecallexception:=E_UNEXPECTED;
  417. end;
  418. class function TObject.ClassInfo : pointer;
  419. begin
  420. ClassInfo := PVmt(Self)^.vTypeInfo;
  421. end;
  422. class function TObject.ClassName : ShortString;
  423. begin
  424. ClassName := PVmt(Self)^.vClassName^;
  425. end;
  426. class function TObject.ClassNameIs(const name : string) : boolean;
  427. begin
  428. // call to ClassName inlined here, this eliminates stack and string copying.
  429. ClassNameIs:=ShortCompareText(PVmt(Self)^.vClassName^, name) = 0;
  430. end;
  431. class function TObject.InheritsFrom(aclass : TClass) : Boolean;
  432. var
  433. vmt: PVmt;
  434. begin
  435. if assigned(aclass) then
  436. begin
  437. vmt:=PVmt(self);
  438. while assigned(vmt) and (vmt <> PVmt(aclass)) do
  439. vmt := vmt^.vParent;
  440. InheritsFrom := (vmt = PVmt(aclass));
  441. end
  442. else
  443. inheritsFrom := False;
  444. end;
  445. class function TObject.stringmessagetable : pstringmessagetable;
  446. begin
  447. stringmessagetable:=PVmt(Self)^.vMsgStrPtr;
  448. end;
  449. type
  450. tmessagehandler = procedure(var msg) of object;
  451. procedure TObject.Dispatch(var message);
  452. type
  453. {$PUSH}
  454. {$PACKRECORDS NORMAL}
  455. PMsgIntTable = ^TMsgIntTable;
  456. TMsgIntTable = record
  457. index : dword;
  458. method : pointer;
  459. end;
  460. PMsgInt = ^TMsgInt;
  461. TMsgInt = record
  462. count : longint;
  463. msgs : array[0..0] of TMsgIntTable;
  464. end;
  465. {$POP}
  466. var
  467. index : dword;
  468. count,i : longint;
  469. msgtable : PMsgIntTable;
  470. p : PMsgInt;
  471. ovmt : PVmt;
  472. msghandler : tmessagehandler;
  473. begin
  474. index:=dword(message);
  475. ovmt := PVmt(ClassType);
  476. while assigned(ovmt) do
  477. begin
  478. // See if we have messages at all in this class.
  479. p:=PMsgInt(ovmt^.vDynamicTable);
  480. If Assigned(p) then
  481. begin
  482. msgtable:=@p^.msgs;
  483. count:=p^.count;
  484. end
  485. else
  486. Count:=0;
  487. { later, we can implement a binary search here }
  488. for i:=0 to count-1 do
  489. begin
  490. if index=msgtable[i].index then
  491. begin
  492. TMethod(msghandler).Code:=msgtable[i].method;
  493. TMethod(msghandler).Data:=self;
  494. msghandler(message);
  495. exit;
  496. end;
  497. end;
  498. ovmt:=ovmt^.vParent;
  499. end;
  500. DefaultHandler(message);
  501. end;
  502. procedure TObject.DispatchStr(var message);
  503. type
  504. PSizeUInt = ^SizeUInt;
  505. var
  506. name : shortstring;
  507. count,i : longint;
  508. msgstrtable : pmsgstrtable;
  509. p: pstringmessagetable;
  510. ovmt : PVmt;
  511. msghandler : tmessagehandler;
  512. begin
  513. name:=pshortstring(@message)^;
  514. ovmt:=PVmt(ClassType);
  515. while assigned(ovmt) do
  516. begin
  517. p := ovmt^.vMsgStrPtr;
  518. if (P<>Nil) and (p^.count<>0) then
  519. begin
  520. count:=p^.count;
  521. msgstrtable:=@p^.msgstrtable;
  522. end
  523. else
  524. Count:=0;
  525. { later, we can implement a binary search here }
  526. for i:=0 to count-1 do
  527. begin
  528. if name=msgstrtable[i].name^ then
  529. begin
  530. TMethod(msghandler).Code:=msgstrtable[i].method;
  531. TMethod(msghandler).Data:=self;
  532. msghandler(message);
  533. exit;
  534. end;
  535. end;
  536. ovmt:=ovmt^.vParent;
  537. end;
  538. DefaultHandlerStr(message);
  539. end;
  540. procedure TObject.DefaultHandler(var message);
  541. begin
  542. end;
  543. procedure TObject.DefaultHandlerStr(var message);
  544. begin
  545. end;
  546. procedure TObject.CleanupInstance;
  547. Type
  548. TRecElem = packed Record
  549. Info : Pointer;
  550. Offset : Longint;
  551. end;
  552. {$ifdef CPU16}
  553. TRecElemArray = packed array[1..Maxint div sizeof(TRecElem)-1] of TRecElem;
  554. {$else CPU16}
  555. TRecElemArray = packed array[1..Maxint] of TRecElem;
  556. {$endif CPU16}
  557. PRecRec = ^TRecRec;
  558. TRecRec = record
  559. Size,Count : Longint;
  560. Elements : TRecElemArray;
  561. end;
  562. var
  563. vmt : PVmt;
  564. temp : pbyte;
  565. count,
  566. i : longint;
  567. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  568. recelem : TRecElem;
  569. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  570. begin
  571. vmt := PVmt(ClassType);
  572. while vmt<>nil do
  573. begin
  574. { This need to be included here, because Finalize()
  575. has should support for tkClass }
  576. Temp:= vmt^.vInitTable;
  577. if Assigned(Temp) then
  578. begin
  579. inc(Temp);
  580. I:=Temp^;
  581. inc(temp,I+1); // skip name string;
  582. temp:=aligntoptr(temp);
  583. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  584. move(PRecRec(Temp)^.Count,Count,sizeof(Count));
  585. {$else FPC_REQUIRES_PROPER_ALIGNMENT}
  586. Count:=PRecRec(Temp)^.Count; // get element Count
  587. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  588. For I:=1 to count do
  589. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  590. begin
  591. move(PRecRec(Temp)^.elements[I],RecElem,sizeof(RecElem));
  592. With RecElem do
  593. int_Finalize (pointer(self)+Offset,Info);
  594. end;
  595. {$else FPC_REQUIRES_PROPER_ALIGNMENT}
  596. With PRecRec(Temp)^.elements[I] do
  597. int_Finalize (pointer(self)+Offset,Info);
  598. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  599. end;
  600. vmt:= vmt^.vParent;
  601. end;
  602. end;
  603. procedure TObject.AfterConstruction;
  604. begin
  605. end;
  606. procedure TObject.BeforeDestruction;
  607. begin
  608. end;
  609. function IsGUIDEqual(const guid1, guid2: tguid): boolean;
  610. begin
  611. IsGUIDEqual:=
  612. (guid1.D1=guid2.D1) and
  613. (PDWORD(@guid1.D2)^=PDWORD(@guid2.D2)^) and
  614. (PDWORD(@guid1.D4[0])^=PDWORD(@guid2.D4[0])^) and
  615. (PDWORD(@guid1.D4[4])^=PDWORD(@guid2.D4[4])^);
  616. end;
  617. // Use of managed types should be avoided here; implicit _Addref/_Release
  618. // will end up in unpredictable behaviour if called on CORBA interfaces.
  619. type
  620. TInterfaceGetter = procedure(out Obj) of object;
  621. TClassGetter = function: TObject of object;
  622. function GetInterfaceByEntry(Instance: pointer; IEntry: pinterfaceentry; out obj): boolean;
  623. var
  624. Getter: TMethod;
  625. begin
  626. Pointer(Obj) := nil;
  627. Getter.Data := Instance;
  628. if Assigned(IEntry) and Assigned(Instance) then
  629. begin
  630. case IEntry^.IType of
  631. etStandard:
  632. Pointer(Obj) := PByte(instance)+IEntry^.IOffset;
  633. etFieldValue, etFieldValueClass:
  634. Pointer(obj) := PPointer(PByte(Instance)+IEntry^.IOffset)^;
  635. etVirtualMethodResult:
  636. begin
  637. // IOffset is relative to the VMT, not to instance.
  638. Getter.code := PPointer(PByte(PPointer(Instance)^) + IEntry^.IOffset)^;
  639. TInterfaceGetter(Getter)(obj);
  640. end;
  641. etVirtualMethodClass:
  642. begin
  643. // IOffset is relative to the VMT, not to instance.
  644. Getter.code := PPointer(PByte(PPointer(Instance)^) + IEntry^.IOffset)^;
  645. TObject(obj) := TClassGetter(Getter)();
  646. end;
  647. etStaticMethodResult:
  648. begin
  649. Getter.code := Pointer(IEntry^.IOffset);
  650. TInterfaceGetter(Getter)(obj);
  651. end;
  652. etStaticMethodClass:
  653. begin
  654. Getter.code := Pointer(IEntry^.IOffset);
  655. TObject(obj) := TClassGetter(Getter)();
  656. end;
  657. end;
  658. end;
  659. result := assigned(pointer(obj));
  660. end;
  661. function TObject.GetInterface(const iid : tguid;out obj) : boolean;
  662. var
  663. IEntry: PInterfaceEntry;
  664. Instance: TObject;
  665. begin
  666. if IsGUIDEqual(IObjectInstance,iid) then
  667. begin
  668. TObject(Obj) := Self;
  669. Result := True;
  670. Exit;
  671. end;
  672. Instance := self;
  673. repeat
  674. IEntry := Instance.GetInterfaceEntry(iid);
  675. result := GetInterfaceByEntry(Instance, IEntry, obj);
  676. if (not result) or
  677. (IEntry^.IType in [etStandard, etFieldValue,
  678. etStaticMethodResult, etVirtualMethodResult]) then
  679. Break;
  680. { if interface is implemented by a class-type property or field,
  681. continue search }
  682. Instance := TObject(obj);
  683. until False;
  684. { Getter function will normally AddRef, so adding another reference here
  685. will cause memleak. }
  686. if result and (IEntry^.IType in [etStandard, etFieldValue]) then
  687. IInterface(obj)._AddRef;
  688. end;
  689. function TObject.GetInterfaceWeak(const iid : tguid; out obj) : boolean;
  690. var
  691. IEntry: PInterfaceEntry;
  692. Instance: TObject;
  693. begin
  694. if IsGUIDEqual(IObjectInstance,iid) then
  695. begin
  696. TObject(Obj) := Self;
  697. Result := True;
  698. Exit;
  699. end;
  700. Instance := self;
  701. repeat
  702. IEntry := Instance.GetInterfaceEntry(iid);
  703. result := GetInterfaceByEntry(Instance, IEntry, obj);
  704. if (not result) or
  705. (IEntry^.IType in [etStandard, etFieldValue,
  706. etStaticMethodResult, etVirtualMethodResult]) then
  707. Break;
  708. { if interface is implemented by a class-type property or field,
  709. continue search }
  710. Instance := TObject(obj);
  711. until False;
  712. { Getter function will normally AddRef, so we have to release it,
  713. else the ref is not weak. }
  714. if result and not (IEntry^.IType in [etStandard, etFieldValue]) then
  715. IInterface(obj)._Release;
  716. end;
  717. function TObject.GetInterfaceByStr(const iidstr : shortstring;out obj) : boolean;
  718. var
  719. IEntry: PInterfaceEntry;
  720. Instance: TObject;
  721. begin
  722. Instance := self;
  723. repeat
  724. IEntry := Instance.GetInterfaceEntryByStr(iidstr);
  725. result := GetInterfaceByEntry(Instance, IEntry, obj);
  726. if (not result) or
  727. (IEntry^.IType in [etStandard, etFieldValue,
  728. etStaticMethodResult, etVirtualMethodResult]) then
  729. Break;
  730. { if interface is implemented by a class-type property or field,
  731. continue search }
  732. Instance := TObject(obj);
  733. until False;
  734. { Getter function will normally AddRef, so adding another reference here
  735. will cause memleak. (com interfaces only!) }
  736. if result and Assigned(IEntry^.IID) and (IEntry^.IType in [etStandard, etFieldValue]) then
  737. IInterface(obj)._AddRef;
  738. end;
  739. function TObject.GetInterface(const iidstr : shortstring;out obj) : boolean;
  740. begin
  741. Result := GetInterfaceByStr(iidstr,obj);
  742. end;
  743. class function TObject.GetInterfaceEntry(const iid : tguid) : pinterfaceentry;
  744. var
  745. i: longint;
  746. intftable: pinterfacetable;
  747. ovmt: PVmt;
  748. begin
  749. ovmt := PVmt(Self);
  750. while Assigned(ovmt) and (ovmt^.vIntfTable <> @emptyintf) do
  751. begin
  752. intftable:=ovmt^.vIntfTable;
  753. if assigned(intftable) then
  754. begin
  755. for i:=0 to intftable^.EntryCount-1 do
  756. begin
  757. result:=@intftable^.Entries[i];
  758. if assigned(Result^.iid) and IsGUIDEqual(Result^.iid^,iid) then
  759. Exit;
  760. end;
  761. end;
  762. ovmt := ovmt^.vParent;
  763. end;
  764. result := nil;
  765. end;
  766. class function TObject.GetInterfaceEntryByStr(const iidstr : shortstring) : pinterfaceentry;
  767. var
  768. i: longint;
  769. intftable: pinterfacetable;
  770. ovmt: PVmt;
  771. begin
  772. ovmt := PVmt(Self);
  773. while Assigned(ovmt) and (ovmt^.vIntfTable <> @emptyintf) do
  774. begin
  775. intftable:=ovmt^.vIntfTable;
  776. if assigned(intftable) then
  777. begin
  778. for i:=0 to intftable^.EntryCount-1 do
  779. begin
  780. result:=@intftable^.Entries[i];
  781. if assigned(result^.iidstr) and (result^.iidstr^ = iidstr) then
  782. Exit;
  783. end;
  784. end;
  785. ovmt := ovmt^.vParent;
  786. end;
  787. result:=nil;
  788. end;
  789. class function TObject.GetInterfaceTable : pinterfacetable;
  790. begin
  791. getinterfacetable:=PVmt(Self)^.vIntfTable;
  792. end;
  793. class function TObject.UnitName : ansistring;
  794. type
  795. // from the typinfo unit
  796. TClassTypeInfo = {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  797. ClassType: TClass;
  798. ParentInfo: Pointer;
  799. PropCount: SmallInt;
  800. UnitName: ShortString;
  801. end;
  802. PClassTypeInfo = ^TClassTypeInfo;
  803. var
  804. classtypeinfo: PClassTypeInfo;
  805. begin
  806. classtypeinfo:=ClassInfo;
  807. if Assigned(classtypeinfo) then
  808. begin
  809. // offset PTypeInfo by Length(Name) + 2 (ShortString length byte + SizeOf(Kind))
  810. inc(Pointer(classtypeinfo), PByte(Pointer(classtypeinfo)+1)^ + 2);
  811. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  812. classtypeinfo:=align(classtypeinfo,sizeof(classtypeinfo));
  813. {$endif}
  814. result:=classtypeinfo^.UnitName;
  815. end
  816. else
  817. result:='';
  818. end;
  819. function TObject.Equals(Obj: TObject) : boolean;
  820. begin
  821. result:=Obj=Self;
  822. end;
  823. function TObject.GetHashCode: PtrInt;
  824. begin
  825. result:=PtrInt(Self);
  826. end;
  827. function TObject.ToString: ansistring;
  828. begin
  829. result:=ClassName;
  830. end;
  831. {****************************************************************************
  832. TINTERFACEDOBJECT
  833. ****************************************************************************}
  834. function TInterfacedObject.QueryInterface(
  835. {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  836. begin
  837. if getinterface(iid,obj) then
  838. result:=S_OK
  839. else
  840. result:=longint(E_NOINTERFACE);
  841. end;
  842. function TInterfacedObject._AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  843. begin
  844. _addref:=interlockedincrement(frefcount);
  845. end;
  846. function TInterfacedObject._Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  847. begin
  848. _Release:=interlockeddecrement(frefcount);
  849. if _Release=0 then
  850. self.destroy;
  851. end;
  852. procedure TInterfacedObject.AfterConstruction;
  853. begin
  854. { we need to fix the refcount we forced in newinstance }
  855. { further, it must be done in a thread safe way }
  856. declocked(frefcount);
  857. end;
  858. procedure TInterfacedObject.BeforeDestruction;
  859. begin
  860. if frefcount<>0 then
  861. HandleError(204);
  862. end;
  863. class function TInterfacedObject.NewInstance : TObject;
  864. begin
  865. NewInstance:=inherited NewInstance;
  866. if NewInstance<>nil then
  867. TInterfacedObject(NewInstance).frefcount:=1;
  868. end;
  869. {****************************************************************************
  870. TAGGREGATEDOBJECT
  871. ****************************************************************************}
  872. constructor TAggregatedObject.Create(const aController: IUnknown);
  873. begin
  874. inherited Create;
  875. { do not keep a counted reference to the controller! }
  876. fcontroller := Pointer(aController);
  877. end;
  878. function TAggregatedObject.QueryInterface(
  879. {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  880. begin
  881. Result := IUnknown(fcontroller).QueryInterface(iid, obj);
  882. end;
  883. function TAggregatedObject._AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  884. begin
  885. Result := IUnknown(fcontroller)._AddRef;
  886. end;
  887. function TAggregatedObject._Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  888. begin
  889. Result := IUnknown(fcontroller)._Release;
  890. end;
  891. function TAggregatedObject.GetController : IUnknown;
  892. begin
  893. Result := IUnknown(fcontroller);
  894. end;
  895. {****************************************************************************
  896. TContainedOBJECT
  897. ****************************************************************************}
  898. function TContainedObject.QueryInterface(
  899. {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  900. begin
  901. if getinterface(iid,obj) then
  902. result:=S_OK
  903. else
  904. result:=longint(E_NOINTERFACE);
  905. end;
  906. {****************************************************************************
  907. Exception Support
  908. ****************************************************************************}
  909. {$ifdef FPC_HAS_FEATURE_EXCEPTIONS}
  910. {$i except.inc}
  911. {$endif FPC_HAS_FEATURE_EXCEPTIONS}