objpas.inc 33 KB

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