objpas.inc 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983
  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. {$ifdef FPC_HAS_FEATURE_VARIANTS}
  12. procedure DoDispCallByIDError(res : Pointer; const disp : IDispatch;desc : PDispDesc; params : Pointer);
  13. begin
  14. handleerrorframe(RuntimeErrorExitCodes[reVarDispatch],get_frame);
  15. end;
  16. procedure fpc_dispatch_by_id(Result: Pointer; const Dispatch: pointer;
  17. DispDesc: Pointer; Params: Pointer); compilerproc;
  18. type
  19. TDispProc = procedure(res : Pointer; const disp : IDispatch;desc : PDispDesc; params : Pointer);
  20. begin
  21. TDispProc(DispCallByIDProc)(Result,IDispatch(Dispatch),DispDesc,Params);
  22. end;
  23. {$endif FPC_HAS_FEATURE_VARIANTS}
  24. {****************************************************************************
  25. Internal Routines called from the Compiler
  26. ****************************************************************************}
  27. { the reverse order of the parameters make code generation easier }
  28. function fpc_do_is(aclass : tclass;aobject : tobject) : boolean;[public,alias: 'FPC_DO_IS']; compilerproc;
  29. begin
  30. fpc_do_is:=assigned(aobject) and assigned(aclass) and
  31. aobject.inheritsfrom(aclass);
  32. end;
  33. { the reverse order of the parameters make code generation easier }
  34. function fpc_do_as(aclass : tclass;aobject : tobject): tobject;[public,alias: 'FPC_DO_AS']; compilerproc;
  35. begin
  36. if assigned(aobject) and not(aobject.inheritsfrom(aclass)) then
  37. handleerrorframe(219,get_frame);
  38. result := aobject;
  39. end;
  40. { interface helpers }
  41. procedure fpc_intf_decr_ref(var i: pointer);[public,alias: 'FPC_INTF_DECR_REF']; compilerproc;
  42. begin
  43. if assigned(i) then
  44. begin
  45. IUnknown(i)._Release;
  46. i:=nil;
  47. end;
  48. end;
  49. { local declaration for intf_decr_ref for local access }
  50. procedure intf_decr_ref(var i: pointer); [external name 'FPC_INTF_DECR_REF'];
  51. procedure fpc_intf_incr_ref(i: pointer);[public,alias: 'FPC_INTF_INCR_REF']; compilerproc;
  52. begin
  53. if assigned(i) then
  54. IUnknown(i)._AddRef;
  55. end;
  56. { local declaration of intf_incr_ref for local access }
  57. procedure intf_incr_ref(i: pointer); [external name 'FPC_INTF_INCR_REF'];
  58. procedure fpc_intf_assign(var D: pointer; const S: pointer);[public,alias: 'FPC_INTF_ASSIGN']; compilerproc;
  59. begin
  60. if assigned(S) then
  61. IUnknown(S)._AddRef;
  62. if assigned(D) then
  63. IUnknown(D)._Release;
  64. D:=S;
  65. end;
  66. procedure fpc_intf_assign_by_iid(var D: pointer; const S: pointer; const iid: TGUID);[public,alias: 'FPC_INTF_ASSIGN2']; compilerproc;
  67. var
  68. tmp : pointer;
  69. begin
  70. if assigned(S) then
  71. begin
  72. tmp:=nil;
  73. if IUnknown(S).QueryInterface(iid,tmp)<>S_OK then
  74. handleerror(219);
  75. if assigned(D) then
  76. IUnknown(D)._Release;
  77. D:=tmp;
  78. end
  79. else
  80. begin
  81. if assigned(D) then
  82. IUnknown(D)._Release;
  83. D:=nil;
  84. end;
  85. end;
  86. function fpc_intf_as(const S: pointer; const iid: TGUID): IInterface;[public,alias: 'FPC_INTF_AS']; compilerproc;
  87. var
  88. tmpi: pointer; // _AddRef before _Release
  89. begin
  90. if assigned(S) then
  91. begin
  92. tmpi:=nil;
  93. if IUnknown(S).QueryInterface(iid,tmpi)<>S_OK then
  94. handleerror(219);
  95. pointer(fpc_intf_as):=tmpi;
  96. end
  97. else
  98. fpc_intf_as:=nil;
  99. end;
  100. function fpc_intf_as_class(const S: pointer; const aclass: tclass): pointer;[public,alias: 'FPC_INTF_AS_CLASS']; compilerproc;
  101. var
  102. tmpi: pointer;
  103. tmpo: tobject;
  104. begin
  105. if assigned(S) then
  106. begin
  107. tmpi := nil;
  108. if IUnknown(S).QueryInterface(IImplementorGetter, tmpi)=S_OK then
  109. begin
  110. tmpo := IImplementorGetter(tmpi).GetObject;
  111. IUnknown(tmpi)._Release;
  112. if not assigned(tmpo) or not tmpo.inheritsfrom(aclass) then
  113. handleerror(219);
  114. fpc_intf_as_class:=tmpo;
  115. end
  116. else
  117. handleerror(219);
  118. end
  119. else
  120. fpc_intf_as_class:=nil;
  121. end;
  122. function fpc_class_as_intf(const S: pointer; const iid: TGUID): IInterface;[public,alias: 'FPC_CLASS_AS_INTF']; compilerproc;
  123. var
  124. tmpi: pointer; // _AddRef before _Release
  125. tmpi2: pointer; // weak!
  126. begin
  127. if assigned(S) then
  128. begin
  129. tmpi:=nil;
  130. tmpi2:=nil;
  131. if not ((TObject(S).GetInterfaceWeak(IUnknown,tmpi2) and (IUnknown(tmpi2).QueryInterface(IID,tmpi)=S_OK)) or TObject(S).GetInterface(IID,tmpi)) then
  132. handleerror(219);
  133. pointer(fpc_class_as_intf):=tmpi;
  134. end
  135. else
  136. fpc_class_as_intf:=nil;
  137. end;
  138. function fpc_class_as_corbaintf(const S: pointer; const iid: Shortstring): Pointer;[public,alias: 'FPC_CLASS_AS_CORBAINTF']; compilerproc;
  139. var
  140. tmpi: pointer; // _AddRef before _Release
  141. begin
  142. if assigned(S) then
  143. begin
  144. tmpi:=nil;
  145. if not TObject(S).GetInterface(iid,tmpi) then
  146. handleerror(219);
  147. fpc_class_as_corbaintf:=tmpi;
  148. end
  149. else
  150. fpc_class_as_corbaintf:=nil;
  151. end;
  152. {****************************************************************************
  153. TOBJECT
  154. ****************************************************************************}
  155. constructor TObject.Create;
  156. begin
  157. end;
  158. destructor TObject.Destroy;
  159. begin
  160. end;
  161. procedure TObject.Free;
  162. begin
  163. // the call via self avoids a warning
  164. if self<>nil then
  165. self.destroy;
  166. end;
  167. class function TObject.InstanceSize : SizeInt;
  168. begin
  169. InstanceSize := PVmt(Self)^.vInstanceSize;
  170. end;
  171. var
  172. emptyintf: ptruint; public name 'FPC_EMPTYINTF';
  173. procedure InitInterfacePointers(objclass: tclass;instance : pointer);
  174. var
  175. ovmt: PVmt;
  176. i: longint;
  177. intftable: pinterfacetable;
  178. Res: pinterfaceentry;
  179. begin
  180. ovmt := PVmt(objclass);
  181. while assigned(ovmt) and (ovmt^.vIntfTable <> @emptyintf) do
  182. begin
  183. intftable:=ovmt^.vIntfTable;
  184. if assigned(intftable) then
  185. begin
  186. i:=intftable^.EntryCount;
  187. Res:=@intftable^.Entries[0];
  188. while i>0 do begin
  189. if Res^.IType = etStandard then
  190. ppointer(@(pbyte(instance)[Res^.IOffset]))^:=
  191. pointer(Res^.VTable);
  192. inc(Res);
  193. dec(i);
  194. end;
  195. end;
  196. ovmt:=ovmt^.vParent;
  197. end;
  198. end;
  199. class function TObject.InitInstance(instance : pointer) : tobject; {$ifdef SYSTEMINLINE} inline; {$ENDIF}
  200. begin
  201. { the size is saved at offset 0 }
  202. fillchar(instance^, InstanceSize, 0);
  203. { insert VMT pointer into the new created memory area }
  204. { (in class methods self contains the VMT!) }
  205. ppointer(instance)^:=pointer(self);
  206. if PVmt(self)^.vIntfTable <> @emptyintf then
  207. InitInterfacePointers(self,instance);
  208. InitInstance:=TObject(Instance);
  209. end;
  210. class function TObject.ClassParent : tclass;
  211. begin
  212. { type of self is class of tobject => it points to the vmt }
  213. { the parent vmt is saved at offset vmtParent }
  214. classparent:=tclass(PVmt(Self)^.vParent);
  215. end;
  216. class function TObject.NewInstance : tobject;
  217. var
  218. p : pointer;
  219. begin
  220. getmem(p, InstanceSize);
  221. if p <> nil then
  222. InitInstance(p);
  223. NewInstance:=TObject(p);
  224. end;
  225. procedure TObject.FreeInstance;
  226. begin
  227. CleanupInstance;
  228. FreeMem(Pointer(Self));
  229. end;
  230. class function TObject.ClassType : TClass;
  231. begin
  232. ClassType:=TClass(Pointer(Self))
  233. end;
  234. type
  235. tmethodnamerec = packed record
  236. name : pshortstring;
  237. addr : pointer;
  238. end;
  239. tmethodnametable = packed record
  240. count : dword;
  241. entries : packed array[0..0] of tmethodnamerec;
  242. end;
  243. pmethodnametable = ^tmethodnametable;
  244. class function TObject.MethodAddress(const name : shortstring) : pointer;
  245. var
  246. methodtable : pmethodnametable;
  247. i : dword;
  248. ovmt : PVmt;
  249. begin
  250. ovmt:=PVmt(self);
  251. while assigned(ovmt) do
  252. begin
  253. methodtable:=pmethodnametable(ovmt^.vMethodTable);
  254. if assigned(methodtable) then
  255. begin
  256. for i:=0 to methodtable^.count-1 do
  257. if ShortCompareText(methodtable^.entries[i].name^, name)=0 then
  258. begin
  259. MethodAddress:=methodtable^.entries[i].addr;
  260. exit;
  261. end;
  262. end;
  263. ovmt := ovmt^.vParent;
  264. end;
  265. MethodAddress:=nil;
  266. end;
  267. class function TObject.MethodName(address : pointer) : shortstring;
  268. var
  269. methodtable : pmethodnametable;
  270. i : dword;
  271. ovmt : PVmt;
  272. begin
  273. ovmt:=PVmt(self);
  274. while assigned(ovmt) do
  275. begin
  276. methodtable:=pmethodnametable(ovmt^.vMethodTable);
  277. if assigned(methodtable) then
  278. begin
  279. for i:=0 to methodtable^.count-1 do
  280. if methodtable^.entries[i].addr=address then
  281. begin
  282. MethodName:=methodtable^.entries[i].name^;
  283. exit;
  284. end;
  285. end;
  286. ovmt := ovmt^.vParent;
  287. end;
  288. MethodName:='';
  289. end;
  290. function TObject.FieldAddress(const name : shortstring) : pointer;
  291. type
  292. PFieldInfo = ^TFieldInfo;
  293. TFieldInfo =
  294. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  295. packed
  296. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  297. record
  298. FieldOffset: PtrUInt;
  299. ClassTypeIndex: Word;
  300. Name: ShortString;
  301. end;
  302. PFieldTable = ^TFieldTable;
  303. TFieldTable =
  304. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  305. packed
  306. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  307. record
  308. FieldCount: Word;
  309. ClassTable: Pointer;
  310. { should be array[Word] of TFieldInfo; but
  311. Elements have variant size! force at least proper alignment }
  312. Fields: array[0..0] of TFieldInfo
  313. end;
  314. var
  315. ovmt: PVmt;
  316. FieldTable: PFieldTable;
  317. FieldInfo: PFieldInfo;
  318. i: longint;
  319. begin
  320. if Length(name) > 0 then
  321. begin
  322. ovmt := PVmt(ClassType);
  323. while ovmt <> nil do
  324. begin
  325. FieldTable := PFieldTable(ovmt^.vFieldTable);
  326. if FieldTable <> nil then
  327. begin
  328. FieldInfo := @FieldTable^.Fields[0];
  329. for i := 0 to FieldTable^.FieldCount - 1 do
  330. begin
  331. if ShortCompareText(FieldInfo^.Name, name) = 0 then
  332. begin
  333. fieldaddress := Pointer(Self) + FieldInfo^.FieldOffset;
  334. exit;
  335. end;
  336. FieldInfo := PFieldInfo(PByte(@FieldInfo^.Name) + 1 + Length(FieldInfo^.Name));
  337. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  338. { align to largest field of TFieldInfo }
  339. FieldInfo := Align(FieldInfo, SizeOf(PtrUInt));
  340. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  341. end;
  342. end;
  343. { Try again with the parent class type }
  344. ovmt:=ovmt^.vParent;
  345. end;
  346. end;
  347. fieldaddress:=nil;
  348. end;
  349. function TObject.SafeCallException(exceptobject : tobject;
  350. exceptaddr : pointer) : HResult;
  351. begin
  352. safecallexception:=E_UNEXPECTED;
  353. end;
  354. class function TObject.ClassInfo : pointer;
  355. begin
  356. ClassInfo := PVmt(Self)^.vTypeInfo;
  357. end;
  358. class function TObject.ClassName : ShortString;
  359. begin
  360. ClassName := PVmt(Self)^.vClassName^;
  361. end;
  362. class function TObject.ClassNameIs(const name : string) : boolean;
  363. begin
  364. // call to ClassName inlined here, this eliminates stack and string copying.
  365. ClassNameIs:=ShortCompareText(PVmt(Self)^.vClassName^, name) = 0;
  366. end;
  367. class function TObject.InheritsFrom(aclass : TClass) : Boolean;
  368. var
  369. vmt: PVmt;
  370. begin
  371. if assigned(aclass) then
  372. begin
  373. vmt:=PVmt(self);
  374. while assigned(vmt) and (vmt <> PVmt(aclass)) do
  375. vmt := vmt^.vParent;
  376. InheritsFrom := (vmt = PVmt(aclass));
  377. end
  378. else
  379. inheritsFrom := False;
  380. end;
  381. class function TObject.stringmessagetable : pstringmessagetable;
  382. begin
  383. stringmessagetable:=PVmt(Self)^.vMsgStrPtr;
  384. end;
  385. type
  386. tmessagehandler = procedure(var msg) of object;
  387. procedure TObject.Dispatch(var message);
  388. type
  389. tmsgtable = packed record
  390. index : dword;
  391. method : pointer;
  392. end;
  393. pmsgtable = ^tmsgtable;
  394. var
  395. index : dword;
  396. count,i : longint;
  397. msgtable : pmsgtable;
  398. p : pointer;
  399. ovmt : PVmt;
  400. msghandler : tmessagehandler;
  401. begin
  402. index:=dword(message);
  403. ovmt := PVmt(ClassType);
  404. while assigned(ovmt) do
  405. begin
  406. // See if we have messages at all in this class.
  407. p:=ovmt^.vDynamicTable;
  408. If Assigned(p) then
  409. begin
  410. msgtable:=pmsgtable(p+4);
  411. count:=pdword(p)^;
  412. end
  413. else
  414. Count:=0;
  415. { later, we can implement a binary search here }
  416. for i:=0 to count-1 do
  417. begin
  418. if index=msgtable[i].index then
  419. begin
  420. TMethod(msghandler).Code:=msgtable[i].method;
  421. TMethod(msghandler).Data:=self;
  422. msghandler(message);
  423. exit;
  424. end;
  425. end;
  426. ovmt:=ovmt^.vParent;
  427. end;
  428. DefaultHandler(message);
  429. end;
  430. procedure TObject.DispatchStr(var message);
  431. type
  432. PSizeUInt = ^SizeUInt;
  433. var
  434. name : shortstring;
  435. count,i : longint;
  436. msgstrtable : pmsgstrtable;
  437. p: pstringmessagetable;
  438. ovmt : PVmt;
  439. msghandler : tmessagehandler;
  440. begin
  441. name:=pshortstring(@message)^;
  442. ovmt:=PVmt(ClassType);
  443. while assigned(ovmt) do
  444. begin
  445. p := ovmt^.vMsgStrPtr;
  446. if (P<>Nil) and (p^.count<>0) then
  447. begin
  448. count:=p^.count;
  449. msgstrtable:=@p^.msgstrtable;
  450. end
  451. else
  452. Count:=0;
  453. { later, we can implement a binary search here }
  454. for i:=0 to count-1 do
  455. begin
  456. if name=msgstrtable[i].name^ then
  457. begin
  458. TMethod(msghandler).Code:=msgstrtable[i].method;
  459. TMethod(msghandler).Data:=self;
  460. msghandler(message);
  461. exit;
  462. end;
  463. end;
  464. ovmt:=ovmt^.vParent;
  465. end;
  466. DefaultHandlerStr(message);
  467. end;
  468. procedure TObject.DefaultHandler(var message);
  469. begin
  470. end;
  471. procedure TObject.DefaultHandlerStr(var message);
  472. begin
  473. end;
  474. procedure TObject.CleanupInstance;
  475. Type
  476. TRecElem = packed Record
  477. Info : Pointer;
  478. Offset : Longint;
  479. end;
  480. {$ifdef CPU16}
  481. TRecElemArray = packed array[1..Maxint div sizeof(TRecElem)-1] of TRecElem;
  482. {$else CPU16}
  483. TRecElemArray = packed array[1..Maxint] of TRecElem;
  484. {$endif CPU16}
  485. PRecRec = ^TRecRec;
  486. TRecRec = record
  487. Size,Count : Longint;
  488. Elements : TRecElemArray;
  489. end;
  490. var
  491. vmt : PVmt;
  492. temp : pbyte;
  493. count,
  494. i : longint;
  495. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  496. recelem : TRecElem;
  497. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  498. begin
  499. vmt := PVmt(ClassType);
  500. while vmt<>nil do
  501. begin
  502. { This need to be included here, because Finalize()
  503. has should support for tkClass }
  504. Temp:= vmt^.vInitTable;
  505. if Assigned(Temp) then
  506. begin
  507. inc(Temp);
  508. I:=Temp^;
  509. inc(temp,I+1); // skip name string;
  510. temp:=aligntoptr(temp);
  511. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  512. move(PRecRec(Temp)^.Count,Count,sizeof(Count));
  513. {$else FPC_REQUIRES_PROPER_ALIGNMENT}
  514. Count:=PRecRec(Temp)^.Count; // get element Count
  515. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  516. For I:=1 to count do
  517. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  518. begin
  519. move(PRecRec(Temp)^.elements[I],RecElem,sizeof(RecElem));
  520. With RecElem do
  521. int_Finalize (pointer(self)+Offset,Info);
  522. end;
  523. {$else FPC_REQUIRES_PROPER_ALIGNMENT}
  524. With PRecRec(Temp)^.elements[I] do
  525. int_Finalize (pointer(self)+Offset,Info);
  526. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  527. end;
  528. vmt:= vmt^.vParent;
  529. end;
  530. end;
  531. procedure TObject.AfterConstruction;
  532. begin
  533. end;
  534. procedure TObject.BeforeDestruction;
  535. begin
  536. end;
  537. function IsGUIDEqual(const guid1, guid2: tguid): boolean;
  538. begin
  539. IsGUIDEqual:=
  540. (guid1.D1=guid2.D1) and
  541. (PDWORD(@guid1.D2)^=PDWORD(@guid2.D2)^) and
  542. (PDWORD(@guid1.D4[0])^=PDWORD(@guid2.D4[0])^) and
  543. (PDWORD(@guid1.D4[4])^=PDWORD(@guid2.D4[4])^);
  544. end;
  545. // Use of managed types should be avoided here; implicit _Addref/_Release
  546. // will end up in unpredictable behaviour if called on CORBA interfaces.
  547. type
  548. TInterfaceGetter = procedure(out Obj) of object;
  549. TClassGetter = function: TObject of object;
  550. function GetInterfaceByEntry(Instance: pointer; IEntry: pinterfaceentry; out obj): boolean;
  551. var
  552. Getter: TMethod;
  553. begin
  554. Pointer(Obj) := nil;
  555. Getter.Data := Instance;
  556. if Assigned(IEntry) and Assigned(Instance) then
  557. begin
  558. case IEntry^.IType of
  559. etStandard:
  560. Pointer(Obj) := PByte(instance)+IEntry^.IOffset;
  561. etFieldValue, etFieldValueClass:
  562. Pointer(obj) := PPointer(PByte(Instance)+IEntry^.IOffset)^;
  563. etVirtualMethodResult:
  564. begin
  565. // IOffset is relative to the VMT, not to instance.
  566. Getter.code := PPointer(PByte(PPointer(Instance)^) + IEntry^.IOffset)^;
  567. TInterfaceGetter(Getter)(obj);
  568. end;
  569. etVirtualMethodClass:
  570. begin
  571. // IOffset is relative to the VMT, not to instance.
  572. Getter.code := PPointer(PByte(PPointer(Instance)^) + IEntry^.IOffset)^;
  573. TObject(obj) := TClassGetter(Getter)();
  574. end;
  575. etStaticMethodResult:
  576. begin
  577. Getter.code := Pointer(IEntry^.IOffset);
  578. TInterfaceGetter(Getter)(obj);
  579. end;
  580. etStaticMethodClass:
  581. begin
  582. Getter.code := Pointer(IEntry^.IOffset);
  583. TObject(obj) := TClassGetter(Getter)();
  584. end;
  585. end;
  586. end;
  587. result := assigned(pointer(obj));
  588. end;
  589. function TObject.GetInterface(const iid : tguid;out obj) : boolean;
  590. var
  591. IEntry: PInterfaceEntry;
  592. Instance: TObject;
  593. begin
  594. Instance := self;
  595. repeat
  596. IEntry := Instance.GetInterfaceEntry(iid);
  597. result := GetInterfaceByEntry(Instance, IEntry, obj);
  598. if (not result) or
  599. (IEntry^.IType in [etStandard, etFieldValue,
  600. etStaticMethodResult, etVirtualMethodResult]) then
  601. Break;
  602. { if interface is implemented by a class-type property or field,
  603. continue search }
  604. Instance := TObject(obj);
  605. until False;
  606. { Getter function will normally AddRef, so adding another reference here
  607. will cause memleak. }
  608. if result and (IEntry^.IType in [etStandard, etFieldValue]) then
  609. IInterface(obj)._AddRef;
  610. end;
  611. function TObject.GetInterfaceWeak(const iid : tguid; out obj) : boolean;
  612. var
  613. IEntry: PInterfaceEntry;
  614. Instance: TObject;
  615. begin
  616. Instance := self;
  617. repeat
  618. IEntry := Instance.GetInterfaceEntry(iid);
  619. result := GetInterfaceByEntry(Instance, IEntry, obj);
  620. if (not result) or
  621. (IEntry^.IType in [etStandard, etFieldValue,
  622. etStaticMethodResult, etVirtualMethodResult]) then
  623. Break;
  624. { if interface is implemented by a class-type property or field,
  625. continue search }
  626. Instance := TObject(obj);
  627. until False;
  628. { Getter function will normally AddRef, so we have to release it,
  629. else the ref is not weak. }
  630. if result and not (IEntry^.IType in [etStandard, etFieldValue]) then
  631. IInterface(obj)._Release;
  632. end;
  633. function TObject.GetInterfaceByStr(const iidstr : shortstring;out obj) : boolean;
  634. var
  635. IEntry: PInterfaceEntry;
  636. Instance: TObject;
  637. begin
  638. Instance := self;
  639. repeat
  640. IEntry := Instance.GetInterfaceEntryByStr(iidstr);
  641. result := GetInterfaceByEntry(Instance, IEntry, obj);
  642. if (not result) or
  643. (IEntry^.IType in [etStandard, etFieldValue,
  644. etStaticMethodResult, etVirtualMethodResult]) then
  645. Break;
  646. { if interface is implemented by a class-type property or field,
  647. continue search }
  648. Instance := TObject(obj);
  649. until False;
  650. { Getter function will normally AddRef, so adding another reference here
  651. will cause memleak. (com interfaces only!) }
  652. if result and Assigned(IEntry^.IID) and (IEntry^.IType in [etStandard, etFieldValue]) then
  653. IInterface(obj)._AddRef;
  654. end;
  655. function TObject.GetInterface(const iidstr : shortstring;out obj) : boolean;
  656. begin
  657. Result := GetInterfaceByStr(iidstr,obj);
  658. end;
  659. class function TObject.GetInterfaceEntry(const iid : tguid) : pinterfaceentry;
  660. var
  661. i: longint;
  662. intftable: pinterfacetable;
  663. ovmt: PVmt;
  664. begin
  665. ovmt := PVmt(Self);
  666. while Assigned(ovmt) and (ovmt^.vIntfTable <> @emptyintf) do
  667. begin
  668. intftable:=ovmt^.vIntfTable;
  669. if assigned(intftable) then
  670. begin
  671. for i:=0 to intftable^.EntryCount-1 do
  672. begin
  673. result:=@intftable^.Entries[i];
  674. if assigned(Result^.iid) and IsGUIDEqual(Result^.iid^,iid) then
  675. Exit;
  676. end;
  677. end;
  678. ovmt := ovmt^.vParent;
  679. end;
  680. result := nil;
  681. end;
  682. class function TObject.GetInterfaceEntryByStr(const iidstr : shortstring) : pinterfaceentry;
  683. var
  684. i: longint;
  685. intftable: pinterfacetable;
  686. ovmt: PVmt;
  687. begin
  688. ovmt := PVmt(Self);
  689. while Assigned(ovmt) and (ovmt^.vIntfTable <> @emptyintf) do
  690. begin
  691. intftable:=ovmt^.vIntfTable;
  692. if assigned(intftable) then
  693. begin
  694. for i:=0 to intftable^.EntryCount-1 do
  695. begin
  696. result:=@intftable^.Entries[i];
  697. if assigned(result^.iidstr) and (result^.iidstr^ = iidstr) then
  698. Exit;
  699. end;
  700. end;
  701. ovmt := ovmt^.vParent;
  702. end;
  703. result:=nil;
  704. end;
  705. class function TObject.GetInterfaceTable : pinterfacetable;
  706. begin
  707. getinterfacetable:=PVmt(Self)^.vIntfTable;
  708. end;
  709. class function TObject.UnitName : ansistring;
  710. type
  711. // from the typinfo unit
  712. TClassTypeInfo = {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  713. ClassType: TClass;
  714. ParentInfo: Pointer;
  715. PropCount: SmallInt;
  716. UnitName: ShortString;
  717. end;
  718. PClassTypeInfo = ^TClassTypeInfo;
  719. var
  720. classtypeinfo: PClassTypeInfo;
  721. begin
  722. classtypeinfo:=ClassInfo;
  723. if Assigned(classtypeinfo) then
  724. begin
  725. // offset PTypeInfo by Length(Name) + 2 (ShortString length byte + SizeOf(Kind))
  726. inc(Pointer(classtypeinfo), PByte(Pointer(classtypeinfo)+1)^ + 2);
  727. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  728. classtypeinfo:=align(classtypeinfo,sizeof(classtypeinfo));
  729. {$endif}
  730. result:=classtypeinfo^.UnitName;
  731. end
  732. else
  733. result:='';
  734. end;
  735. function TObject.Equals(Obj: TObject) : boolean;
  736. begin
  737. result:=Obj=Self;
  738. end;
  739. function TObject.GetHashCode: PtrInt;
  740. begin
  741. result:=PtrInt(Self);
  742. end;
  743. function TObject.ToString: ansistring;
  744. begin
  745. result:=ClassName;
  746. end;
  747. {****************************************************************************
  748. TINTERFACEDOBJECT
  749. ****************************************************************************}
  750. function TInterfacedObject.QueryInterface(
  751. const iid : tguid;out obj) : longint;stdcall;
  752. begin
  753. if getinterface(iid,obj) then
  754. result:=S_OK
  755. else
  756. result:=longint(E_NOINTERFACE);
  757. end;
  758. function TInterfacedObject._AddRef : longint;stdcall;
  759. begin
  760. _addref:=interlockedincrement(frefcount);
  761. end;
  762. function TInterfacedObject._Release : longint;stdcall;
  763. begin
  764. _Release:=interlockeddecrement(frefcount);
  765. if _Release=0 then
  766. self.destroy;
  767. end;
  768. function TInterfacedObject.GetObject : TObject;
  769. begin
  770. GetObject:=Self;
  771. end;
  772. procedure TInterfacedObject.AfterConstruction;
  773. begin
  774. { we need to fix the refcount we forced in newinstance }
  775. { further, it must be done in a thread safe way }
  776. declocked(frefcount);
  777. end;
  778. procedure TInterfacedObject.BeforeDestruction;
  779. begin
  780. if frefcount<>0 then
  781. HandleError(204);
  782. end;
  783. class function TInterfacedObject.NewInstance : TObject;
  784. begin
  785. NewInstance:=inherited NewInstance;
  786. if NewInstance<>nil then
  787. TInterfacedObject(NewInstance).frefcount:=1;
  788. end;
  789. {****************************************************************************
  790. TAGGREGATEDOBJECT
  791. ****************************************************************************}
  792. constructor TAggregatedObject.Create(const aController: IUnknown);
  793. begin
  794. inherited Create;
  795. { do not keep a counted reference to the controller! }
  796. fcontroller := Pointer(aController);
  797. end;
  798. function TAggregatedObject.QueryInterface(
  799. const iid : tguid;out obj) : longint;stdcall;
  800. begin
  801. Result := IUnknown(fcontroller).QueryInterface(iid, obj);
  802. end;
  803. function TAggregatedObject._AddRef : longint;stdcall;
  804. begin
  805. Result := IUnknown(fcontroller)._AddRef;
  806. end;
  807. function TAggregatedObject._Release : longint;stdcall;
  808. begin
  809. Result := IUnknown(fcontroller)._Release;
  810. end;
  811. function TAggregatedObject.GetController : IUnknown;
  812. begin
  813. Result := IUnknown(fcontroller);
  814. end;
  815. {****************************************************************************
  816. TContainedOBJECT
  817. ****************************************************************************}
  818. function TContainedObject.QueryInterface(
  819. const iid : tguid;out obj) : longint; stdcall;
  820. begin
  821. if getinterface(iid,obj) then
  822. result:=S_OK
  823. else
  824. result:=longint(E_NOINTERFACE);
  825. end;
  826. {****************************************************************************
  827. Exception Support
  828. ****************************************************************************}
  829. {$ifdef FPC_HAS_FEATURE_EXCEPTIONS}
  830. {$i except.inc}
  831. {$endif FPC_HAS_FEATURE_EXCEPTIONS}