objpas.inc 21 KB

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