objpas.inc 18 KB

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