objpas.inc 36 KB

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