objpas.inc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by the Free Pascal development team
  5. This unit makes Free Pascal as much as possible Delphi compatible
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {****************************************************************************
  13. Internal Routines called from the Compiler
  14. ****************************************************************************}
  15. { the reverse order of the parameters make code generation easier }
  16. function fpc_do_is(aclass : tclass;aobject : tobject) : boolean;[public,alias: 'FPC_DO_IS']; {$ifdef hascompilerproc} compilerproc; {$endif}
  17. begin
  18. fpc_do_is:=assigned(aobject) and assigned(aclass) and
  19. aobject.inheritsfrom(aclass);
  20. end;
  21. { the reverse order of the parameters make code generation easier }
  22. function fpc_do_as(aclass : tclass;aobject : tobject): tobject;[public,alias: 'FPC_DO_AS']; {$ifdef hascompilerproc} compilerproc; {$endif}
  23. begin
  24. if assigned(aobject) and not(aobject.inheritsfrom(aclass)) then
  25. handleerrorframe(219,get_frame);
  26. result := aobject;
  27. end;
  28. {$ifndef HASINTF}
  29. { dummies for make cycle with 1.0.x }
  30. procedure fpc_intf_decr_ref(var i: pointer);saveregisters;[public,alias: 'FPC_INTF_DECR_REF']; {$ifdef hascompilerproc} compilerproc; {$endif}
  31. begin
  32. end;
  33. procedure fpc_intf_incr_ref(i: pointer);saveregisters;[public,alias: 'FPC_INTF_INCR_REF']; {$ifdef hascompilerproc} compilerproc; {$endif}
  34. begin
  35. end;
  36. procedure fpc_intf_assign(var D: pointer; const S: pointer);[public,alias: 'FPC_INTF_ASSIGN']; {$ifdef hascompilerproc} compilerproc; {$endif}
  37. begin
  38. end;
  39. function fpc_intf_as(const S: pointer; const iid: TGUID): pointer;[public,alias: 'FPC_INTF_AS']; {$ifdef hascompilerproc} compilerproc; {$endif}
  40. begin
  41. end;
  42. function fpc_class_as_intf(const S: pointer; const iid: TGUID): pointer;[public,alias: 'FPC_CLASS_AS_INTF']; {$ifdef hascompilerproc} compilerproc; {$endif}
  43. begin
  44. end;
  45. {$else HASINTF}
  46. { interface helpers }
  47. procedure fpc_intf_decr_ref(var i: pointer);saveregisters;[public,alias: 'FPC_INTF_DECR_REF']; {$ifdef hascompilerproc} compilerproc; {$endif}
  48. begin
  49. if assigned(i) then
  50. IUnknown(i)._Release;
  51. i:=nil;
  52. end;
  53. {$ifdef hascompilerproc}
  54. { local declaration for intf_decr_ref for local access }
  55. procedure intf_decr_ref(var i: pointer);saveregisters; [external name 'FPC_INTF_DECR_REF'];
  56. {$endif hascompilerproc}
  57. procedure fpc_intf_incr_ref(i: pointer);saveregisters;[public,alias: 'FPC_INTF_INCR_REF']; {$ifdef hascompilerproc} compilerproc; {$endif}
  58. begin
  59. if assigned(i) then
  60. IUnknown(i)._AddRef;
  61. end;
  62. {$ifdef hascompilerproc}
  63. { local declaration of intf_incr_ref for local access }
  64. procedure intf_incr_ref(i: pointer);saveregisters; [external name 'FPC_INTF_INCR_REF'];
  65. {$endif hascompilerproc}
  66. procedure fpc_intf_assign(var D: pointer; const S: pointer);[public,alias: 'FPC_INTF_ASSIGN']; {$ifdef hascompilerproc} compilerproc; {$endif}
  67. begin
  68. if assigned(S) then
  69. IUnknown(S)._AddRef;
  70. if assigned(D) then
  71. IUnknown(D)._Release;
  72. D:=S;
  73. end;
  74. function fpc_intf_as(const S: pointer; const iid: TGUID): pointer;[public,alias: 'FPC_INTF_AS']; {$ifdef hascompilerproc} compilerproc; {$endif}
  75. const
  76. S_OK = 0;
  77. var
  78. tmpi: pointer; // _AddRef before _Release
  79. begin
  80. if assigned(S) then
  81. begin
  82. if IUnknown(S).QueryInterface(iid,tmpi)<>S_OK then
  83. handleerror(219);
  84. fpc_intf_as:=tmpi;
  85. end
  86. else
  87. fpc_intf_as:=nil;
  88. end;
  89. function fpc_class_as_intf(const S: pointer; const iid: TGUID): pointer;[public,alias: 'FPC_CLASS_AS_INTF']; {$ifdef hascompilerproc} compilerproc; {$endif}
  90. const
  91. S_OK = 0;
  92. var
  93. tmpi: pointer; // _AddRef before _Release
  94. begin
  95. if assigned(S) then
  96. begin
  97. if not TObject(S).GetInterface(iid,tmpi) then
  98. handleerror(219);
  99. fpc_class_as_intf:=tmpi;
  100. end
  101. else
  102. fpc_class_as_intf:=nil;
  103. end;
  104. {$endif HASINTF}
  105. {****************************************************************************
  106. TOBJECT
  107. ****************************************************************************}
  108. constructor TObject.Create;
  109. begin
  110. end;
  111. destructor TObject.Destroy;
  112. begin
  113. end;
  114. procedure TObject.Free;
  115. begin
  116. // the call via self avoids a warning
  117. if self<>nil then
  118. self.destroy;
  119. end;
  120. class function TObject.InstanceSize : LongInt;
  121. type
  122. plongint = ^longint;
  123. begin
  124. { type of self is class of tobject => it points to the vmt }
  125. { the size is saved at offset 0 }
  126. InstanceSize:=plongint(self)^;
  127. end;
  128. procedure InitInterfacePointers(objclass: tclass;instance : pointer);
  129. {$ifdef HASINTF}
  130. var
  131. intftable : pinterfacetable;
  132. i : longint;
  133. begin
  134. while assigned(objclass) do
  135. begin
  136. intftable:=objclass.getinterfacetable;
  137. if assigned(intftable) then
  138. for i:=0 to intftable^.EntryCount-1 do
  139. ppointer(@(PChar(instance)[intftable^.Entries[i].IOffset]))^:=
  140. pointer(intftable^.Entries[i].VTable);
  141. objclass:=pclass(pointer(objclass)+vmtParent)^;
  142. end;
  143. end;
  144. {$else HASINTF}
  145. begin
  146. end;
  147. {$endif HASINTF}
  148. class function TObject.InitInstance(instance : pointer) : tobject;
  149. begin
  150. fillchar(instance^,self.instancesize,0);
  151. { insert VMT pointer into the new created memory area }
  152. { (in class methods self contains the VMT!) }
  153. ppointer(instance)^:=pointer(self);
  154. {$ifdef HASINTF}
  155. InitInterfacePointers(self,instance);
  156. {$endif HASINTF}
  157. InitInstance:=TObject(Instance);
  158. end;
  159. class function TObject.ClassParent : tclass;
  160. begin
  161. { type of self is class of tobject => it points to the vmt }
  162. { the parent vmt is saved at offset vmtParent }
  163. classparent:=pclass(pointer(self)+vmtParent)^;
  164. end;
  165. class function TObject.NewInstance : tobject;
  166. var
  167. p : pointer;
  168. begin
  169. getmem(p,instancesize);
  170. if p <> nil then
  171. InitInstance(p);
  172. NewInstance:=TObject(p);
  173. end;
  174. procedure TObject.FreeInstance;
  175. begin
  176. CleanupInstance;
  177. FreeMem(Pointer(Self));
  178. end;
  179. function TObject.ClassType : TClass;
  180. begin
  181. ClassType:=TClass(Pointer(Self)^)
  182. end;
  183. type
  184. tmethodnamerec = packed record
  185. name : pshortstring;
  186. addr : pointer;
  187. end;
  188. tmethodnametable = packed record
  189. count : dword;
  190. entries : packed array[0..0] of tmethodnamerec;
  191. end;
  192. pmethodnametable = ^tmethodnametable;
  193. class function TObject.MethodAddress(const name : shortstring) : pointer;
  194. var
  195. UName : ShortString;
  196. methodtable : pmethodnametable;
  197. i : dword;
  198. vmt : tclass;
  199. begin
  200. UName := UpCase(name);
  201. vmt:=self;
  202. while assigned(vmt) do
  203. begin
  204. methodtable:=pmethodnametable((Pointer(vmt)+vmtMethodTable)^);
  205. if assigned(methodtable) then
  206. begin
  207. for i:=0 to methodtable^.count-1 do
  208. if UpCase(methodtable^.entries[i].name^)=UName then
  209. begin
  210. MethodAddress:=methodtable^.entries[i].addr;
  211. exit;
  212. end;
  213. end;
  214. vmt:=pclass(pointer(vmt)+vmtParent)^;
  215. end;
  216. MethodAddress:=nil;
  217. end;
  218. class function TObject.MethodName(address : pointer) : shortstring;
  219. var
  220. methodtable : pmethodnametable;
  221. i : dword;
  222. vmt : tclass;
  223. begin
  224. vmt:=self;
  225. while assigned(vmt) do
  226. begin
  227. methodtable:=pmethodnametable((Pointer(vmt)+vmtMethodTable)^);
  228. if assigned(methodtable) then
  229. begin
  230. for i:=0 to methodtable^.count-1 do
  231. if methodtable^.entries[i].addr=address then
  232. begin
  233. MethodName:=methodtable^.entries[i].name^;
  234. exit;
  235. end;
  236. end;
  237. vmt:=pclass(pointer(vmt)+vmtParent)^;
  238. end;
  239. MethodName:='';
  240. end;
  241. function TObject.FieldAddress(const name : shortstring) : pointer;
  242. type
  243. PFieldInfo = ^TFieldInfo;
  244. TFieldInfo = packed record
  245. FieldOffset: LongWord;
  246. ClassTypeIndex: Word;
  247. Name: ShortString;
  248. end;
  249. PFieldTable = ^TFieldTable;
  250. TFieldTable = packed record
  251. FieldCount: Word;
  252. ClassTable: Pointer;
  253. { Fields: array[Word] of TFieldInfo; Elements have variant size! }
  254. end;
  255. var
  256. UName: ShortString;
  257. CurClassType: TClass;
  258. FieldTable: PFieldTable;
  259. FieldInfo: PFieldInfo;
  260. i: Integer;
  261. begin
  262. if Length(name) > 0 then
  263. begin
  264. UName := UpCase(name);
  265. CurClassType := ClassType;
  266. while CurClassType <> nil do
  267. begin
  268. FieldTable := PFieldTable((Pointer(CurClassType) + vmtFieldTable)^);
  269. if FieldTable <> nil then
  270. begin
  271. FieldInfo := PFieldInfo(Pointer(FieldTable) + 6);
  272. for i := 0 to FieldTable^.FieldCount - 1 do
  273. begin
  274. if UpCase(FieldInfo^.Name) = UName then
  275. begin
  276. fieldaddress := Pointer(Self) + FieldInfo^.FieldOffset;
  277. exit;
  278. end;
  279. Inc(Pointer(FieldInfo), 7 + Length(FieldInfo^.Name));
  280. end;
  281. end;
  282. { Try again with the parent class type }
  283. CurClassType:=pclass(pointer(CurClassType)+vmtParent)^;
  284. end;
  285. end;
  286. fieldaddress:=nil;
  287. end;
  288. function TObject.SafeCallException(exceptobject : tobject;
  289. exceptaddr : pointer) : longint;
  290. begin
  291. safecallexception:=0;
  292. end;
  293. class function TObject.ClassInfo : pointer;
  294. begin
  295. ClassInfo:=ppointer(Pointer(self)+vmtTypeInfo)^;
  296. end;
  297. class function TObject.ClassName : ShortString;
  298. begin
  299. ClassName:=PShortString((Pointer(Self)+vmtClassName)^)^;
  300. end;
  301. class function TObject.ClassNameIs(const name : string) : boolean;
  302. begin
  303. ClassNameIs:=Upcase(ClassName)=Upcase(name);
  304. end;
  305. class function TObject.InheritsFrom(aclass : TClass) : Boolean;
  306. var
  307. vmt : tclass;
  308. begin
  309. vmt:=self;
  310. while assigned(vmt) do
  311. begin
  312. if vmt=aclass then
  313. begin
  314. InheritsFrom:=true;
  315. exit;
  316. end;
  317. vmt:=pclass(pointer(vmt)+vmtParent)^;
  318. end;
  319. InheritsFrom:=false;
  320. end;
  321. class function TObject.stringmessagetable : pstringmessagetable;
  322. type
  323. pdword = ^dword;
  324. begin
  325. stringmessagetable:=pstringmessagetable((pointer(Self)+vmtMsgStrPtr)^);
  326. end;
  327. type
  328. tmessagehandler = procedure(var msg) of object;
  329. tmessagehandlerrec = packed record
  330. proc : pointer;
  331. obj : pointer;
  332. end;
  333. procedure TObject.Dispatch(var message);
  334. type
  335. tmsgtable = record
  336. index : dword;
  337. method : pointer;
  338. end;
  339. pmsgtable = ^tmsgtable;
  340. pdword = ^dword;
  341. var
  342. index : dword;
  343. count,i : longint;
  344. msgtable : pmsgtable;
  345. p : pointer;
  346. vmt : tclass;
  347. msghandler : tmessagehandler;
  348. begin
  349. index:=dword(message);
  350. vmt:=ClassType;
  351. while assigned(vmt) do
  352. begin
  353. // See if we have messages at all in this class.
  354. p:=pointer(vmt)+vmtDynamicTable;
  355. If Assigned(p) and (Pdword(p)^<>0) then
  356. begin
  357. msgtable:=pmsgtable(pdword(P)^+4);
  358. count:=pdword(pdword(P)^)^;
  359. end
  360. else
  361. Count:=0;
  362. { later, we can implement a binary search here }
  363. for i:=0 to count-1 do
  364. begin
  365. if index=msgtable[i].index then
  366. begin
  367. p:=msgtable[i].method;
  368. tmessagehandlerrec(msghandler).proc:=p;
  369. tmessagehandlerrec(msghandler).obj:=self;
  370. msghandler(message);
  371. exit;
  372. end;
  373. end;
  374. vmt:=pclass(pointer(vmt)+vmtParent)^;
  375. end;
  376. DefaultHandler(message);
  377. end;
  378. procedure TObject.DispatchStr(var message);
  379. type
  380. pdword = ^dword;
  381. var
  382. name : shortstring;
  383. count,i : longint;
  384. msgstrtable : pmsgstrtable;
  385. p : pointer;
  386. vmt : tclass;
  387. msghandler : tmessagehandler;
  388. begin
  389. name:=pshortstring(@message)^;
  390. vmt:=ClassType;
  391. while assigned(vmt) do
  392. begin
  393. p:=(pointer(vmt)+vmtMsgStrPtr);
  394. If (P<>Nil) and (PDWord(P)^<>0) then
  395. begin
  396. count:=pdword(pdword(p)^)^;
  397. msgstrtable:=pmsgstrtable(pdword(P)^+4);
  398. end
  399. else
  400. Count:=0;
  401. { later, we can implement a binary search here }
  402. for i:=0 to count-1 do
  403. begin
  404. if name=msgstrtable[i].name^ then
  405. begin
  406. p:=msgstrtable[i].method;
  407. tmessagehandlerrec(msghandler).proc:=p;
  408. tmessagehandlerrec(msghandler).obj:=self;
  409. msghandler(message);
  410. exit;
  411. end;
  412. end;
  413. vmt:=pclass(pointer(vmt)+vmtParent)^;
  414. end;
  415. DefaultHandlerStr(message);
  416. end;
  417. procedure TObject.DefaultHandler(var message);
  418. begin
  419. end;
  420. procedure TObject.DefaultHandlerStr(var message);
  421. begin
  422. end;
  423. procedure TObject.CleanupInstance;
  424. var
  425. vmt : tclass;
  426. begin
  427. vmt:=ClassType;
  428. while vmt<>nil do
  429. begin
  430. if Assigned(Pointer((Pointer(vmt)+vmtInitTable)^)) then
  431. int_finalize(Pointer(Self),Pointer((Pointer(vmt)+vmtInitTable)^));
  432. vmt:=pclass(pointer(vmt)+vmtParent)^;
  433. end;
  434. end;
  435. procedure TObject.AfterConstruction;
  436. begin
  437. end;
  438. procedure TObject.BeforeDestruction;
  439. begin
  440. end;
  441. {$ifdef HASINTF}
  442. function IsGUIDEqual(const guid1, guid2: tguid): boolean;
  443. begin
  444. IsGUIDEqual:=
  445. (guid1.D1=guid2.D1) and
  446. (PDWORD(@guid1.D2)^=PDWORD(@guid2.D2)^) and
  447. (PDWORD(@guid1.D4[0])^=PDWORD(@guid2.D4[0])^) and
  448. (PDWORD(@guid1.D4[4])^=PDWORD(@guid2.D4[4])^);
  449. end;
  450. function TObject.getinterface(const iid : tguid;out obj) : boolean;
  451. var
  452. IEntry: pinterfaceentry;
  453. begin
  454. IEntry:=getinterfaceentry(iid);
  455. if Assigned(IEntry) then begin
  456. PDWORD(@obj)^:=DWORD(PDWORD(Self))+IEntry^.IOffset;
  457. intf_incr_ref(pointer(obj)); { it must be an com interface }
  458. getinterface:=True;
  459. end
  460. else begin
  461. PDWORD(@Obj)^:=0;
  462. getinterface:=False;
  463. end;
  464. end;
  465. function TObject.getinterfacebystr(const iidstr : string;out obj) : boolean;
  466. var
  467. IEntry: pinterfaceentry;
  468. begin
  469. IEntry:=getinterfaceentrybystr(iidstr);
  470. if Assigned(IEntry) then begin
  471. PDWORD(@obj)^:=DWORD(PDWORD(Self))+IEntry^.IOffset;
  472. if Assigned(IEntry^.iid) then { for Com interfaces }
  473. intf_incr_ref(pointer(obj));
  474. getinterfacebystr:=True;
  475. end
  476. else begin
  477. PDWORD(@Obj)^:=0;
  478. getinterfacebystr:=False;
  479. end;
  480. end;
  481. class function TObject.getinterfaceentry(const iid : tguid) : pinterfaceentry;
  482. var
  483. i: integer;
  484. intftable: pinterfacetable;
  485. Res: pinterfaceentry;
  486. begin
  487. getinterfaceentry:=nil;
  488. intftable:=getinterfacetable;
  489. if assigned(intftable) then begin
  490. i:=intftable^.EntryCount;
  491. Res:=@intftable^.Entries[0];
  492. while (i>0) and
  493. not (assigned(Res^.iid) and IsGUIDEqual(Res^.iid^,iid)) do begin
  494. inc(Res);
  495. dec(i);
  496. end;
  497. if (i>0) then
  498. getinterfaceentry:=Res;
  499. end;
  500. end;
  501. class function TObject.getinterfaceentrybystr(const iidstr : string) : pinterfaceentry;
  502. var
  503. i: integer;
  504. intftable: pinterfacetable;
  505. Res: pinterfaceentry;
  506. begin
  507. getinterfaceentrybystr:=nil;
  508. intftable:=getinterfacetable;
  509. if assigned(intftable) then begin
  510. i:=intftable^.EntryCount;
  511. Res:=@intftable^.Entries[0];
  512. while (i>0) and (Res^.iidstr^<>iidstr) do begin
  513. inc(Res);
  514. dec(i);
  515. end;
  516. if (i>0) then
  517. getinterfaceentrybystr:=Res;
  518. end;
  519. end;
  520. class function TObject.getinterfacetable : pinterfacetable;
  521. begin
  522. getinterfacetable:=pinterfacetable((pointer(Self)+vmtIntfTable)^);
  523. end;
  524. {****************************************************************************
  525. TINTERFACEDOBJECT
  526. ****************************************************************************}
  527. function TInterfacedObject.QueryInterface(
  528. const iid : tguid;out obj) : longint;stdcall;
  529. begin
  530. if getinterface(iid,obj) then
  531. result:=0
  532. else
  533. result:=longint($80004002);
  534. end;
  535. function TInterfacedObject._AddRef : longint;stdcall;
  536. begin
  537. inclocked(frefcount);
  538. _addref:=frefcount;
  539. end;
  540. function TInterfacedObject._Release : longint;stdcall;
  541. begin
  542. if declocked(frefcount) then
  543. begin
  544. destroy;
  545. _Release:=0;
  546. end
  547. else
  548. _Release:=frefcount;
  549. end;
  550. procedure TInterfacedObject.AfterConstruction;
  551. begin
  552. { we need to fix the refcount we forced in newinstance }
  553. { further, it must be done in a thread safe way }
  554. declocked(frefcount);
  555. end;
  556. procedure TInterfacedObject.BeforeDestruction;
  557. begin
  558. if frefcount<>0 then
  559. HandleError(204);
  560. end;
  561. class function TInterfacedObject.NewInstance : TObject;
  562. begin
  563. NewInstance:=inherited NewInstance;
  564. TInterfacedObject(NewInstance).frefcount:=1;
  565. end;
  566. {$endif HASINTF}
  567. {****************************************************************************
  568. Exception Support
  569. ****************************************************************************}
  570. {$i except.inc}
  571. {****************************************************************************
  572. Initialize
  573. ****************************************************************************}
  574. {
  575. $Log$
  576. Revision 1.29 2002-10-15 19:29:49 peter
  577. * manual inline classparent calls in the loops
  578. Revision 1.28 2002/10/11 14:05:21 florian
  579. * initinterfacepointers improved
  580. Revision 1.27 2002/09/07 15:07:46 peter
  581. * old logs removed and tabs fixed
  582. Revision 1.26 2002/09/07 11:08:58 carl
  583. - remove logs
  584. Revision 1.25 2002/08/31 13:11:11 florian
  585. * several fixes for Linux/PPC compilation
  586. }