objpas.inc 34 KB

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