objpas.inc 22 KB

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