objpas.inc 34 KB

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