objpas.inc 28 KB

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