objpas.inc 23 KB

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