mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-09 20:28:49 +02:00

the IInterface implementation to be XPCom-compatible --- Merging r15997 through r16179 into '.': U rtl/inc/variants.pp U rtl/inc/objpash.inc U rtl/inc/objpas.inc U rtl/objpas/classes/persist.inc U rtl/objpas/classes/compon.inc U rtl/objpas/classes/classesh.inc A tests/test/tconstref1.pp A tests/test/tconstref2.pp A tests/test/tconstref3.pp U tests/test/tinterface4.pp A tests/test/tconstref4.pp U tests/webtbs/tw10897.pp U tests/webtbs/tw4086.pp U tests/webtbs/tw15363.pp U tests/webtbs/tw2177.pp U tests/webtbs/tw16592.pp U tests/tbs/tb0546.pp U compiler/sparc/cpupara.pas U compiler/i386/cpupara.pas U compiler/pdecsub.pas U compiler/symdef.pas U compiler/powerpc/cpupara.pas U compiler/avr/cpupara.pas U compiler/browcol.pas U compiler/defcmp.pas U compiler/powerpc64/cpupara.pas U compiler/ncgrtti.pas U compiler/x86_64/cpupara.pas U compiler/opttail.pas U compiler/htypechk.pas U compiler/tokens.pas U compiler/objcutil.pas U compiler/ncal.pas U compiler/symtable.pas U compiler/symsym.pas U compiler/m68k/cpupara.pas U compiler/regvars.pas U compiler/arm/cpupara.pas U compiler/symconst.pas U compiler/mips/cpupara.pas U compiler/paramgr.pas U compiler/psub.pas U compiler/pdecvar.pas U compiler/dbgstabs.pas U compiler/options.pas U packages/fcl-fpcunit/src/testutils.pp git-svn-id: trunk@16180 -
196 lines
4.3 KiB
ObjectPascal
196 lines
4.3 KiB
ObjectPascal
{ %opt=-g-h }
|
|
|
|
program project1;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
uses
|
|
{$IFDEF UNIX}{$IFDEF UseCThreads}
|
|
cthreads,
|
|
{$ENDIF}{$ENDIF}
|
|
Classes, sysutils
|
|
{ you can add units after this };
|
|
|
|
type
|
|
{ TInterfacedObj }
|
|
|
|
TInterfacedObj = class(TObject, IUnknown)
|
|
private
|
|
FOwner:TInterfacedObj;
|
|
FDestructorCalled:boolean;
|
|
|
|
function GetInterface(const iid: tguid; out obj): longint;
|
|
procedure Log(const Str:string);
|
|
protected
|
|
FRefCount : longint;
|
|
public
|
|
function QueryInterface(constref iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
|
|
function _AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
|
|
function _Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
|
|
|
|
constructor Create;
|
|
|
|
procedure AfterConstruction;override;
|
|
procedure BeforeDestruction;override;
|
|
class function NewInstance : TObject;override;
|
|
|
|
property Owner:TInterfacedObj read FOwner write FOwner;
|
|
end;
|
|
|
|
|
|
IIntf1 = interface
|
|
['{EFB94FA8-4F38-4E44-8D12-74A84D07A78C}']
|
|
end;
|
|
|
|
IIntf2 = interface
|
|
['{EBC4A858-7BAC-4310-8426-E52B449D022A}']
|
|
procedure Print;
|
|
procedure SetI(const S:string);
|
|
end;
|
|
|
|
TClass1 = class(TInterfacedObj, IIntf1)
|
|
|
|
end;
|
|
|
|
{ TClass2 }
|
|
|
|
TClass2 = class(TInterfacedObj, IIntf2)
|
|
i:string;
|
|
procedure Print;
|
|
procedure SetI(const S:string);
|
|
end;
|
|
|
|
TClass3 = class(TClass1, IIntf2)
|
|
private
|
|
FIntf2:IIntf2;
|
|
property Intf2Prop:IIntf2 read FIntf2 implements IIntf2;
|
|
public
|
|
constructor Create;
|
|
end;
|
|
|
|
{ TClass2 }
|
|
|
|
procedure TClass2.Print;
|
|
begin
|
|
WriteLn('Print ', i);
|
|
end;
|
|
|
|
procedure TClass2.SetI(const S: string);
|
|
begin
|
|
i:=S;
|
|
end;
|
|
|
|
{ TInterfacedObj }
|
|
|
|
const Err = HResult($80004002);
|
|
function TInterfacedObj.GetInterface(const iid: tguid; out obj): longint;
|
|
begin
|
|
if inherited GetInterface(IID, Obj) then
|
|
Result:=0
|
|
else
|
|
Result:=Err;
|
|
end;
|
|
|
|
procedure TInterfacedObj.Log(const Str: string);
|
|
begin
|
|
WriteLn(Format('%s Obj=$%P class=%s RefCount=%d', [Str, Pointer(Self), ClassName, FRefCount]));
|
|
end;
|
|
|
|
function TInterfacedObj.QueryInterface(constref iid: tguid; out obj): longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
|
|
begin
|
|
Result:=GetInterface(iid, obj);
|
|
|
|
//try to find interface in Owner
|
|
if (FOwner <> nil) and (Result = Err) then
|
|
Result:=FOwner.QueryInterface(iid, obj);
|
|
end;
|
|
|
|
function TInterfacedObj._AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};[public,alias:'TInterfacedObj_AddRef'];
|
|
begin
|
|
if not FDestructorCalled then
|
|
begin
|
|
_addref:=interlockedincrement(frefcount);
|
|
Log('AddRef');
|
|
|
|
if FOwner <> nil then
|
|
FOwner._AddRef;
|
|
end;
|
|
end;
|
|
|
|
function TInterfacedObj._Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
|
|
begin
|
|
if FDestructorCalled then Exit;
|
|
|
|
_Release:=interlockeddecrement(frefcount);
|
|
Log('Release');
|
|
if _Release=0 then
|
|
begin
|
|
FDestructorCalled:=True;
|
|
|
|
Log('Destroy');
|
|
self.destroy;
|
|
end
|
|
else
|
|
if FOwner <> nil then
|
|
FOwner._Release;
|
|
end;
|
|
|
|
procedure TInterfacedObj.AfterConstruction;
|
|
begin
|
|
{ we need to fix the refcount we forced in newinstance }
|
|
{ further, it must be done in a thread safe way }
|
|
//declocked(frefcount);
|
|
interlockeddecrement(frefcount);
|
|
Log('AfterConstruction');
|
|
end;
|
|
|
|
procedure TInterfacedObj.BeforeDestruction;
|
|
begin
|
|
Log('BeforeDestruction');
|
|
if frefcount<>0 then
|
|
raise Exception.Create('Cannot free object still referenced.');
|
|
end;
|
|
|
|
class function TInterfacedObj.NewInstance : TObject;
|
|
begin
|
|
NewInstance:=inherited NewInstance;
|
|
if NewInstance<>nil then
|
|
TInterfacedObj(NewInstance).frefcount:=1;
|
|
end;
|
|
|
|
constructor TInterfacedObj.Create;
|
|
begin
|
|
FDestructorCalled:=false;
|
|
inherited Create;
|
|
FOwner:=nil;
|
|
end;
|
|
|
|
|
|
{ TClass2 }
|
|
|
|
constructor TClass3.Create;
|
|
var O:TClass2;
|
|
begin
|
|
inherited Create;
|
|
O:=TClass2.Create;
|
|
FIntf2:=O;
|
|
O.Owner:=Self;
|
|
|
|
FIntf2.SetI('AAA'); //this line is crucial for bug reproducing
|
|
end;
|
|
|
|
var O:TClass3;
|
|
I1:IIntf1;
|
|
I2:IIntf2;
|
|
begin
|
|
HaltOnNotReleased := true;
|
|
O:=TClass3.Create;
|
|
I1:=O;
|
|
|
|
//at this moment O object is already freed in rev.15156+ !!!
|
|
I2:=I1 as IIntf2;
|
|
I2.Print;
|
|
Writeln('ok');
|
|
end.
|
|
|