objpas.inc 25 KB

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