objpas.inc 24 KB

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