objpas.inc 29 KB

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