objpas.inc 29 KB

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