objpas.inc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  4. This unit makes Free Pascal as much as possible Delphi compatible
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {****************************************************************************
  12. Internal Routines called from the Compiler
  13. ****************************************************************************}
  14. { the reverse order of the parameters make code generation easier }
  15. function fpc_do_is(aclass : tclass;aobject : tobject) : boolean;[public,alias: 'FPC_DO_IS']; compilerproc;
  16. begin
  17. fpc_do_is:=assigned(aobject) and assigned(aclass) and
  18. aobject.inheritsfrom(aclass);
  19. end;
  20. { the reverse order of the parameters make code generation easier }
  21. function fpc_do_as(aclass : tclass;aobject : tobject): tobject;[public,alias: 'FPC_DO_AS']; compilerproc;
  22. begin
  23. if assigned(aobject) and not(aobject.inheritsfrom(aclass)) then
  24. handleerrorframe(219,get_frame);
  25. result := aobject;
  26. end;
  27. { interface helpers }
  28. procedure fpc_intf_decr_ref(var i: pointer);[public,alias: 'FPC_INTF_DECR_REF']; compilerproc;
  29. begin
  30. if assigned(i) then
  31. IUnknown(i)._Release;
  32. i:=nil;
  33. end;
  34. { local declaration for intf_decr_ref for local access }
  35. procedure intf_decr_ref(var i: pointer); [external name 'FPC_INTF_DECR_REF'];
  36. procedure fpc_intf_incr_ref(i: pointer);[public,alias: 'FPC_INTF_INCR_REF']; compilerproc;
  37. begin
  38. if assigned(i) then
  39. IUnknown(i)._AddRef;
  40. end;
  41. { local declaration of intf_incr_ref for local access }
  42. procedure intf_incr_ref(i: pointer); [external name 'FPC_INTF_INCR_REF'];
  43. procedure fpc_intf_assign(var D: pointer; const S: pointer);[public,alias: 'FPC_INTF_ASSIGN']; compilerproc;
  44. begin
  45. if assigned(S) then
  46. IUnknown(S)._AddRef;
  47. if assigned(D) then
  48. IUnknown(D)._Release;
  49. D:=S;
  50. end;
  51. function fpc_intf_as(const S: pointer; const iid: TGUID): IInterface;[public,alias: 'FPC_INTF_AS']; compilerproc;
  52. var
  53. tmpi: pointer; // _AddRef before _Release
  54. begin
  55. if assigned(S) then
  56. begin
  57. if IUnknown(S).QueryInterface(iid,tmpi)<>S_OK then
  58. handleerror(219);
  59. pointer(fpc_intf_as):=tmpi;
  60. end
  61. else
  62. fpc_intf_as:=nil;
  63. end;
  64. function fpc_class_as_intf(const S: pointer; const iid: TGUID): IInterface;[public,alias: 'FPC_CLASS_AS_INTF']; compilerproc;
  65. var
  66. tmpi: pointer; // _AddRef before _Release
  67. begin
  68. if assigned(S) then
  69. begin
  70. if not TObject(S).GetInterface(iid,tmpi) then
  71. handleerror(219);
  72. pointer(fpc_class_as_intf):=tmpi;
  73. end
  74. else
  75. fpc_class_as_intf:=nil;
  76. end;
  77. {****************************************************************************
  78. TOBJECT
  79. ****************************************************************************}
  80. constructor TObject.Create;
  81. begin
  82. end;
  83. destructor TObject.Destroy;
  84. begin
  85. end;
  86. procedure TObject.Free;
  87. begin
  88. // the call via self avoids a warning
  89. if self<>nil then
  90. self.destroy;
  91. end;
  92. class function TObject.InstanceSize : SizeInt;
  93. begin
  94. InstanceSize:=pSizeInt(pointer(self)+vmtInstanceSize)^;
  95. end;
  96. procedure InitInterfacePointers(objclass: tclass;instance : pointer);
  97. var
  98. intftable : pinterfacetable;
  99. i : longint;
  100. begin
  101. while assigned(objclass) do
  102. begin
  103. intftable:=pinterfacetable((pointer(objclass)+vmtIntfTable)^);
  104. if assigned(intftable) then
  105. for i:=0 to intftable^.EntryCount-1 do
  106. ppointer(@(PChar(instance)[intftable^.Entries[i].IOffset]))^:=
  107. pointer(intftable^.Entries[i].VTable);
  108. objclass:=pclass(pointer(objclass)+vmtParent)^;
  109. end;
  110. end;
  111. class function TObject.InitInstance(instance : pointer) : tobject;
  112. begin
  113. { the size is saved at offset 0 }
  114. fillchar(instance^, InstanceSize, 0);
  115. { insert VMT pointer into the new created memory area }
  116. { (in class methods self contains the VMT!) }
  117. ppointer(instance)^:=pointer(self);
  118. InitInterfacePointers(self,instance);
  119. InitInstance:=TObject(Instance);
  120. end;
  121. class function TObject.ClassParent : tclass;
  122. begin
  123. { type of self is class of tobject => it points to the vmt }
  124. { the parent vmt is saved at offset vmtParent }
  125. classparent:=pclass(pointer(self)+vmtParent)^;
  126. end;
  127. class function TObject.NewInstance : tobject;
  128. var
  129. p : pointer;
  130. begin
  131. getmem(p, InstanceSize);
  132. if p <> nil then
  133. InitInstance(p);
  134. NewInstance:=TObject(p);
  135. end;
  136. procedure TObject.FreeInstance;
  137. begin
  138. CleanupInstance;
  139. FreeMem(Pointer(Self));
  140. end;
  141. class function TObject.ClassType : TClass;
  142. begin
  143. ClassType:=TClass(Pointer(Self))
  144. end;
  145. type
  146. tmethodnamerec = packed record
  147. name : pshortstring;
  148. addr : pointer;
  149. end;
  150. tmethodnametable = packed record
  151. count : dword;
  152. entries : packed array[0..0] of tmethodnamerec;
  153. end;
  154. pmethodnametable = ^tmethodnametable;
  155. class function TObject.MethodAddress(const name : shortstring) : pointer;
  156. var
  157. UName : ShortString;
  158. methodtable : pmethodnametable;
  159. i : dword;
  160. vmt : tclass;
  161. begin
  162. UName := UpCase(name);
  163. vmt:=self;
  164. while assigned(vmt) do
  165. begin
  166. methodtable:=pmethodnametable((Pointer(vmt)+vmtMethodTable)^);
  167. if assigned(methodtable) then
  168. begin
  169. for i:=0 to methodtable^.count-1 do
  170. if UpCase(methodtable^.entries[i].name^)=UName then
  171. begin
  172. MethodAddress:=methodtable^.entries[i].addr;
  173. exit;
  174. end;
  175. end;
  176. vmt:=pclass(pointer(vmt)+vmtParent)^;
  177. end;
  178. MethodAddress:=nil;
  179. end;
  180. class function TObject.MethodName(address : pointer) : shortstring;
  181. var
  182. methodtable : pmethodnametable;
  183. i : dword;
  184. vmt : tclass;
  185. begin
  186. vmt:=self;
  187. while assigned(vmt) do
  188. begin
  189. methodtable:=pmethodnametable((Pointer(vmt)+vmtMethodTable)^);
  190. if assigned(methodtable) then
  191. begin
  192. for i:=0 to methodtable^.count-1 do
  193. if methodtable^.entries[i].addr=address then
  194. begin
  195. MethodName:=methodtable^.entries[i].name^;
  196. exit;
  197. end;
  198. end;
  199. vmt:=pclass(pointer(vmt)+vmtParent)^;
  200. end;
  201. MethodName:='';
  202. end;
  203. function TObject.FieldAddress(const name : shortstring) : pointer;
  204. type
  205. PFieldInfo = ^TFieldInfo;
  206. TFieldInfo =
  207. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  208. packed
  209. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  210. record
  211. FieldOffset: PtrUInt;
  212. ClassTypeIndex: Word;
  213. Name: ShortString;
  214. end;
  215. PFieldTable = ^TFieldTable;
  216. TFieldTable =
  217. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  218. packed
  219. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  220. record
  221. FieldCount: Word;
  222. ClassTable: Pointer;
  223. { should be array[Word] of TFieldInfo; but
  224. Elements have variant size! force at least proper alignment }
  225. Fields: array[0..0] of TFieldInfo
  226. end;
  227. var
  228. UName: ShortString;
  229. CurClassType: TClass;
  230. FieldTable: PFieldTable;
  231. FieldInfo: PFieldInfo;
  232. i: Integer;
  233. begin
  234. if Length(name) > 0 then
  235. begin
  236. UName := UpCase(name);
  237. CurClassType := ClassType;
  238. while CurClassType <> nil do
  239. begin
  240. FieldTable := PFieldTable((Pointer(CurClassType) + vmtFieldTable)^);
  241. if FieldTable <> nil then
  242. begin
  243. FieldInfo := @FieldTable^.Fields;
  244. for i := 0 to FieldTable^.FieldCount - 1 do
  245. begin
  246. if UpCase(FieldInfo^.Name) = UName then
  247. begin
  248. fieldaddress := Pointer(Self) + FieldInfo^.FieldOffset;
  249. exit;
  250. end;
  251. FieldInfo := @FieldInfo^.Name + 1 + Length(FieldInfo^.Name);
  252. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  253. { align to largest field of TFieldInfo }
  254. FieldInfo := Align(FieldInfo, SizeOf(PtrUInt));
  255. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  256. end;
  257. end;
  258. { Try again with the parent class type }
  259. CurClassType:=pclass(pointer(CurClassType)+vmtParent)^;
  260. end;
  261. end;
  262. fieldaddress:=nil;
  263. end;
  264. function TObject.SafeCallException(exceptobject : tobject;
  265. exceptaddr : pointer) : longint;
  266. begin
  267. safecallexception:=0;
  268. end;
  269. class function TObject.ClassInfo : pointer;
  270. begin
  271. ClassInfo:=ppointer(Pointer(self)+vmtTypeInfo)^;
  272. end;
  273. class function TObject.ClassName : ShortString;
  274. begin
  275. ClassName:=PShortString((Pointer(Self)+vmtClassName)^)^;
  276. end;
  277. class function TObject.ClassNameIs(const name : string) : boolean;
  278. begin
  279. ClassNameIs:=Upcase(ClassName)=Upcase(name);
  280. end;
  281. class function TObject.InheritsFrom(aclass : TClass) : Boolean;
  282. var
  283. vmt : tclass;
  284. begin
  285. vmt:=self;
  286. while assigned(vmt) do
  287. begin
  288. if vmt=aclass then
  289. begin
  290. InheritsFrom:=true;
  291. exit;
  292. end;
  293. vmt:=pclass(pointer(vmt)+vmtParent)^;
  294. end;
  295. InheritsFrom:=false;
  296. end;
  297. class function TObject.stringmessagetable : pstringmessagetable;
  298. begin
  299. stringmessagetable:=pstringmessagetable((pointer(Self)+vmtMsgStrPtr)^);
  300. end;
  301. type
  302. tmessagehandler = procedure(var msg) of object;
  303. tmessagehandlerrec = packed record
  304. proc : pointer;
  305. obj : pointer;
  306. end;
  307. procedure TObject.Dispatch(var message);
  308. type
  309. tmsgtable = packed record
  310. index : dword;
  311. method : pointer;
  312. end;
  313. pmsgtable = ^tmsgtable;
  314. var
  315. index : dword;
  316. count,i : longint;
  317. msgtable : pmsgtable;
  318. p : pointer;
  319. vmt : tclass;
  320. msghandler : tmessagehandler;
  321. begin
  322. index:=dword(message);
  323. vmt:=ClassType;
  324. while assigned(vmt) do
  325. begin
  326. // See if we have messages at all in this class.
  327. p:=pointer(vmt)+vmtDynamicTable;
  328. If assigned(PPointer(p)^) then
  329. begin
  330. msgtable:=pmsgtable(Pointer(p^)+4);
  331. count:=pdword(p^)^;
  332. end
  333. else
  334. Count:=0;
  335. { later, we can implement a binary search here }
  336. for i:=0 to count-1 do
  337. begin
  338. if index=msgtable[i].index then
  339. begin
  340. p:=msgtable[i].method;
  341. tmessagehandlerrec(msghandler).proc:=p;
  342. tmessagehandlerrec(msghandler).obj:=self;
  343. msghandler(message);
  344. exit;
  345. end;
  346. end;
  347. vmt:=pclass(pointer(vmt)+vmtParent)^;
  348. end;
  349. DefaultHandler(message);
  350. end;
  351. procedure TObject.DispatchStr(var message);
  352. type
  353. PSizeUInt = ^SizeUInt;
  354. var
  355. name : shortstring;
  356. count,i : longint;
  357. msgstrtable : pmsgstrtable;
  358. p : pointer;
  359. vmt : tclass;
  360. msghandler : tmessagehandler;
  361. begin
  362. name:=pshortstring(@message)^;
  363. vmt:=ClassType;
  364. while assigned(vmt) do
  365. begin
  366. p:=(pointer(vmt)+vmtMsgStrPtr);
  367. If (P<>Nil) and (PPtrInt(P)^<>0) then
  368. begin
  369. count:=PPtrInt(PSizeUInt(p)^)^;
  370. msgstrtable:=pmsgstrtable(PSizeUInt(P)^+sizeof(ptrint));
  371. end
  372. else
  373. Count:=0;
  374. { later, we can implement a binary search here }
  375. for i:=0 to count-1 do
  376. begin
  377. if name=msgstrtable[i].name^ then
  378. begin
  379. p:=msgstrtable[i].method;
  380. tmessagehandlerrec(msghandler).proc:=p;
  381. tmessagehandlerrec(msghandler).obj:=self;
  382. msghandler(message);
  383. exit;
  384. end;
  385. end;
  386. vmt:=pclass(pointer(vmt)+vmtParent)^;
  387. end;
  388. DefaultHandlerStr(message);
  389. end;
  390. procedure TObject.DefaultHandler(var message);
  391. begin
  392. end;
  393. procedure TObject.DefaultHandlerStr(var message);
  394. begin
  395. end;
  396. procedure TObject.CleanupInstance;
  397. Type
  398. TRecElem = packed Record
  399. Info : Pointer;
  400. Offset : Longint;
  401. end;
  402. TRecElemArray = packed array[1..Maxint] of TRecElem;
  403. PRecRec = ^TRecRec;
  404. TRecRec = record
  405. Size,Count : Longint;
  406. Elements : TRecElemArray;
  407. end;
  408. var
  409. vmt : tclass;
  410. temp : pbyte;
  411. count,
  412. i : longint;
  413. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  414. recelem : TRecElem;
  415. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  416. begin
  417. vmt:=ClassType;
  418. while vmt<>nil do
  419. begin
  420. { This need to be included here, because Finalize()
  421. has should support for tkClass }
  422. Temp:=Pointer((Pointer(vmt)+vmtInitTable)^);
  423. if Assigned(Temp) then
  424. begin
  425. inc(Temp);
  426. I:=Temp^;
  427. inc(temp,I+1); // skip name string;
  428. temp:=aligntoptr(temp);
  429. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  430. move(PRecRec(Temp)^.Count,Count,sizeof(Count));
  431. {$else FPC_REQUIRES_PROPER_ALIGNMENT}
  432. Count:=PRecRec(Temp)^.Count; // get element Count
  433. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  434. For I:=1 to count do
  435. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  436. begin
  437. move(PRecRec(Temp)^.elements[I],RecElem,sizeof(RecElem));
  438. With RecElem do
  439. int_Finalize (pointer(self)+Offset,Info);
  440. end;
  441. {$else FPC_REQUIRES_PROPER_ALIGNMENT}
  442. With PRecRec(Temp)^.elements[I] do
  443. int_Finalize (pointer(self)+Offset,Info);
  444. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  445. end;
  446. vmt:=pclass(pointer(vmt)+vmtParent)^;
  447. end;
  448. end;
  449. procedure TObject.AfterConstruction;
  450. begin
  451. end;
  452. procedure TObject.BeforeDestruction;
  453. begin
  454. end;
  455. function IsGUIDEqual(const guid1, guid2: tguid): boolean;
  456. begin
  457. IsGUIDEqual:=
  458. (guid1.D1=guid2.D1) and
  459. (PDWORD(@guid1.D2)^=PDWORD(@guid2.D2)^) and
  460. (PDWORD(@guid1.D4[0])^=PDWORD(@guid2.D4[0])^) and
  461. (PDWORD(@guid1.D4[4])^=PDWORD(@guid2.D4[4])^);
  462. end;
  463. function TObject.getinterface(const iid : tguid;out obj) : boolean;
  464. var
  465. IEntry: pinterfaceentry;
  466. begin
  467. IEntry:=getinterfaceentry(iid);
  468. if Assigned(IEntry) then
  469. begin
  470. Pointer(obj):=Pointer(Self)+IEntry^.IOffset;
  471. if assigned(pointer(obj)) then
  472. iinterface(obj)._AddRef;
  473. getinterface:=True;
  474. end
  475. else
  476. begin
  477. PPointer(@Obj)^:=nil;
  478. getinterface:=False;
  479. end;
  480. end;
  481. function TObject.getinterfacebystr(const iidstr : string;out obj) : boolean;
  482. var
  483. IEntry: pinterfaceentry;
  484. begin
  485. IEntry:=getinterfaceentrybystr(iidstr);
  486. if Assigned(IEntry) then
  487. begin
  488. Pointer(obj):=Pointer(Self)+IEntry^.IOffset;
  489. if assigned(pointer(obj)) then
  490. iinterface(obj)._AddRef;
  491. getinterfacebystr:=True;
  492. end
  493. else
  494. begin
  495. PPointer(@Obj)^:=nil;
  496. getinterfacebystr:=False;
  497. end;
  498. end;
  499. class function TObject.getinterfaceentry(const iid : tguid) : pinterfaceentry;
  500. var
  501. i: integer;
  502. intftable: pinterfacetable;
  503. Res: pinterfaceentry;
  504. begin
  505. getinterfaceentry:=nil;
  506. intftable:=pinterfacetable((pointer(Self)+vmtIntfTable)^);
  507. if assigned(intftable) then begin
  508. i:=intftable^.EntryCount;
  509. Res:=@intftable^.Entries[0];
  510. while (i>0) and
  511. not (assigned(Res^.iid) and IsGUIDEqual(Res^.iid^,iid)) do begin
  512. inc(Res);
  513. dec(i);
  514. end;
  515. if (i>0) then
  516. getinterfaceentry:=Res;
  517. end;
  518. if (getinterfaceentry=nil)and not(classparent=nil) then
  519. getinterfaceentry:=classparent.getinterfaceentry(iid)
  520. end;
  521. class function TObject.getinterfaceentrybystr(const iidstr : string) : pinterfaceentry;
  522. var
  523. i: integer;
  524. intftable: pinterfacetable;
  525. Res: pinterfaceentry;
  526. begin
  527. getinterfaceentrybystr:=nil;
  528. intftable:=getinterfacetable;
  529. if assigned(intftable) then begin
  530. i:=intftable^.EntryCount;
  531. Res:=@intftable^.Entries[0];
  532. while (i>0) and (Res^.iidstr^<>iidstr) do begin
  533. inc(Res);
  534. dec(i);
  535. end;
  536. if (i>0) then
  537. getinterfaceentrybystr:=Res;
  538. end;
  539. if (getinterfaceentrybystr=nil)and not(classparent=nil) then
  540. getinterfaceentrybystr:=classparent.getinterfaceentrybystr(iidstr)
  541. end;
  542. class function TObject.getinterfacetable : pinterfacetable;
  543. begin
  544. getinterfacetable:=pinterfacetable((pointer(Self)+vmtIntfTable)^);
  545. end;
  546. {****************************************************************************
  547. TINTERFACEDOBJECT
  548. ****************************************************************************}
  549. function TInterfacedObject.QueryInterface(
  550. const iid : tguid;out obj) : longint;stdcall;
  551. begin
  552. if getinterface(iid,obj) then
  553. result:=0
  554. else
  555. result:=longint($80004002);
  556. end;
  557. function TInterfacedObject._AddRef : longint;stdcall;
  558. begin
  559. inclocked(frefcount);
  560. _addref:=frefcount;
  561. end;
  562. function TInterfacedObject._Release : longint;stdcall;
  563. begin
  564. if declocked(frefcount) then
  565. begin
  566. self.destroy;
  567. _Release:=0;
  568. end
  569. else
  570. _Release:=frefcount;
  571. end;
  572. procedure TInterfacedObject.AfterConstruction;
  573. begin
  574. { we need to fix the refcount we forced in newinstance }
  575. { further, it must be done in a thread safe way }
  576. declocked(frefcount);
  577. end;
  578. procedure TInterfacedObject.BeforeDestruction;
  579. begin
  580. if frefcount<>0 then
  581. HandleError(204);
  582. end;
  583. class function TInterfacedObject.NewInstance : TObject;
  584. begin
  585. NewInstance:=inherited NewInstance;
  586. TInterfacedObject(NewInstance).frefcount:=1;
  587. end;
  588. {****************************************************************************
  589. Exception Support
  590. ****************************************************************************}
  591. {$i except.inc}