objpas.inc 34 KB

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