objpas.inc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  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. {****************************************************************************
  12. Internal Routines called from the Compiler
  13. ****************************************************************************}
  14. { the reverse order of the parameters make code generation easier }
  15. function fpc_do_is(aclass : tclass;aobject : tobject) : boolean;[public,alias: 'FPC_DO_IS']; compilerproc;
  16. begin
  17. fpc_do_is:=assigned(aobject) and assigned(aclass) and
  18. aobject.inheritsfrom(aclass);
  19. end;
  20. { the reverse order of the parameters make code generation easier }
  21. function fpc_do_as(aclass : tclass;aobject : tobject): tobject;[public,alias: 'FPC_DO_AS']; compilerproc;
  22. begin
  23. if assigned(aobject) and not(aobject.inheritsfrom(aclass)) then
  24. handleerrorframe(219,get_frame);
  25. result := aobject;
  26. end;
  27. { interface helpers }
  28. procedure fpc_intf_decr_ref(var i: pointer);[public,alias: 'FPC_INTF_DECR_REF']; compilerproc;
  29. begin
  30. if assigned(i) then
  31. IUnknown(i)._Release;
  32. i:=nil;
  33. end;
  34. { local declaration for intf_decr_ref for local access }
  35. procedure intf_decr_ref(var i: pointer); [external name 'FPC_INTF_DECR_REF'];
  36. procedure fpc_intf_incr_ref(i: pointer);[public,alias: 'FPC_INTF_INCR_REF']; compilerproc;
  37. begin
  38. if assigned(i) then
  39. IUnknown(i)._AddRef;
  40. end;
  41. { local declaration of intf_incr_ref for local access }
  42. procedure intf_incr_ref(i: pointer); [external name 'FPC_INTF_INCR_REF'];
  43. procedure fpc_intf_assign(var D: pointer; const S: pointer);[public,alias: 'FPC_INTF_ASSIGN']; compilerproc;
  44. begin
  45. if assigned(S) then
  46. IUnknown(S)._AddRef;
  47. if assigned(D) then
  48. IUnknown(D)._Release;
  49. D:=S;
  50. end;
  51. procedure fpc_intf_assign_by_iid(var D: pointer; const S: pointer; const iid: TGUID);[public,alias: 'FPC_INTF_ASSIGN2']; compilerproc;
  52. begin
  53. if assigned(D) then
  54. IUnknown(D)._Release;
  55. if assigned(S) then
  56. IUnknown(S).QueryInterface(iid, D)
  57. else
  58. D := nil;
  59. end;
  60. function fpc_intf_as(const S: pointer; const iid: TGUID): IInterface;[public,alias: 'FPC_INTF_AS']; compilerproc;
  61. var
  62. tmpi: pointer; // _AddRef before _Release
  63. begin
  64. if assigned(S) then
  65. begin
  66. if IUnknown(S).QueryInterface(iid,tmpi)<>S_OK then
  67. handleerror(219);
  68. pointer(fpc_intf_as):=tmpi;
  69. end
  70. else
  71. fpc_intf_as:=nil;
  72. end;
  73. function fpc_class_as_intf(const S: pointer; const iid: TGUID): IInterface;[public,alias: 'FPC_CLASS_AS_INTF']; compilerproc;
  74. var
  75. tmpi: pointer; // _AddRef before _Release
  76. begin
  77. if assigned(S) then
  78. begin
  79. if not TObject(S).GetInterface(iid,tmpi) then
  80. handleerror(219);
  81. pointer(fpc_class_as_intf):=tmpi;
  82. end
  83. else
  84. fpc_class_as_intf:=nil;
  85. end;
  86. {****************************************************************************
  87. TOBJECT
  88. ****************************************************************************}
  89. constructor TObject.Create;
  90. begin
  91. end;
  92. destructor TObject.Destroy;
  93. begin
  94. end;
  95. procedure TObject.Free;
  96. begin
  97. // the call via self avoids a warning
  98. if self<>nil then
  99. self.destroy;
  100. end;
  101. class function TObject.InstanceSize : SizeInt;
  102. begin
  103. InstanceSize:=pSizeInt(pointer(self)+vmtInstanceSize)^;
  104. end;
  105. procedure InitInterfacePointers(objclass: tclass;instance : pointer);
  106. var
  107. i: integer;
  108. intftable: pinterfacetable;
  109. Res: pinterfaceentry;
  110. begin
  111. while assigned(objclass) do
  112. begin
  113. intftable:=pinterfacetable((pointer(objclass)+vmtIntfTable)^);
  114. if assigned(intftable) then
  115. begin
  116. i:=intftable^.EntryCount;
  117. Res:=@intftable^.Entries[0];
  118. while i>0 do begin
  119. if Res^.EntryType = etStandard then
  120. ppointer(@(pbyte(instance)[Res^.IOffset]))^:=
  121. pointer(Res^.VTable);
  122. inc(Res);
  123. dec(i);
  124. end;
  125. end;
  126. objclass:=pclass(pointer(objclass)+vmtParent)^;
  127. end;
  128. end;
  129. class function TObject.InitInstance(instance : pointer) : tobject;
  130. begin
  131. { the size is saved at offset 0 }
  132. fillchar(instance^, InstanceSize, 0);
  133. { insert VMT pointer into the new created memory area }
  134. { (in class methods self contains the VMT!) }
  135. ppointer(instance)^:=pointer(self);
  136. InitInterfacePointers(self,instance);
  137. InitInstance:=TObject(Instance);
  138. end;
  139. class function TObject.ClassParent : tclass;
  140. begin
  141. { type of self is class of tobject => it points to the vmt }
  142. { the parent vmt is saved at offset vmtParent }
  143. classparent:=pclass(pointer(self)+vmtParent)^;
  144. end;
  145. class function TObject.NewInstance : tobject;
  146. var
  147. p : pointer;
  148. begin
  149. getmem(p, InstanceSize);
  150. if p <> nil then
  151. InitInstance(p);
  152. NewInstance:=TObject(p);
  153. end;
  154. procedure TObject.FreeInstance;
  155. begin
  156. CleanupInstance;
  157. FreeMem(Pointer(Self));
  158. end;
  159. class function TObject.ClassType : TClass;
  160. begin
  161. ClassType:=TClass(Pointer(Self))
  162. end;
  163. type
  164. tmethodnamerec = packed record
  165. name : pshortstring;
  166. addr : pointer;
  167. end;
  168. tmethodnametable = packed record
  169. count : dword;
  170. entries : packed array[0..0] of tmethodnamerec;
  171. end;
  172. pmethodnametable = ^tmethodnametable;
  173. class function TObject.MethodAddress(const name : shortstring) : pointer;
  174. var
  175. UName : ShortString;
  176. methodtable : pmethodnametable;
  177. i : dword;
  178. vmt : tclass;
  179. begin
  180. UName := UpCase(name);
  181. vmt:=self;
  182. while assigned(vmt) do
  183. begin
  184. methodtable:=pmethodnametable((Pointer(vmt)+vmtMethodTable)^);
  185. if assigned(methodtable) then
  186. begin
  187. for i:=0 to methodtable^.count-1 do
  188. if UpCase(methodtable^.entries[i].name^)=UName then
  189. begin
  190. MethodAddress:=methodtable^.entries[i].addr;
  191. exit;
  192. end;
  193. end;
  194. vmt:=pclass(pointer(vmt)+vmtParent)^;
  195. end;
  196. MethodAddress:=nil;
  197. end;
  198. class function TObject.MethodName(address : pointer) : shortstring;
  199. var
  200. methodtable : pmethodnametable;
  201. i : dword;
  202. vmt : tclass;
  203. begin
  204. vmt:=self;
  205. while assigned(vmt) do
  206. begin
  207. methodtable:=pmethodnametable((Pointer(vmt)+vmtMethodTable)^);
  208. if assigned(methodtable) then
  209. begin
  210. for i:=0 to methodtable^.count-1 do
  211. if methodtable^.entries[i].addr=address then
  212. begin
  213. MethodName:=methodtable^.entries[i].name^;
  214. exit;
  215. end;
  216. end;
  217. vmt:=pclass(pointer(vmt)+vmtParent)^;
  218. end;
  219. MethodName:='';
  220. end;
  221. function TObject.FieldAddress(const name : shortstring) : pointer;
  222. type
  223. PFieldInfo = ^TFieldInfo;
  224. TFieldInfo =
  225. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  226. packed
  227. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  228. record
  229. FieldOffset: PtrUInt;
  230. ClassTypeIndex: Word;
  231. Name: ShortString;
  232. end;
  233. PFieldTable = ^TFieldTable;
  234. TFieldTable =
  235. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  236. packed
  237. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  238. record
  239. FieldCount: Word;
  240. ClassTable: Pointer;
  241. { should be array[Word] of TFieldInfo; but
  242. Elements have variant size! force at least proper alignment }
  243. Fields: array[0..0] of TFieldInfo
  244. end;
  245. var
  246. UName: ShortString;
  247. CurClassType: TClass;
  248. FieldTable: PFieldTable;
  249. FieldInfo: PFieldInfo;
  250. i: Integer;
  251. begin
  252. if Length(name) > 0 then
  253. begin
  254. UName := UpCase(name);
  255. CurClassType := ClassType;
  256. while CurClassType <> nil do
  257. begin
  258. FieldTable := PFieldTable((Pointer(CurClassType) + vmtFieldTable)^);
  259. if FieldTable <> nil then
  260. begin
  261. FieldInfo := @FieldTable^.Fields[0];
  262. for i := 0 to FieldTable^.FieldCount - 1 do
  263. begin
  264. if UpCase(FieldInfo^.Name) = UName then
  265. begin
  266. fieldaddress := Pointer(Self) + FieldInfo^.FieldOffset;
  267. exit;
  268. end;
  269. FieldInfo := PFieldInfo(PByte(@FieldInfo^.Name) + 1 + Length(FieldInfo^.Name));
  270. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  271. { align to largest field of TFieldInfo }
  272. FieldInfo := Align(FieldInfo, SizeOf(PtrUInt));
  273. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  274. end;
  275. end;
  276. { Try again with the parent class type }
  277. CurClassType:=pclass(pointer(CurClassType)+vmtParent)^;
  278. end;
  279. end;
  280. fieldaddress:=nil;
  281. end;
  282. function TObject.SafeCallException(exceptobject : tobject;
  283. exceptaddr : pointer) : longint;
  284. begin
  285. safecallexception:=0;
  286. end;
  287. class function TObject.ClassInfo : pointer;
  288. begin
  289. ClassInfo:=ppointer(Pointer(self)+vmtTypeInfo)^;
  290. end;
  291. class function TObject.ClassName : ShortString;
  292. begin
  293. ClassName:=PShortString((Pointer(Self)+vmtClassName)^)^;
  294. end;
  295. class function TObject.ClassNameIs(const name : string) : boolean;
  296. begin
  297. ClassNameIs:=Upcase(ClassName)=Upcase(name);
  298. end;
  299. class function TObject.InheritsFrom(aclass : TClass) : Boolean;
  300. var
  301. vmt : tclass;
  302. begin
  303. vmt:=self;
  304. while assigned(vmt) do
  305. begin
  306. if vmt=aclass then
  307. begin
  308. InheritsFrom:=true;
  309. exit;
  310. end;
  311. vmt:=pclass(pointer(vmt)+vmtParent)^;
  312. end;
  313. InheritsFrom:=false;
  314. end;
  315. class function TObject.stringmessagetable : pstringmessagetable;
  316. begin
  317. stringmessagetable:=pstringmessagetable((pointer(Self)+vmtMsgStrPtr)^);
  318. end;
  319. type
  320. tmessagehandler = procedure(var msg) of object;
  321. tmessagehandlerrec = packed record
  322. proc : pointer;
  323. obj : pointer;
  324. end;
  325. procedure TObject.Dispatch(var message);
  326. type
  327. tmsgtable = packed record
  328. index : dword;
  329. method : pointer;
  330. end;
  331. pmsgtable = ^tmsgtable;
  332. var
  333. index : dword;
  334. count,i : longint;
  335. msgtable : pmsgtable;
  336. p : pointer;
  337. vmt : tclass;
  338. msghandler : tmessagehandler;
  339. begin
  340. index:=dword(message);
  341. vmt:=ClassType;
  342. while assigned(vmt) do
  343. begin
  344. // See if we have messages at all in this class.
  345. p:=pointer(vmt)+vmtDynamicTable;
  346. If assigned(PPointer(p)^) then
  347. begin
  348. msgtable:=pmsgtable(Pointer(p^)+4);
  349. count:=pdword(p^)^;
  350. end
  351. else
  352. Count:=0;
  353. { later, we can implement a binary search here }
  354. for i:=0 to count-1 do
  355. begin
  356. if index=msgtable[i].index then
  357. begin
  358. p:=msgtable[i].method;
  359. tmessagehandlerrec(msghandler).proc:=p;
  360. tmessagehandlerrec(msghandler).obj:=self;
  361. msghandler(message);
  362. exit;
  363. end;
  364. end;
  365. vmt:=pclass(pointer(vmt)+vmtParent)^;
  366. end;
  367. DefaultHandler(message);
  368. end;
  369. procedure TObject.DispatchStr(var message);
  370. type
  371. PSizeUInt = ^SizeUInt;
  372. var
  373. name : shortstring;
  374. count,i : longint;
  375. msgstrtable : pmsgstrtable;
  376. p : pointer;
  377. vmt : tclass;
  378. msghandler : tmessagehandler;
  379. begin
  380. name:=pshortstring(@message)^;
  381. vmt:=ClassType;
  382. while assigned(vmt) do
  383. begin
  384. p:=(pointer(vmt)+vmtMsgStrPtr);
  385. If (P<>Nil) and (PPtrInt(P)^<>0) then
  386. begin
  387. count:=PPtrInt(PSizeUInt(p)^)^;
  388. msgstrtable:=pmsgstrtable(PSizeUInt(P)^+sizeof(ptrint));
  389. end
  390. else
  391. Count:=0;
  392. { later, we can implement a binary search here }
  393. for i:=0 to count-1 do
  394. begin
  395. if name=msgstrtable[i].name^ then
  396. begin
  397. p:=msgstrtable[i].method;
  398. tmessagehandlerrec(msghandler).proc:=p;
  399. tmessagehandlerrec(msghandler).obj:=self;
  400. msghandler(message);
  401. exit;
  402. end;
  403. end;
  404. vmt:=pclass(pointer(vmt)+vmtParent)^;
  405. end;
  406. DefaultHandlerStr(message);
  407. end;
  408. procedure TObject.DefaultHandler(var message);
  409. begin
  410. end;
  411. procedure TObject.DefaultHandlerStr(var message);
  412. begin
  413. end;
  414. procedure TObject.CleanupInstance;
  415. Type
  416. TRecElem = packed Record
  417. Info : Pointer;
  418. Offset : Longint;
  419. end;
  420. TRecElemArray = packed array[1..Maxint] of TRecElem;
  421. PRecRec = ^TRecRec;
  422. TRecRec = record
  423. Size,Count : Longint;
  424. Elements : TRecElemArray;
  425. end;
  426. var
  427. vmt : tclass;
  428. temp : pbyte;
  429. count,
  430. i : longint;
  431. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  432. recelem : TRecElem;
  433. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  434. begin
  435. vmt:=ClassType;
  436. while vmt<>nil do
  437. begin
  438. { This need to be included here, because Finalize()
  439. has should support for tkClass }
  440. Temp:=Pointer((Pointer(vmt)+vmtInitTable)^);
  441. if Assigned(Temp) then
  442. begin
  443. inc(Temp);
  444. I:=Temp^;
  445. inc(temp,I+1); // skip name string;
  446. temp:=aligntoptr(temp);
  447. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  448. move(PRecRec(Temp)^.Count,Count,sizeof(Count));
  449. {$else FPC_REQUIRES_PROPER_ALIGNMENT}
  450. Count:=PRecRec(Temp)^.Count; // get element Count
  451. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  452. For I:=1 to count do
  453. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  454. begin
  455. move(PRecRec(Temp)^.elements[I],RecElem,sizeof(RecElem));
  456. With RecElem do
  457. int_Finalize (pointer(self)+Offset,Info);
  458. end;
  459. {$else FPC_REQUIRES_PROPER_ALIGNMENT}
  460. With PRecRec(Temp)^.elements[I] do
  461. int_Finalize (pointer(self)+Offset,Info);
  462. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  463. end;
  464. vmt:=pclass(pointer(vmt)+vmtParent)^;
  465. end;
  466. end;
  467. procedure TObject.AfterConstruction;
  468. begin
  469. end;
  470. procedure TObject.BeforeDestruction;
  471. begin
  472. end;
  473. function IsGUIDEqual(const guid1, guid2: tguid): boolean;
  474. begin
  475. IsGUIDEqual:=
  476. (guid1.D1=guid2.D1) and
  477. (PDWORD(@guid1.D2)^=PDWORD(@guid2.D2)^) and
  478. (PDWORD(@guid1.D4[0])^=PDWORD(@guid2.D4[0])^) and
  479. (PDWORD(@guid1.D4[4])^=PDWORD(@guid2.D4[4])^);
  480. end;
  481. function getinterfacebyentry(Instance: pointer; IEntry: pinterfaceentry; out obj): boolean;
  482. var
  483. Getter: function: IInterface of object;
  484. begin
  485. Pointer(Obj) := nil;
  486. if Assigned(IEntry) then
  487. begin
  488. case IEntry^.EntryType of
  489. etStandard:
  490. begin
  491. //writeln('Doing etStandard cast of ', TObject(Instance).classname(), ' with self = ', ptruint(Instance), ' and offset = ', IEntry^.IOffset);
  492. Pointer(Obj) := Pointer(PtrInt(Instance) + IEntry^.IOffset);
  493. end;
  494. etFieldValue:
  495. begin
  496. //writeln('Doing etFieldValue cast of ', TObject(Instance).classname(), ' with offset = ', IEntry^.EntryOffset);
  497. Pointer(obj) := ppointer(Pointer(Instance)+IEntry^.EntryOffset)^;
  498. end;
  499. etVirtualMethodResult:
  500. begin
  501. //writeln('Doing etVirtualMethodResult cast of ', TObject(Instance).classname());
  502. TMethod(Getter).data := Instance;
  503. TMethod(Getter).code := ppointer(ptrint(Instance) + IEntry^.EntryOffset)^;
  504. Pointer(obj) := Pointer(Getter());
  505. end;
  506. etStaticMethodResult:
  507. begin
  508. //writeln('Doing etStaticMethodResult cast of ', TObject(Instance).classname());
  509. TMethod(Getter).data := Instance;
  510. TMethod(Getter).code := pointer(IEntry^.EntryOffset);
  511. Pointer(obj) := Pointer(Getter());
  512. end;
  513. end;
  514. end;
  515. result := assigned(pointer(obj));
  516. if result then
  517. IInterface(obj)._AddRef;
  518. end;
  519. function TObject.getinterface(const iid : tguid;out obj) : boolean;
  520. begin
  521. Result := getinterfacebyentry(self, getinterfaceentry(iid), obj);
  522. end;
  523. function TObject.getinterfacebystr(const iidstr : string;out obj) : boolean;
  524. begin
  525. Result := getinterfacebyentry(self, getinterfaceentrybystr(iidstr), obj);
  526. end;
  527. class function TObject.getinterfaceentry(const iid : tguid) : pinterfaceentry;
  528. var
  529. i: integer;
  530. intftable: pinterfacetable;
  531. Res: pinterfaceentry;
  532. begin
  533. getinterfaceentry:=nil;
  534. intftable:=pinterfacetable((pointer(Self)+vmtIntfTable)^);
  535. if assigned(intftable) then begin
  536. i:=intftable^.EntryCount;
  537. Res:=@intftable^.Entries[0];
  538. while (i>0) and
  539. not (assigned(Res^.iid) and IsGUIDEqual(Res^.iid^,iid)) do begin
  540. inc(Res);
  541. dec(i);
  542. end;
  543. if (i>0) then
  544. getinterfaceentry:=Res;
  545. end;
  546. if (getinterfaceentry=nil)and not(classparent=nil) then
  547. getinterfaceentry:=classparent.getinterfaceentry(iid)
  548. end;
  549. class function TObject.getinterfaceentrybystr(const iidstr : string) : pinterfaceentry;
  550. var
  551. i: integer;
  552. intftable: pinterfacetable;
  553. Res: pinterfaceentry;
  554. begin
  555. getinterfaceentrybystr:=nil;
  556. intftable:=pinterfacetable((pointer(Self)+vmtIntfTable)^);
  557. if assigned(intftable) then begin
  558. i:=intftable^.EntryCount;
  559. Res:=@intftable^.Entries[0];
  560. while (i>0) and (Res^.iidstr^<>iidstr) do begin
  561. inc(Res);
  562. dec(i);
  563. end;
  564. if (i>0) then
  565. getinterfaceentrybystr:=Res;
  566. end;
  567. if (getinterfaceentrybystr=nil) and not(classparent=nil) then
  568. getinterfaceentrybystr:=classparent.getinterfaceentrybystr(iidstr)
  569. end;
  570. class function TObject.getinterfacetable : pinterfacetable;
  571. begin
  572. getinterfacetable:=pinterfacetable((pointer(Self)+vmtIntfTable)^);
  573. end;
  574. {****************************************************************************
  575. TINTERFACEDOBJECT
  576. ****************************************************************************}
  577. function TInterfacedObject.QueryInterface(
  578. const iid : tguid;out obj) : longint;stdcall;
  579. begin
  580. if getinterface(iid,obj) then
  581. result:=0
  582. else
  583. result:=longint(E_NOINTERFACE);
  584. end;
  585. function TInterfacedObject._AddRef : longint;stdcall;
  586. begin
  587. inclocked(frefcount);
  588. _addref:=frefcount;
  589. end;
  590. function TInterfacedObject._Release : longint;stdcall;
  591. begin
  592. if declocked(frefcount) then
  593. begin
  594. self.destroy;
  595. _Release:=0;
  596. end
  597. else
  598. _Release:=frefcount;
  599. end;
  600. procedure TInterfacedObject.AfterConstruction;
  601. begin
  602. { we need to fix the refcount we forced in newinstance }
  603. { further, it must be done in a thread safe way }
  604. declocked(frefcount);
  605. end;
  606. procedure TInterfacedObject.BeforeDestruction;
  607. begin
  608. if frefcount<>0 then
  609. HandleError(204);
  610. end;
  611. class function TInterfacedObject.NewInstance : TObject;
  612. begin
  613. NewInstance:=inherited NewInstance;
  614. TInterfacedObject(NewInstance).frefcount:=1;
  615. end;
  616. {****************************************************************************
  617. Exception Support
  618. ****************************************************************************}
  619. {$i except.inc}