objpas.inc 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071
  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. handleerroraddrframeind(RuntimeErrorExitCodes[reVarDispatch],
  15. get_pc_addr,get_frame);
  16. end;
  17. procedure fpc_dispatch_by_id(Result: Pointer; const Dispatch: pointer;
  18. DispDesc: Pointer; Params: Pointer); compilerproc;
  19. type
  20. TDispProc = procedure(res : Pointer; const disp : IDispatch;desc : PDispDesc; params : Pointer);
  21. begin
  22. TDispProc(DispCallByIDProc)(Result,IDispatch(Dispatch),DispDesc,Params);
  23. end;
  24. {$endif FPC_HAS_FEATURE_VARIANTS}
  25. {****************************************************************************
  26. Internal Routines called from the Compiler
  27. ****************************************************************************}
  28. { the reverse order of the parameters make code generation easier }
  29. function fpc_do_is(aclass : tclass;aobject : tobject) : boolean;[public,alias: 'FPC_DO_IS']; compilerproc;
  30. begin
  31. fpc_do_is:=assigned(aobject) and assigned(aclass) and
  32. aobject.inheritsfrom(aclass);
  33. end;
  34. { the reverse order of the parameters make code generation easier }
  35. function fpc_do_as(aclass : tclass;aobject : tobject): tobject;[public,alias: 'FPC_DO_AS']; compilerproc;
  36. begin
  37. if assigned(aobject) and not(aobject.inheritsfrom(aclass)) then
  38. handleerroraddrframeInd(219,get_pc_addr,get_frame);
  39. result := aobject;
  40. end;
  41. { interface helpers }
  42. procedure fpc_intf_decr_ref(var i: pointer);[public,alias: 'FPC_INTF_DECR_REF']; compilerproc;
  43. begin
  44. if assigned(i) then
  45. begin
  46. IUnknown(i)._Release;
  47. i:=nil;
  48. end;
  49. end;
  50. { local declaration for intf_decr_ref for local access }
  51. procedure intf_decr_ref(var i: pointer); [external name 'FPC_INTF_DECR_REF'];
  52. procedure fpc_intf_incr_ref(i: pointer);[public,alias: 'FPC_INTF_INCR_REF']; compilerproc;
  53. begin
  54. if assigned(i) then
  55. IUnknown(i)._AddRef;
  56. end;
  57. { local declaration of intf_incr_ref for local access }
  58. procedure intf_incr_ref(i: pointer); [external name 'FPC_INTF_INCR_REF'];
  59. procedure fpc_intf_assign(var D: pointer; const S: pointer);[public,alias: 'FPC_INTF_ASSIGN']; compilerproc;
  60. begin
  61. if assigned(S) then
  62. IUnknown(S)._AddRef;
  63. if assigned(D) then
  64. IUnknown(D)._Release;
  65. D:=S;
  66. end;
  67. procedure fpc_intf_assign(var D: pointer; const s: pointer); [external name 'FPC_INTF_ASSIGN'];
  68. {procedure fpc_intf_assign_by_iid(var D: pointer; const S: pointer; const iid: TGUID);[public,alias: 'FPC_INTF_ASSIGN2']; compilerproc;
  69. var
  70. tmp : pointer;
  71. begin
  72. if assigned(S) then
  73. begin
  74. tmp:=nil;
  75. if IUnknown(S).QueryInterface(iid,tmp)<>S_OK then
  76. handleerror(219);
  77. if assigned(D) then
  78. IUnknown(D)._Release;
  79. D:=tmp;
  80. end
  81. else
  82. begin
  83. if assigned(D) then
  84. IUnknown(D)._Release;
  85. D:=nil;
  86. end;
  87. end;}
  88. function fpc_intf_is(const S: pointer; const iid: TGUID): Boolean;[public,alias: 'FPC_INTF_IS']; compilerproc;
  89. var
  90. tmpi: pointer;
  91. begin
  92. tmpi:=nil;
  93. fpc_intf_is:=Assigned(S) and (IUnknown(S).QueryInterface(iid,tmpi)=S_OK);
  94. if Assigned(tmpi) then
  95. IUnknown(tmpi)._Release;
  96. end;
  97. function fpc_intf_is_class(const S: pointer; const aclass: tclass): Boolean;[public,alias: 'FPC_INTF_IS_CLASS']; compilerproc;
  98. var
  99. tmpo: tobject;
  100. begin
  101. fpc_intf_is_class:=Assigned(S) and (IUnknown(S).QueryInterface(IObjectInstance,tmpo)=S_OK) and tmpo.InheritsFrom(aclass);
  102. end;
  103. function fpc_class_is_intf(const S: pointer; const iid: TGUID): Boolean;[public,alias: 'FPC_CLASS_IS_INTF']; compilerproc;
  104. var
  105. tmpi: pointer;
  106. tmpi2: pointer; // weak!
  107. begin
  108. tmpi:=nil;
  109. tmpi2:=nil;
  110. fpc_class_is_intf:=Assigned(S) and ((TObject(S).GetInterfaceWeak(IUnknown,tmpi2) and (IUnknown(tmpi2).QueryInterface(IID,tmpi)=S_OK)) or
  111. TObject(S).GetInterface(IID,tmpi));
  112. if Assigned(tmpi) then
  113. IUnknown(tmpi)._Release;
  114. end;
  115. function fpc_class_is_corbaintf(const S: pointer; const iid: Shortstring): Boolean;[public,alias: 'FPC_CLASS_IS_CORBAINTF']; compilerproc;
  116. begin
  117. fpc_class_is_corbaintf:=Assigned(S) and Assigned(TObject(S).GetInterfaceEntryByStr(iid));
  118. end;
  119. function fpc_intf_cast(const S: pointer; const iid: TGUID): IInterface;[public,alias: 'FPC_INTF_CAST']; compilerproc;
  120. var
  121. tmpi: pointer;
  122. begin
  123. tmpi:=nil;
  124. if Assigned(S) and (IUnknown(S).QueryInterface(iid,tmpi)=S_OK) then
  125. pointer(fpc_intf_cast):=tmpi
  126. else
  127. fpc_intf_cast:= nil;
  128. end;
  129. function fpc_intf_cast_class(const S: pointer; const aclass: tclass): pointer;[public,alias: 'FPC_INTF_CAST_CLASS']; compilerproc;
  130. var
  131. tmpo: tobject;
  132. begin
  133. if Assigned(S) and (IUnknown(S).QueryInterface(IObjectInstance,tmpo)=S_OK) and tmpo.InheritsFrom(aclass) then
  134. fpc_intf_cast_class:=tmpo
  135. else
  136. fpc_intf_cast_class:=nil;
  137. end;
  138. function fpc_class_cast_intf(const S: pointer; const iid: TGUID): IInterface;[public,alias: 'FPC_CLASS_CAST_INTF']; compilerproc;
  139. var
  140. tmpi: pointer;
  141. tmpi2: pointer; // weak!
  142. begin
  143. tmpi:=nil;
  144. tmpi2:=nil;
  145. if Assigned(S) and ((TObject(S).GetInterfaceWeak(IUnknown,tmpi2) and (IUnknown(tmpi2).QueryInterface(IID,tmpi)=S_OK)) or
  146. TObject(S).GetInterface(IID,tmpi)) then
  147. begin
  148. // decrease reference count
  149. fpc_class_cast_intf:=nil;
  150. pointer(fpc_class_cast_intf):=tmpi
  151. end
  152. else
  153. fpc_class_cast_intf:=nil;
  154. end;
  155. function fpc_class_cast_corbaintf(const S: pointer; const iid: Shortstring): Pointer;[public,alias: 'FPC_CLASS_CAST_CORBAINTF']; compilerproc;
  156. var
  157. tmpi: pointer;
  158. begin
  159. if Assigned(S) and TObject(S).GetInterface(iid,tmpi) then
  160. fpc_class_cast_corbaintf:=tmpi
  161. else
  162. fpc_class_cast_corbaintf:=nil;
  163. end;
  164. function fpc_intf_as(const S: pointer; const iid: TGUID): IInterface;[public,alias: 'FPC_INTF_AS']; compilerproc;
  165. var
  166. tmpi: pointer; // _AddRef before _Release
  167. begin
  168. if assigned(S) then
  169. begin
  170. tmpi:=nil;
  171. if IUnknown(S).QueryInterface(iid,tmpi)<>S_OK then
  172. handleerror(219);
  173. // decrease reference count
  174. fpc_intf_as:=nil;
  175. pointer(fpc_intf_as):=tmpi;
  176. end
  177. else
  178. fpc_intf_as:=nil;
  179. end;
  180. function fpc_intf_as_class(const S: pointer; const aclass: tclass): pointer;[public,alias: 'FPC_INTF_AS_CLASS']; compilerproc;
  181. var
  182. tmpo: tobject;
  183. begin
  184. if assigned(S) then
  185. begin
  186. if not ((IUnknown(S).QueryInterface(IObjectInstance,tmpo)=S_OK) and tmpo.inheritsfrom(aclass)) then
  187. handleerror(219);
  188. fpc_intf_as_class:=tmpo;
  189. end
  190. else
  191. fpc_intf_as_class:=nil;
  192. end;
  193. function fpc_class_as_intf(const S: pointer; const iid: TGUID): IInterface;[public,alias: 'FPC_CLASS_AS_INTF']; compilerproc;
  194. var
  195. tmpi: pointer; // _AddRef before _Release
  196. tmpi2: pointer; // weak!
  197. begin
  198. if assigned(S) then
  199. begin
  200. tmpi:=nil;
  201. tmpi2:=nil;
  202. if not ((TObject(S).GetInterfaceWeak(IUnknown,tmpi2) and (IUnknown(tmpi2).QueryInterface(IID,tmpi)=S_OK)) or TObject(S).GetInterface(IID,tmpi)) then
  203. handleerror(219);
  204. // decrease reference count
  205. fpc_class_as_intf:=nil;
  206. pointer(fpc_class_as_intf):=tmpi;
  207. end
  208. else
  209. fpc_class_as_intf:=nil;
  210. end;
  211. function fpc_class_as_corbaintf(const S: pointer; const iid: Shortstring): Pointer;[public,alias: 'FPC_CLASS_AS_CORBAINTF']; compilerproc;
  212. var
  213. tmpi: pointer; // _AddRef before _Release
  214. begin
  215. if assigned(S) then
  216. begin
  217. tmpi:=nil;
  218. if not TObject(S).GetInterface(iid,tmpi) then
  219. handleerror(219);
  220. fpc_class_as_corbaintf:=tmpi;
  221. end
  222. else
  223. fpc_class_as_corbaintf:=nil;
  224. end;
  225. {****************************************************************************
  226. TOBJECT
  227. ****************************************************************************}
  228. function TVmt.GetvParent: PVmt;
  229. begin
  230. {$ifdef ver2_6}
  231. Result:=vParentRef;
  232. {$else}
  233. if Assigned(vParentRef) then
  234. Result:=vParentRef^
  235. else
  236. Result:=Nil;
  237. {$endif}
  238. end;
  239. {****************************************************************************
  240. TOBJECT
  241. ****************************************************************************}
  242. constructor TObject.Create;
  243. begin
  244. end;
  245. destructor TObject.Destroy;
  246. begin
  247. end;
  248. procedure TObject.Free;
  249. begin
  250. // the call via self avoids a warning
  251. if self<>nil then
  252. self.destroy;
  253. end;
  254. class function TObject.InstanceSize : SizeInt;
  255. begin
  256. InstanceSize := PVmt(Self)^.vInstanceSize;
  257. end;
  258. var
  259. emptyintf: ptruint; public name 'FPC_EMPTYINTF';
  260. const
  261. emptyintfptr: pinterfacetable = {$ifdef ver2_6}@emptyintf{$else}pinterfacetable(1){$endif};
  262. procedure InitInterfacePointers(objclass: tclass;instance : pointer);
  263. var
  264. ovmt: PVmt;
  265. i: longint;
  266. intftable: pinterfacetable;
  267. Res: pinterfaceentry;
  268. begin
  269. ovmt := PVmt(objclass);
  270. while assigned(ovmt) and (ovmt^.vIntfTable <> emptyintfptr) do
  271. begin
  272. intftable:=ovmt^.vIntfTable;
  273. if assigned(intftable) then
  274. begin
  275. i:=intftable^.EntryCount;
  276. Res:=@intftable^.Entries[0];
  277. while i>0 do begin
  278. if Res^.IType = etStandard then
  279. ppointer(@(pbyte(instance)[Res^.IOffset]))^:=
  280. pointer(Res^.VTable);
  281. inc(Res);
  282. dec(i);
  283. end;
  284. end;
  285. ovmt:=ovmt^.vParent;
  286. end;
  287. end;
  288. class function TObject.InitInstance(instance : pointer) : tobject; {$ifdef SYSTEMINLINE} inline; {$ENDIF}
  289. begin
  290. { the size is saved at offset 0 }
  291. fillchar(instance^, InstanceSize, 0);
  292. { insert VMT pointer into the new created memory area }
  293. { (in class methods self contains the VMT!) }
  294. ppointer(instance)^:=pointer(self);
  295. if PVmt(self)^.vIntfTable <> emptyintfptr then
  296. InitInterfacePointers(self,instance);
  297. InitInstance:=TObject(Instance);
  298. end;
  299. class function TObject.ClassParent : tclass;
  300. begin
  301. { type of self is class of tobject => it points to the vmt }
  302. { the parent vmt is saved at offset vmtParent }
  303. classparent:=tclass(PVmt(Self)^.vParent);
  304. end;
  305. class function TObject.NewInstance : tobject;
  306. var
  307. p : pointer;
  308. begin
  309. getmem(p, InstanceSize);
  310. if p <> nil then
  311. InitInstance(p);
  312. NewInstance:=TObject(p);
  313. end;
  314. procedure TObject.FreeInstance;
  315. begin
  316. CleanupInstance;
  317. FreeMem(Pointer(Self));
  318. end;
  319. class function TObject.ClassType : TClass;
  320. begin
  321. ClassType:=TClass(Pointer(Self))
  322. end;
  323. type
  324. tmethodnamerec = packed record
  325. name : pshortstring;
  326. addr : codepointer;
  327. end;
  328. tmethodnametable = packed record
  329. count : dword;
  330. entries : packed array[0..0] of tmethodnamerec;
  331. end;
  332. pmethodnametable = ^tmethodnametable;
  333. class function TObject.MethodAddress(const name : shortstring) : codepointer;
  334. var
  335. methodtable : pmethodnametable;
  336. i : dword;
  337. ovmt : PVmt;
  338. begin
  339. ovmt:=PVmt(self);
  340. while assigned(ovmt) do
  341. begin
  342. methodtable:=pmethodnametable(ovmt^.vMethodTable);
  343. if assigned(methodtable) then
  344. begin
  345. for i:=0 to methodtable^.count-1 do
  346. if ShortCompareText(methodtable^.entries[i].name^, name)=0 then
  347. begin
  348. MethodAddress:=methodtable^.entries[i].addr;
  349. exit;
  350. end;
  351. end;
  352. ovmt := ovmt^.vParent;
  353. end;
  354. MethodAddress:=nil;
  355. end;
  356. class function TObject.MethodName(address : codepointer) : shortstring;
  357. var
  358. methodtable : pmethodnametable;
  359. i : dword;
  360. ovmt : PVmt;
  361. begin
  362. ovmt:=PVmt(self);
  363. while assigned(ovmt) do
  364. begin
  365. methodtable:=pmethodnametable(ovmt^.vMethodTable);
  366. if assigned(methodtable) then
  367. begin
  368. for i:=0 to methodtable^.count-1 do
  369. if methodtable^.entries[i].addr=address then
  370. begin
  371. MethodName:=methodtable^.entries[i].name^;
  372. exit;
  373. end;
  374. end;
  375. ovmt := ovmt^.vParent;
  376. end;
  377. MethodName:='';
  378. end;
  379. function TObject.FieldAddress(const name : shortstring) : pointer;
  380. type
  381. PFieldInfo = ^TFieldInfo;
  382. TFieldInfo =
  383. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  384. packed
  385. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  386. record
  387. FieldOffset: PtrUInt;
  388. ClassTypeIndex: Word;
  389. Name: ShortString;
  390. end;
  391. PFieldTable = ^TFieldTable;
  392. TFieldTable =
  393. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  394. packed
  395. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  396. record
  397. FieldCount: Word;
  398. ClassTable: Pointer;
  399. { should be array[Word] of TFieldInfo; but
  400. Elements have variant size! force at least proper alignment }
  401. Fields: array[0..0] of TFieldInfo
  402. end;
  403. var
  404. ovmt: PVmt;
  405. FieldTable: PFieldTable;
  406. FieldInfo: PFieldInfo;
  407. i: longint;
  408. begin
  409. if Length(name) > 0 then
  410. begin
  411. ovmt := PVmt(ClassType);
  412. while ovmt <> nil do
  413. begin
  414. FieldTable := PFieldTable(ovmt^.vFieldTable);
  415. if FieldTable <> nil then
  416. begin
  417. FieldInfo := @FieldTable^.Fields[0];
  418. for i := 0 to FieldTable^.FieldCount - 1 do
  419. begin
  420. if ShortCompareText(FieldInfo^.Name, name) = 0 then
  421. begin
  422. fieldaddress := Pointer(Self) + FieldInfo^.FieldOffset;
  423. exit;
  424. end;
  425. FieldInfo := PFieldInfo(PByte(@FieldInfo^.Name) + 1 + Length(FieldInfo^.Name));
  426. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  427. { align to largest field of TFieldInfo }
  428. FieldInfo := Align(FieldInfo, SizeOf(PtrUInt));
  429. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  430. end;
  431. end;
  432. { Try again with the parent class type }
  433. ovmt:=ovmt^.vParent;
  434. end;
  435. end;
  436. fieldaddress:=nil;
  437. end;
  438. function TObject.SafeCallException(exceptobject : tobject;
  439. exceptaddr : codepointer) : HResult;
  440. begin
  441. safecallexception:=E_UNEXPECTED;
  442. end;
  443. class function TObject.ClassInfo : pointer;
  444. begin
  445. ClassInfo := PVmt(Self)^.vTypeInfo;
  446. end;
  447. class function TObject.ClassName : ShortString;
  448. begin
  449. ClassName := PVmt(Self)^.vClassName^;
  450. end;
  451. class function TObject.ClassNameIs(const name : string) : boolean;
  452. begin
  453. // call to ClassName inlined here, this eliminates stack and string copying.
  454. ClassNameIs:=ShortCompareText(PVmt(Self)^.vClassName^, name) = 0;
  455. end;
  456. class function TObject.InheritsFrom(aclass : TClass) : Boolean;
  457. var
  458. vmt: PVmt;
  459. begin
  460. if assigned(aclass) then
  461. begin
  462. vmt:=PVmt(self);
  463. while assigned(vmt) and (vmt <> PVmt(aclass)) do
  464. vmt := vmt^.vParent;
  465. InheritsFrom := (vmt = PVmt(aclass));
  466. end
  467. else
  468. inheritsFrom := False;
  469. end;
  470. class function TObject.stringmessagetable : pstringmessagetable;
  471. begin
  472. stringmessagetable:=PVmt(Self)^.vMsgStrPtr;
  473. end;
  474. type
  475. tmessagehandler = procedure(var msg) of object;
  476. procedure TObject.Dispatch(var message);
  477. type
  478. {$PUSH}
  479. {$PACKRECORDS NORMAL}
  480. PMsgIntTable = ^TMsgIntTable;
  481. TMsgIntTable = record
  482. index : dword;
  483. method : codepointer;
  484. end;
  485. PMsgInt = ^TMsgInt;
  486. TMsgInt = record
  487. count : longint;
  488. msgs : array[0..0] of TMsgIntTable;
  489. end;
  490. {$POP}
  491. var
  492. index : dword;
  493. count,i : longint;
  494. msgtable : PMsgIntTable;
  495. p : PMsgInt;
  496. ovmt : PVmt;
  497. msghandler : tmessagehandler;
  498. begin
  499. index:=dword(message);
  500. ovmt := PVmt(ClassType);
  501. while assigned(ovmt) do
  502. begin
  503. // See if we have messages at all in this class.
  504. p:=PMsgInt(ovmt^.vDynamicTable);
  505. If Assigned(p) then
  506. begin
  507. msgtable:=@p^.msgs;
  508. count:=p^.count;
  509. end
  510. else
  511. Count:=0;
  512. { later, we can implement a binary search here }
  513. for i:=0 to count-1 do
  514. begin
  515. if index=msgtable[i].index then
  516. begin
  517. TMethod(msghandler).Code:=msgtable[i].method;
  518. TMethod(msghandler).Data:=self;
  519. msghandler(message);
  520. exit;
  521. end;
  522. end;
  523. ovmt:=ovmt^.vParent;
  524. end;
  525. DefaultHandler(message);
  526. end;
  527. procedure TObject.DispatchStr(var message);
  528. var
  529. name : shortstring;
  530. count,i : longint;
  531. msgstrtable : pmsgstrtable;
  532. p: pstringmessagetable;
  533. ovmt : PVmt;
  534. msghandler : tmessagehandler;
  535. begin
  536. name:=pshortstring(@message)^;
  537. ovmt:=PVmt(ClassType);
  538. while assigned(ovmt) do
  539. begin
  540. p := ovmt^.vMsgStrPtr;
  541. if (P<>Nil) and (p^.count<>0) then
  542. begin
  543. count:=p^.count;
  544. msgstrtable:=@p^.msgstrtable;
  545. end
  546. else
  547. Count:=0;
  548. { later, we can implement a binary search here }
  549. for i:=0 to count-1 do
  550. begin
  551. if name=msgstrtable[i].name^ then
  552. begin
  553. TMethod(msghandler).Code:=msgstrtable[i].method;
  554. TMethod(msghandler).Data:=self;
  555. msghandler(message);
  556. exit;
  557. end;
  558. end;
  559. ovmt:=ovmt^.vParent;
  560. end;
  561. DefaultHandlerStr(message);
  562. end;
  563. procedure TObject.DefaultHandler(var message);
  564. begin
  565. end;
  566. procedure TObject.DefaultHandlerStr(var message);
  567. begin
  568. end;
  569. procedure TObject.CleanupInstance;
  570. var
  571. vmt : PVmt;
  572. temp : pointer;
  573. begin
  574. vmt := PVmt(ClassType);
  575. while vmt<>nil do
  576. begin
  577. Temp:= vmt^.vInitTable;
  578. { The RTTI format matches one for records, except the type is tkClass.
  579. Since RecordRTTI does not check the type, calling it yields the desired result. }
  580. if Assigned(Temp) then
  581. RecordRTTI(Self,Temp,@int_finalize);
  582. vmt:= vmt^.vParent;
  583. end;
  584. end;
  585. procedure TObject.AfterConstruction;
  586. begin
  587. end;
  588. procedure TObject.BeforeDestruction;
  589. begin
  590. end;
  591. function IsGUIDEqual(const guid1, guid2: tguid): boolean;
  592. begin
  593. IsGUIDEqual:=
  594. (guid1.D1=guid2.D1) and
  595. (PDWORD(@guid1.D2)^=PDWORD(@guid2.D2)^) and
  596. (PDWORD(@guid1.D4[0])^=PDWORD(@guid2.D4[0])^) and
  597. (PDWORD(@guid1.D4[4])^=PDWORD(@guid2.D4[4])^);
  598. end;
  599. // Use of managed types should be avoided here; implicit _Addref/_Release
  600. // will end up in unpredictable behaviour if called on CORBA interfaces.
  601. type
  602. TInterfaceGetter = procedure(out Obj) of object;
  603. TClassGetter = function: TObject of object;
  604. function GetInterfaceByEntry(Instance: pointer; IEntry: pinterfaceentry; out obj): boolean;
  605. var
  606. Getter: TMethod;
  607. begin
  608. Pointer(Obj) := nil;
  609. Getter.Data := Instance;
  610. if Assigned(IEntry) and Assigned(Instance) then
  611. begin
  612. case IEntry^.IType of
  613. etStandard:
  614. Pointer(Obj) := PByte(instance)+IEntry^.IOffset;
  615. etFieldValue, etFieldValueClass:
  616. Pointer(obj) := PPointer(PByte(Instance)+IEntry^.IOffset)^;
  617. etVirtualMethodResult:
  618. begin
  619. // IOffset is relative to the VMT, not to instance.
  620. Getter.code := PCodePointer(PByte(PPointer(Instance)^) + IEntry^.IOffset)^;
  621. TInterfaceGetter(Getter)(obj);
  622. end;
  623. etVirtualMethodClass:
  624. begin
  625. // IOffset is relative to the VMT, not to instance.
  626. Getter.code := PCodePointer(PByte(PPointer(Instance)^) + IEntry^.IOffset)^;
  627. TObject(obj) := TClassGetter(Getter)();
  628. end;
  629. etStaticMethodResult:
  630. begin
  631. Getter.code := CodePointer(IEntry^.IOffset);
  632. TInterfaceGetter(Getter)(obj);
  633. end;
  634. etStaticMethodClass:
  635. begin
  636. Getter.code := CodePointer(IEntry^.IOffset);
  637. TObject(obj) := TClassGetter(Getter)();
  638. end;
  639. end;
  640. end;
  641. result := assigned(pointer(obj));
  642. end;
  643. function TObject.GetInterface(const iid : tguid;out obj) : boolean;
  644. var
  645. IEntry: PInterfaceEntry;
  646. Instance: TObject;
  647. begin
  648. if IsGUIDEqual(IObjectInstance,iid) then
  649. begin
  650. TObject(Obj) := Self;
  651. Result := True;
  652. Exit;
  653. end;
  654. Instance := self;
  655. repeat
  656. IEntry := Instance.GetInterfaceEntry(iid);
  657. result := GetInterfaceByEntry(Instance, IEntry, obj);
  658. if (not result) or
  659. (IEntry^.IType in [etStandard, etFieldValue,
  660. etStaticMethodResult, etVirtualMethodResult]) then
  661. Break;
  662. { if interface is implemented by a class-type property or field,
  663. continue search }
  664. Instance := TObject(obj);
  665. until False;
  666. { Getter function will normally AddRef, so adding another reference here
  667. will cause memleak. }
  668. if result and (IEntry^.IType in [etStandard, etFieldValue]) then
  669. IInterface(obj)._AddRef;
  670. end;
  671. function TObject.GetInterfaceWeak(const iid : tguid; out obj) : boolean;
  672. var
  673. IEntry: PInterfaceEntry;
  674. Instance: TObject;
  675. begin
  676. if IsGUIDEqual(IObjectInstance,iid) then
  677. begin
  678. TObject(Obj) := Self;
  679. Result := True;
  680. Exit;
  681. end;
  682. Instance := self;
  683. repeat
  684. IEntry := Instance.GetInterfaceEntry(iid);
  685. result := GetInterfaceByEntry(Instance, IEntry, obj);
  686. if (not result) or
  687. (IEntry^.IType in [etStandard, etFieldValue,
  688. etStaticMethodResult, etVirtualMethodResult]) then
  689. Break;
  690. { if interface is implemented by a class-type property or field,
  691. continue search }
  692. Instance := TObject(obj);
  693. until False;
  694. { Getter function will normally AddRef, so we have to release it,
  695. else the ref is not weak. }
  696. if result and not (IEntry^.IType in [etStandard, etFieldValue]) then
  697. IInterface(obj)._Release;
  698. end;
  699. function TObject.GetInterfaceByStr(const iidstr : shortstring;out obj) : boolean;
  700. var
  701. IEntry: PInterfaceEntry;
  702. Instance: TObject;
  703. begin
  704. Instance := self;
  705. repeat
  706. IEntry := Instance.GetInterfaceEntryByStr(iidstr);
  707. result := GetInterfaceByEntry(Instance, IEntry, obj);
  708. if (not result) or
  709. (IEntry^.IType in [etStandard, etFieldValue,
  710. etStaticMethodResult, etVirtualMethodResult]) then
  711. Break;
  712. { if interface is implemented by a class-type property or field,
  713. continue search }
  714. Instance := TObject(obj);
  715. until False;
  716. { Getter function will normally AddRef, so adding another reference here
  717. will cause memleak. (com interfaces only!) }
  718. if result and Assigned(IEntry^.IID) and (IEntry^.IType in [etStandard, etFieldValue]) then
  719. IInterface(obj)._AddRef;
  720. end;
  721. function TObject.GetInterface(const iidstr : shortstring;out obj) : boolean;
  722. begin
  723. Result := GetInterfaceByStr(iidstr,obj);
  724. end;
  725. class function TObject.GetInterfaceEntry(const iid : tguid) : pinterfaceentry;
  726. var
  727. i: longint;
  728. intftable: pinterfacetable;
  729. ovmt: PVmt;
  730. begin
  731. ovmt := PVmt(Self);
  732. while Assigned(ovmt) and (ovmt^.vIntfTable <> emptyintfptr) do
  733. begin
  734. intftable:=ovmt^.vIntfTable;
  735. if assigned(intftable) then
  736. begin
  737. for i:=0 to intftable^.EntryCount-1 do
  738. begin
  739. result:=@intftable^.Entries[i];
  740. {$ifndef ver2_6}
  741. if assigned(Result^.iid) and assigned(Result^.iid^) and IsGUIDEqual(Result^.iid^^,iid) then
  742. {$else}
  743. if assigned(Result^.iid) and IsGUIDEqual(Result^.iid^,iid) then
  744. {$endif}
  745. Exit;
  746. end;
  747. end;
  748. ovmt := ovmt^.vParent;
  749. end;
  750. result := nil;
  751. end;
  752. class function TObject.GetInterfaceEntryByStr(const iidstr : shortstring) : pinterfaceentry;
  753. var
  754. i: longint;
  755. intftable: pinterfacetable;
  756. ovmt: PVmt;
  757. begin
  758. ovmt := PVmt(Self);
  759. while Assigned(ovmt) and (ovmt^.vIntfTable <> emptyintfptr) do
  760. begin
  761. intftable:=ovmt^.vIntfTable;
  762. if assigned(intftable) then
  763. begin
  764. for i:=0 to intftable^.EntryCount-1 do
  765. begin
  766. result:=@intftable^.Entries[i];
  767. {$ifndef ver2_6}
  768. if assigned(result^.iidstr) and assigned(result^.iidstr^) and (result^.iidstr^^ = iidstr) then
  769. {$else}
  770. if assigned(result^.iidstr) and (result^.iidstr^ = iidstr) then
  771. {$endif}
  772. Exit;
  773. end;
  774. end;
  775. ovmt := ovmt^.vParent;
  776. end;
  777. result:=nil;
  778. end;
  779. class function TObject.GetInterfaceTable : pinterfacetable;
  780. begin
  781. getinterfacetable:=PVmt(Self)^.vIntfTable;
  782. end;
  783. class function TObject.UnitName : ansistring;
  784. type
  785. // from the typinfo unit
  786. TClassTypeInfo = {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  787. ClassType: TClass;
  788. ParentInfo: Pointer;
  789. PropCount: SmallInt;
  790. UnitName: ShortString;
  791. end;
  792. PClassTypeInfo = ^TClassTypeInfo;
  793. var
  794. classtypeinfo: PClassTypeInfo;
  795. begin
  796. classtypeinfo:=ClassInfo;
  797. if Assigned(classtypeinfo) then
  798. begin
  799. // offset PTypeInfo by Length(Name) + 2 (ShortString length byte + SizeOf(Kind))
  800. inc(Pointer(classtypeinfo), PByte(Pointer(classtypeinfo)+1)^ + 2);
  801. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  802. classtypeinfo:=align(classtypeinfo,sizeof(classtypeinfo));
  803. {$endif}
  804. result:=classtypeinfo^.UnitName;
  805. end
  806. else
  807. result:='';
  808. end;
  809. function TObject.Equals(Obj: TObject) : boolean;
  810. begin
  811. result:=Obj=Self;
  812. end;
  813. function TObject.GetHashCode: PtrInt;
  814. begin
  815. result:=PtrInt(Self);
  816. end;
  817. function TObject.ToString: ansistring;
  818. begin
  819. result:=ClassName;
  820. end;
  821. {****************************************************************************
  822. TINTERFACEDOBJECT
  823. ****************************************************************************}
  824. function TInterfacedObject.QueryInterface(
  825. {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  826. begin
  827. if getinterface(iid,obj) then
  828. result:=S_OK
  829. else
  830. result:=longint(E_NOINTERFACE);
  831. end;
  832. function TInterfacedObject._AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  833. begin
  834. _addref:=interlockedincrement(frefcount);
  835. end;
  836. function TInterfacedObject._Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  837. begin
  838. _Release:=interlockeddecrement(frefcount);
  839. if _Release=0 then
  840. self.destroy;
  841. end;
  842. procedure TInterfacedObject.AfterConstruction;
  843. begin
  844. { we need to fix the refcount we forced in newinstance }
  845. { further, it must be done in a thread safe way }
  846. declocked(frefcount);
  847. end;
  848. procedure TInterfacedObject.BeforeDestruction;
  849. begin
  850. if frefcount<>0 then
  851. HandleError(204);
  852. end;
  853. class function TInterfacedObject.NewInstance : TObject;
  854. begin
  855. NewInstance:=inherited NewInstance;
  856. if NewInstance<>nil then
  857. TInterfacedObject(NewInstance).frefcount:=1;
  858. end;
  859. {****************************************************************************
  860. TAGGREGATEDOBJECT
  861. ****************************************************************************}
  862. constructor TAggregatedObject.Create(const aController: IUnknown);
  863. begin
  864. inherited Create;
  865. { do not keep a counted reference to the controller! }
  866. fcontroller := Pointer(aController);
  867. end;
  868. function TAggregatedObject.QueryInterface(
  869. {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  870. begin
  871. Result := IUnknown(fcontroller).QueryInterface(iid, obj);
  872. end;
  873. function TAggregatedObject._AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  874. begin
  875. Result := IUnknown(fcontroller)._AddRef;
  876. end;
  877. function TAggregatedObject._Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  878. begin
  879. Result := IUnknown(fcontroller)._Release;
  880. end;
  881. function TAggregatedObject.GetController : IUnknown;
  882. begin
  883. Result := IUnknown(fcontroller);
  884. end;
  885. {****************************************************************************
  886. TContainedOBJECT
  887. ****************************************************************************}
  888. function TContainedObject.QueryInterface(
  889. {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  890. begin
  891. if getinterface(iid,obj) then
  892. result:=S_OK
  893. else
  894. result:=longint(E_NOINTERFACE);
  895. end;
  896. {****************************************************************************
  897. Exception Support
  898. ****************************************************************************}
  899. {$ifdef FPC_HAS_FEATURE_EXCEPTIONS}
  900. {$i except.inc}
  901. {$endif FPC_HAS_FEATURE_EXCEPTIONS}