objpas.inc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  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 fpc_intf_decr_ref(var i: pointer);saveregisters;[public,alias: 'FPC_INTF_DECR_REF']; {$ifdef hascompilerproc} compilerproc; {$endif}
  31. begin
  32. end;
  33. procedure fpc_intf_incr_ref(i: pointer);saveregisters;[public,alias: 'FPC_INTF_INCR_REF']; {$ifdef hascompilerproc} compilerproc; {$endif}
  34. begin
  35. end;
  36. procedure fpc_intf_assign(var D: pointer; const S: pointer);[public,alias: 'FPC_INTF_ASSIGN']; {$ifdef hascompilerproc} compilerproc; {$endif}
  37. begin
  38. end;
  39. function fpc_intf_as(const S: pointer; const iid: TGUID): pointer;[public,alias: 'FPC_INTF_AS']; {$ifdef hascompilerproc} compilerproc; {$endif}
  40. begin
  41. end;
  42. function fpc_class_as_intf(const S: pointer; const iid: TGUID): pointer;[public,alias: 'FPC_CLASS_AS_INTF']; {$ifdef hascompilerproc} compilerproc; {$endif}
  43. begin
  44. end;
  45. {$else HASINTF}
  46. { interface helpers }
  47. procedure fpc_intf_decr_ref(var i: pointer);saveregisters;[public,alias: 'FPC_INTF_DECR_REF']; {$ifdef hascompilerproc} compilerproc; {$endif}
  48. begin
  49. if assigned(i) then
  50. IUnknown(i)._Release;
  51. i:=nil;
  52. end;
  53. {$ifdef hascompilerproc}
  54. { local declaration for intf_decr_ref for local access }
  55. procedure intf_decr_ref(var i: pointer);saveregisters; [external name 'FPC_INTF_DECR_REF'];
  56. {$endif hascompilerproc}
  57. procedure fpc_intf_incr_ref(i: pointer);saveregisters;[public,alias: 'FPC_INTF_INCR_REF']; {$ifdef hascompilerproc} compilerproc; {$endif}
  58. begin
  59. if assigned(i) then
  60. IUnknown(i)._AddRef;
  61. end;
  62. {$ifdef hascompilerproc}
  63. { local declaration of intf_incr_ref for local access }
  64. procedure intf_incr_ref(i: pointer);saveregisters; [external name 'FPC_INTF_INCR_REF'];
  65. {$endif hascompilerproc}
  66. procedure fpc_intf_assign(var D: pointer; const S: pointer);[public,alias: 'FPC_INTF_ASSIGN']; {$ifdef hascompilerproc} compilerproc; {$endif}
  67. begin
  68. if assigned(S) then
  69. IUnknown(S)._AddRef;
  70. if assigned(D) then
  71. IUnknown(D)._Release;
  72. D:=S;
  73. end;
  74. function fpc_intf_as(const S: pointer; const iid: TGUID): pointer;[public,alias: 'FPC_INTF_AS']; {$ifdef hascompilerproc} compilerproc; {$endif}
  75. const
  76. S_OK = 0;
  77. var
  78. tmpi: pointer; // _AddRef before _Release
  79. begin
  80. if assigned(S) then
  81. begin
  82. if IUnknown(S).QueryInterface(iid,tmpi)<>S_OK then
  83. handleerror(219);
  84. fpc_intf_as:=tmpi;
  85. end
  86. else
  87. fpc_intf_as:=nil;
  88. end;
  89. function fpc_class_as_intf(const S: pointer; const iid: TGUID): pointer;[public,alias: 'FPC_CLASS_AS_INTF']; {$ifdef hascompilerproc} compilerproc; {$endif}
  90. const
  91. S_OK = 0;
  92. var
  93. tmpi: pointer; // _AddRef before _Release
  94. begin
  95. if assigned(S) then
  96. begin
  97. if not TObject(S).GetInterface(iid,tmpi) then
  98. handleerror(219);
  99. fpc_class_as_intf:=tmpi;
  100. end
  101. else
  102. fpc_class_as_intf:=nil;
  103. end;
  104. {$endif HASINTF}
  105. {****************************************************************************
  106. TOBJECT
  107. ****************************************************************************}
  108. constructor TObject.Create;
  109. begin
  110. end;
  111. destructor TObject.Destroy;
  112. begin
  113. end;
  114. procedure TObject.Free;
  115. begin
  116. // the call via self avoids a warning
  117. if self<>nil then
  118. self.destroy;
  119. end;
  120. class function TObject.InstanceSize : LongInt;
  121. type
  122. plongint = ^longint;
  123. begin
  124. { type of self is class of tobject => it points to the vmt }
  125. { the size is saved at offset 0 }
  126. InstanceSize:=plongint(self)^;
  127. end;
  128. procedure InitInterfacePointers(objclass: tclass;instance : pointer);
  129. {$ifdef HASINTF}
  130. var
  131. intftable : pinterfacetable;
  132. i : longint;
  133. begin
  134. if assigned(objclass.classparent) then
  135. InitInterfacePointers(objclass.classparent,instance);
  136. intftable:=objclass.getinterfacetable;
  137. if assigned(intftable) then
  138. for i:=0 to intftable^.EntryCount-1 do
  139. ppointer(@(PChar(instance)[intftable^.Entries[i].IOffset]))^:=
  140. pointer(intftable^.Entries[i].VTable);
  141. end;
  142. {$else HASINTF}
  143. begin
  144. end;
  145. {$endif HASINTF}
  146. class function TObject.InitInstance(instance : pointer) : tobject;
  147. begin
  148. fillchar(instance^,self.instancesize,0);
  149. { insert VMT pointer into the new created memory area }
  150. { (in class methods self contains the VMT!) }
  151. ppointer(instance)^:=pointer(self);
  152. {$ifdef HASINTF}
  153. InitInterfacePointers(self,instance);
  154. {$endif HASINTF}
  155. InitInstance:=TObject(Instance);
  156. end;
  157. class function TObject.ClassParent : tclass;
  158. begin
  159. { type of self is class of tobject => it points to the vmt }
  160. { the parent vmt is saved at offset vmtParent }
  161. classparent:=pclass(pointer(self)+vmtParent)^;
  162. end;
  163. class function TObject.NewInstance : tobject;
  164. var
  165. p : pointer;
  166. begin
  167. getmem(p,instancesize);
  168. if p <> nil then
  169. InitInstance(p);
  170. NewInstance:=TObject(p);
  171. end;
  172. procedure TObject.FreeInstance;
  173. var
  174. p : Pointer;
  175. begin
  176. CleanupInstance;
  177. { self is a register, so we can't pass it call by reference }
  178. p:=Pointer(Self);
  179. FreeMem(p,InstanceSize);
  180. end;
  181. function TObject.ClassType : TClass;
  182. begin
  183. ClassType:=TClass(Pointer(Self)^)
  184. end;
  185. type
  186. tmethodnamerec = packed record
  187. name : pshortstring;
  188. addr : pointer;
  189. end;
  190. tmethodnametable = packed record
  191. count : dword;
  192. entries : packed array[0..0] of tmethodnamerec;
  193. end;
  194. pmethodnametable = ^tmethodnametable;
  195. class function TObject.MethodAddress(const name : shortstring) : pointer;
  196. var
  197. UName : ShortString;
  198. methodtable : pmethodnametable;
  199. i : dword;
  200. c : tclass;
  201. begin
  202. UName := UpCase(name);
  203. c:=self;
  204. while assigned(c) do
  205. begin
  206. methodtable:=pmethodnametable((Pointer(c)+vmtMethodTable)^);
  207. if assigned(methodtable) then
  208. begin
  209. for i:=0 to methodtable^.count-1 do
  210. if UpCase(methodtable^.entries[i].name^)=UName then
  211. begin
  212. MethodAddress:=methodtable^.entries[i].addr;
  213. exit;
  214. end;
  215. end;
  216. c:=c.ClassParent;
  217. end;
  218. MethodAddress:=nil;
  219. end;
  220. class function TObject.MethodName(address : pointer) : shortstring;
  221. var
  222. methodtable : pmethodnametable;
  223. i : dword;
  224. c : tclass;
  225. begin
  226. c:=self;
  227. while assigned(c) do
  228. begin
  229. methodtable:=pmethodnametable((Pointer(c)+vmtMethodTable)^);
  230. if assigned(methodtable) then
  231. begin
  232. for i:=0 to methodtable^.count-1 do
  233. if methodtable^.entries[i].addr=address then
  234. begin
  235. MethodName:=methodtable^.entries[i].name^;
  236. exit;
  237. end;
  238. end;
  239. c:=c.ClassParent;
  240. end;
  241. MethodName:='';
  242. end;
  243. function TObject.FieldAddress(const name : shortstring) : pointer;
  244. type
  245. PFieldInfo = ^TFieldInfo;
  246. TFieldInfo = packed record
  247. FieldOffset: LongWord;
  248. ClassTypeIndex: Word;
  249. Name: ShortString;
  250. end;
  251. PFieldTable = ^TFieldTable;
  252. TFieldTable = packed record
  253. FieldCount: Word;
  254. ClassTable: Pointer;
  255. { Fields: array[Word] of TFieldInfo; Elements have variant size! }
  256. end;
  257. var
  258. UName: ShortString;
  259. CurClassType: TClass;
  260. FieldTable: PFieldTable;
  261. FieldInfo: PFieldInfo;
  262. i: Integer;
  263. begin
  264. if Length(name) > 0 then
  265. begin
  266. UName := UpCase(name);
  267. CurClassType := ClassType;
  268. while CurClassType <> nil do
  269. begin
  270. FieldTable := PFieldTable((Pointer(CurClassType) + vmtFieldTable)^);
  271. if FieldTable <> nil then
  272. begin
  273. FieldInfo := PFieldInfo(Pointer(FieldTable) + 6);
  274. for i := 0 to FieldTable^.FieldCount - 1 do
  275. begin
  276. if UpCase(FieldInfo^.Name) = UName then
  277. begin
  278. fieldaddress := Pointer(Self) + FieldInfo^.FieldOffset;
  279. exit;
  280. end;
  281. Inc(Pointer(FieldInfo), 7 + Length(FieldInfo^.Name));
  282. end;
  283. end;
  284. { Try again with the parent class type }
  285. CurClassType := CurClassType.ClassParent;
  286. end;
  287. end;
  288. fieldaddress:=nil;
  289. end;
  290. function TObject.SafeCallException(exceptobject : tobject;
  291. exceptaddr : pointer) : longint;
  292. begin
  293. safecallexception:=0;
  294. end;
  295. class function TObject.ClassInfo : pointer;
  296. begin
  297. ClassInfo:=ppointer(Pointer(self)+vmtTypeInfo)^;
  298. end;
  299. class function TObject.ClassName : ShortString;
  300. begin
  301. ClassName:=PShortString((Pointer(Self)+vmtClassName)^)^;
  302. end;
  303. class function TObject.ClassNameIs(const name : string) : boolean;
  304. begin
  305. ClassNameIs:=Upcase(ClassName)=Upcase(name);
  306. end;
  307. class function TObject.InheritsFrom(aclass : TClass) : Boolean;
  308. var
  309. c : tclass;
  310. begin
  311. c:=self;
  312. while assigned(c) do
  313. begin
  314. if c=aclass then
  315. begin
  316. InheritsFrom:=true;
  317. exit;
  318. end;
  319. c:=c.ClassParent;
  320. end;
  321. InheritsFrom:=false;
  322. end;
  323. class function TObject.stringmessagetable : pstringmessagetable;
  324. type
  325. pdword = ^dword;
  326. begin
  327. stringmessagetable:=pstringmessagetable((pointer(Self)+vmtMsgStrPtr)^);
  328. end;
  329. type
  330. tmessagehandler = procedure(var msg) of object;
  331. tmessagehandlerrec = packed record
  332. proc : pointer;
  333. obj : pointer;
  334. end;
  335. procedure TObject.Dispatch(var message);
  336. type
  337. tmsgtable = record
  338. index : dword;
  339. method : pointer;
  340. end;
  341. pmsgtable = ^tmsgtable;
  342. pdword = ^dword;
  343. var
  344. index : dword;
  345. count,i : longint;
  346. msgtable : pmsgtable;
  347. p : pointer;
  348. vmt : tclass;
  349. msghandler : tmessagehandler;
  350. begin
  351. index:=dword(message);
  352. vmt:=ClassType;
  353. while assigned(vmt) do
  354. begin
  355. // See if we have messages at all in this class.
  356. p:=pointer(vmt)+vmtDynamicTable;
  357. If Assigned(p) and (Pdword(p)^<>0) then
  358. begin
  359. msgtable:=pmsgtable(pdword(P)^+4);
  360. count:=pdword(pdword(P)^)^;
  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 index=msgtable[i].index then
  368. begin
  369. p:=msgtable[i].method;
  370. tmessagehandlerrec(msghandler).proc:=p;
  371. tmessagehandlerrec(msghandler).obj:=self;
  372. msghandler(message);
  373. exit;
  374. end;
  375. end;
  376. vmt:=vmt.ClassParent;
  377. end;
  378. DefaultHandler(message);
  379. end;
  380. procedure TObject.DispatchStr(var message);
  381. type
  382. pdword = ^dword;
  383. var
  384. name : shortstring;
  385. count,i : longint;
  386. msgstrtable : pmsgstrtable;
  387. p : pointer;
  388. vmt : tclass;
  389. msghandler : tmessagehandler;
  390. begin
  391. name:=pshortstring(@message)^;
  392. vmt:=ClassType;
  393. while assigned(vmt) do
  394. begin
  395. p:=(pointer(vmt)+vmtMsgStrPtr);
  396. If (P<>Nil) and (PDWord(P)^<>0) then
  397. begin
  398. count:=pdword(pdword(p)^)^;
  399. msgstrtable:=pmsgstrtable(pdword(P)^+4);
  400. end
  401. else
  402. Count:=0;
  403. { later, we can implement a binary search here }
  404. for i:=0 to count-1 do
  405. begin
  406. if name=msgstrtable[i].name^ then
  407. begin
  408. p:=msgstrtable[i].method;
  409. tmessagehandlerrec(msghandler).proc:=p;
  410. tmessagehandlerrec(msghandler).obj:=self;
  411. msghandler(message);
  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.27 2002-09-07 15:07:46 peter
  579. * old logs removed and tabs fixed
  580. Revision 1.26 2002/09/07 11:08:58 carl
  581. - remove logs
  582. Revision 1.25 2002/08/31 13:11:11 florian
  583. * several fixes for Linux/PPC compilation
  584. }