fpc/tests/webtbs/tw16592.pp
joost 07bf44517c * Merged XPCom branch into trunk, added support for constref and changed
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 -
2010-10-17 20:58:22 +00:00

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.