objpas.inc 22 KB

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