objpas.inc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  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. Procedure Finalize (Data,TypeInfo: Pointer);forward;
  13. {****************************************************************************
  14. Internal Routines called from the Compiler
  15. ****************************************************************************}
  16. { the reverse order of the parameters make code generation easier }
  17. function int_do_is(aclass : tclass;aobject : tobject) : boolean;[public,alias: 'FPC_DO_IS'];
  18. begin
  19. int_do_is:=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 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 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 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 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 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. 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. class function TObject.InitInstance(instance : pointer) : tobject;
  103. begin
  104. fillchar(instance^,self.instancesize,0);
  105. { insert VMT pointer into the new created memory area }
  106. { (in class methods self contains the VMT!) }
  107. ppointer(instance)^:=pointer(self);
  108. InitInstance:=TObject(Instance);
  109. end;
  110. class function TObject.ClassParent : tclass;
  111. begin
  112. { type of self is class of tobject => it points to the vmt }
  113. { the parent vmt is saved at offset vmtParent }
  114. classparent:=pclass(pointer(self)+vmtParent)^;
  115. end;
  116. class function TObject.NewInstance : tobject;
  117. var
  118. p : pointer;
  119. begin
  120. getmem(p,instancesize);
  121. InitInstance(p);
  122. NewInstance:=TObject(p);
  123. end;
  124. procedure TObject.FreeInstance;
  125. var
  126. p : Pointer;
  127. begin
  128. CleanupInstance;
  129. { self is a register, so we can't pass it call by reference }
  130. p:=Pointer(Self);
  131. FreeMem(p,InstanceSize);
  132. end;
  133. function TObject.ClassType : TClass;
  134. begin
  135. ClassType:=TClass(Pointer(Self)^)
  136. end;
  137. type
  138. tmethodnamerec = packed record
  139. name : pshortstring;
  140. addr : pointer;
  141. end;
  142. tmethodnametable = packed record
  143. count : dword;
  144. entries : packed array[0..0] of tmethodnamerec;
  145. end;
  146. pmethodnametable = ^tmethodnametable;
  147. class function TObject.MethodAddress(const name : shortstring) : pointer;
  148. var
  149. UName : ShortString;
  150. methodtable : pmethodnametable;
  151. i : dword;
  152. c : tclass;
  153. begin
  154. UName := UpCase(name);
  155. c:=self;
  156. while assigned(c) do
  157. begin
  158. methodtable:=pmethodnametable((Pointer(c)+vmtMethodTable)^);
  159. if assigned(methodtable) then
  160. begin
  161. for i:=0 to methodtable^.count-1 do
  162. if UpCase(methodtable^.entries[i].name^)=UName then
  163. begin
  164. MethodAddress:=methodtable^.entries[i].addr;
  165. exit;
  166. end;
  167. end;
  168. c:=c.ClassParent;
  169. end;
  170. MethodAddress:=nil;
  171. end;
  172. class function TObject.MethodName(address : pointer) : shortstring;
  173. var
  174. methodtable : pmethodnametable;
  175. i : dword;
  176. c : tclass;
  177. begin
  178. c:=self;
  179. while assigned(c) do
  180. begin
  181. methodtable:=pmethodnametable((Pointer(c)+vmtMethodTable)^);
  182. if assigned(methodtable) then
  183. begin
  184. for i:=0 to methodtable^.count-1 do
  185. if methodtable^.entries[i].addr=address then
  186. begin
  187. MethodName:=methodtable^.entries[i].name^;
  188. exit;
  189. end;
  190. end;
  191. c:=c.ClassParent;
  192. end;
  193. MethodName:='';
  194. end;
  195. function TObject.FieldAddress(const name : shortstring) : pointer;
  196. type
  197. PFieldInfo = ^TFieldInfo;
  198. TFieldInfo = packed record
  199. FieldOffset: LongWord;
  200. ClassTypeIndex: Word;
  201. Name: ShortString;
  202. end;
  203. PFieldTable = ^TFieldTable;
  204. TFieldTable = packed record
  205. FieldCount: Word;
  206. ClassTable: Pointer;
  207. { Fields: array[Word] of TFieldInfo; Elements have variant size! }
  208. end;
  209. var
  210. UName: ShortString;
  211. CurClassType: TClass;
  212. FieldTable: PFieldTable;
  213. FieldInfo: PFieldInfo;
  214. i: Integer;
  215. begin
  216. if Length(name) > 0 then
  217. begin
  218. UName := UpCase(name);
  219. CurClassType := ClassType;
  220. while CurClassType <> nil do
  221. begin
  222. FieldTable := PFieldTable((Pointer(CurClassType) + vmtFieldTable)^);
  223. if FieldTable <> nil then
  224. begin
  225. FieldInfo := PFieldInfo(Pointer(FieldTable) + 6);
  226. for i := 0 to FieldTable^.FieldCount - 1 do
  227. begin
  228. if UpCase(FieldInfo^.Name) = UName then
  229. begin
  230. fieldaddress := Pointer(Self) + FieldInfo^.FieldOffset;
  231. exit;
  232. end;
  233. Inc(Pointer(FieldInfo), 7 + Length(FieldInfo^.Name));
  234. end;
  235. end;
  236. { Try again with the parent class type }
  237. CurClassType := CurClassType.ClassParent;
  238. end;
  239. end;
  240. fieldaddress:=nil;
  241. end;
  242. function TObject.SafeCallException(exceptobject : tobject;
  243. exceptaddr : pointer) : longint;
  244. begin
  245. safecallexception:=0;
  246. end;
  247. class function TObject.ClassInfo : pointer;
  248. begin
  249. ClassInfo:=ppointer(Pointer(self)+vmtTypeInfo)^;
  250. end;
  251. class function TObject.ClassName : ShortString;
  252. begin
  253. ClassName:=PShortString((Pointer(Self)+vmtClassName)^)^;
  254. end;
  255. class function TObject.ClassNameIs(const name : string) : boolean;
  256. begin
  257. ClassNameIs:=Upcase(ClassName)=Upcase(name);
  258. end;
  259. class function TObject.InheritsFrom(aclass : TClass) : Boolean;
  260. var
  261. c : tclass;
  262. begin
  263. c:=self;
  264. while assigned(c) do
  265. begin
  266. if c=aclass then
  267. begin
  268. InheritsFrom:=true;
  269. exit;
  270. end;
  271. c:=c.ClassParent;
  272. end;
  273. InheritsFrom:=false;
  274. end;
  275. class function TObject.stringmessagetable : pstringmessagetable;
  276. type
  277. pdword = ^dword;
  278. begin
  279. stringmessagetable:=pstringmessagetable((pointer(Self)+vmtMsgStrPtr)^);
  280. end;
  281. type
  282. tmessagehandler = procedure(var msg) of object;
  283. tmessagehandlerrec = packed record
  284. proc : pointer;
  285. obj : pointer;
  286. end;
  287. procedure TObject.Dispatch(var message);
  288. type
  289. tmsgtable = record
  290. index : dword;
  291. method : pointer;
  292. end;
  293. pmsgtable = ^tmsgtable;
  294. pdword = ^dword;
  295. var
  296. index : dword;
  297. count,i : longint;
  298. msgtable : pmsgtable;
  299. p : pointer;
  300. vmt : tclass;
  301. msghandler : tmessagehandler;
  302. begin
  303. index:=dword(message);
  304. vmt:=ClassType;
  305. while assigned(vmt) do
  306. begin
  307. // See if we have messages at all in this class.
  308. p:=pointer(vmt)+vmtDynamicTable;
  309. If Assigned(p) and (Pdword(p)^<>0) then
  310. begin
  311. msgtable:=pmsgtable(pdword(P)^+4);
  312. count:=pdword(pdword(P)^)^;
  313. end
  314. else
  315. Count:=0;
  316. { later, we can implement a binary search here }
  317. for i:=0 to count-1 do
  318. begin
  319. if index=msgtable[i].index then
  320. begin
  321. p:=msgtable[i].method;
  322. tmessagehandlerrec(msghandler).proc:=p;
  323. tmessagehandlerrec(msghandler).obj:=self;
  324. msghandler(message);
  325. { we don't need any longer the assembler
  326. solution
  327. asm
  328. pushl message
  329. pushl %esi
  330. movl p,%edi
  331. call *%edi
  332. end;
  333. }
  334. exit;
  335. end;
  336. end;
  337. vmt:=vmt.ClassParent;
  338. end;
  339. DefaultHandler(message);
  340. end;
  341. procedure TObject.DispatchStr(var message);
  342. type
  343. pdword = ^dword;
  344. var
  345. name : shortstring;
  346. count,i : longint;
  347. msgstrtable : pmsgstrtable;
  348. p : pointer;
  349. vmt : tclass;
  350. msghandler : tmessagehandler;
  351. begin
  352. name:=pshortstring(@message)^;
  353. vmt:=ClassType;
  354. while assigned(vmt) do
  355. begin
  356. p:=(pointer(vmt)+vmtMsgStrPtr);
  357. If (P<>Nil) and (PDWord(P)^<>0) then
  358. begin
  359. count:=pdword(pdword(p)^)^;
  360. msgstrtable:=pmsgstrtable(pdword(P)^+4);
  361. end
  362. else
  363. Count:=0;
  364. { later, we can implement a binary search here }
  365. for i:=0 to count-1 do
  366. begin
  367. if name=msgstrtable[i].name^ then
  368. begin
  369. p:=msgstrtable[i].method;
  370. tmessagehandlerrec(msghandler).proc:=p;
  371. tmessagehandlerrec(msghandler).obj:=self;
  372. msghandler(message);
  373. { we don't need any longer the assembler
  374. solution
  375. asm
  376. pushl message
  377. pushl %esi
  378. movl p,%edi
  379. call *%edi
  380. end;
  381. }
  382. exit;
  383. end;
  384. end;
  385. vmt:=vmt.ClassParent;
  386. end;
  387. DefaultHandlerStr(message);
  388. end;
  389. procedure TObject.DefaultHandler(var message);
  390. begin
  391. end;
  392. procedure TObject.DefaultHandlerStr(var message);
  393. begin
  394. end;
  395. procedure TObject.CleanupInstance;
  396. var
  397. vmt : tclass;
  398. begin
  399. vmt:=ClassType;
  400. while vmt<>nil do
  401. begin
  402. if Assigned(Pointer((Pointer(vmt)+vmtInitTable)^)) then
  403. Finalize(Pointer(Self),Pointer((Pointer(vmt)+vmtInitTable)^));
  404. vmt:=vmt.ClassParent;
  405. end;
  406. end;
  407. procedure TObject.AfterConstruction;
  408. begin
  409. end;
  410. procedure TObject.BeforeDestruction;
  411. begin
  412. end;
  413. {$ifdef HASINTF}
  414. function IsGUIDEqual(const guid1, guid2: tguid): boolean;
  415. begin
  416. IsGUIDEqual:=
  417. (guid1.D1=guid2.D1) and
  418. (PDWORD(@guid1.D2)^=PDWORD(@guid2.D2)^) and
  419. (PDWORD(@guid1.D4[0])^=PDWORD(@guid2.D4[0])^) and
  420. (PDWORD(@guid1.D4[4])^=PDWORD(@guid2.D4[4])^);
  421. end;
  422. function TObject.getinterface(const iid : tguid;out obj) : boolean;
  423. var
  424. IEntry: pinterfaceentry;
  425. begin
  426. IEntry:=getinterfaceentry(iid);
  427. if Assigned(IEntry) then begin
  428. PDWORD(@obj)^:=DWORD(PDWORD(Self))+IEntry^.IOffset;
  429. int_do_intf_incr_ref(pointer(obj)); { it must be an com interface }
  430. getinterface:=True;
  431. end
  432. else begin
  433. PDWORD(@Obj)^:=0;
  434. getinterface:=False;
  435. end;
  436. end;
  437. function TObject.getinterfacebystr(const iidstr : string;out obj) : boolean;
  438. var
  439. IEntry: pinterfaceentry;
  440. begin
  441. IEntry:=getinterfaceentrybystr(iidstr);
  442. if Assigned(IEntry) then begin
  443. PDWORD(@obj)^:=DWORD(PDWORD(Self))+IEntry^.IOffset;
  444. if Assigned(IEntry^.iid) then { for Com interfaces }
  445. int_do_intf_incr_ref(pointer(obj));
  446. getinterfacebystr:=True;
  447. end
  448. else begin
  449. PDWORD(@Obj)^:=0;
  450. getinterfacebystr:=False;
  451. end;
  452. end;
  453. class function TObject.getinterfaceentry(const iid : tguid) : pinterfaceentry;
  454. var
  455. i: integer;
  456. intftable: pinterfacetable;
  457. Res: pinterfaceentry;
  458. begin
  459. getinterfaceentry:=nil;
  460. intftable:=getinterfacetable;
  461. if assigned(intftable) then begin
  462. i:=intftable^.EntryCount;
  463. Res:=@intftable^.Entries[0];
  464. while (i>0) and
  465. not (assigned(Res^.iid) and IsGUIDEqual(Res^.iid^,iid)) do begin
  466. inc(Res);
  467. dec(i);
  468. end;
  469. if (i>0) then
  470. getinterfaceentry:=Res;
  471. end;
  472. end;
  473. class function TObject.getinterfaceentrybystr(const iidstr : string) : pinterfaceentry;
  474. var
  475. i: integer;
  476. intftable: pinterfacetable;
  477. Res: pinterfaceentry;
  478. begin
  479. getinterfaceentrybystr:=nil;
  480. intftable:=getinterfacetable;
  481. if assigned(intftable) then begin
  482. i:=intftable^.EntryCount;
  483. Res:=@intftable^.Entries[0];
  484. while (i>0) and (Res^.iidstr^<>iidstr) do begin
  485. inc(Res);
  486. dec(i);
  487. end;
  488. if (i>0) then
  489. getinterfaceentrybystr:=Res;
  490. end;
  491. end;
  492. class function TObject.getinterfacetable : pinterfacetable;
  493. begin
  494. getinterfacetable:=pinterfacetable((pointer(Self)+vmtIntfTable)^);
  495. end;
  496. {$endif HASINTF}
  497. {****************************************************************************
  498. Exception Support
  499. ****************************************************************************}
  500. {$i except.inc}
  501. {****************************************************************************
  502. Initialize
  503. ****************************************************************************}
  504. {
  505. $Log$
  506. Revision 1.7 2000-11-06 21:35:59 peter
  507. * removed some warnings
  508. Revision 1.6 2000/11/06 20:34:24 peter
  509. * changed ver1_0 defines to temporary defs
  510. Revision 1.5 2000/11/04 17:52:46 florian
  511. * fixed linker errors
  512. Revision 1.4 2000/11/04 16:29:54 florian
  513. + interfaces support
  514. Revision 1.3 2000/07/22 14:52:01 sg
  515. * Resolved CVS conflicts for TObject.MethodAddress patch
  516. Revision 1.1.2.1 2000/07/22 14:46:57 sg
  517. * Made TObject.MethodAddress case independent
  518. }