Jump to content

yonojoy

Members
  • Content Count

    13
  • Joined

  • Last visited

Posts posted by yonojoy


  1. I use the following approach (out of my memory):

    type  
        TSnapTallyWrapper = TInterfaceWrapper<ISnapTally>;
    
    begin
        li.Data := TSnapTallyWrapper.Create(snap_tally);
        //...
        ISnapTally Test := TSnapTallyWrapper(li.Data).Intf;
        //...
        Free(li.Data);
        li.Data := nil;
    end;

    with

    TInterfaceWrapper<T: IInterface> = class(TObject)
    private
        FIntf: T;
    public
        constructor Create(AIntf: T);
        property Intf: T read FIntf write FIntf;
    end;
    
    //...
    
    constructor TInterfaceWrapper<T>.Create(AIntf: T);
    begin
        inherited Create;
        FIntf := AIntf;
    end;

    No tricks. Clean references.
       


  2. 2 hours ago, Anders Melander said:

    I still can't follow your example ...

    That was the most simple example I could find, that triggers the problem.

     

    I have a class hierarchy:
    TIBase<I>
    TIBaseExt<I> = class(TIBase<I>)
    TIFoo = class(TIBaseExt<IFooBroker>)

     

    TIBase<I> has a local variable Broker of type I. With my code one can assign a variable of type IBaseBroker to Broker even if Broker is of type IFooBroker (via TIBase<IFooBroker>).

     

    What I really wanted to know is, if I should report this to QP, especially if this problem still exists in actual Delphi versions (I only have XE4 available here).


  3. I know the cast is senseless. This was my try to break down a real world bug to, what I think, might be a compiler bug.

     

    Essentially I have a class definition with TIBaseExt<I: IBaseBroker>.Create(ABroker: I) and I can call this Create constructor with IBaseBroker even if I is instantiated with IFooBroker. In the end I should have TIBaseExt<IFooBroker>.Create(ABroker: IFooBroker) and I can call this with an IBaseBroker interface and the compiler wont complain.

     

    The cast was the bug in our code and I would have expected the compiler to error on it, but instead it compiled and I had to track the access violations.

    I modified the calling code to make this more clear:

    procedure TForm1.Button1Click(Sender: TObject);
    var
        BaseBroker: IBaseBroker;
        Broker: IFooBroker;
        Foo: TIFoo;
    begin
        Broker := TIFooBroker.Create();
    
        if not Supports(Broker, IBaseBroker, BaseBroker) then
          raise Exception.Create('...');
        //Here the compiler will complain: E2010: Incompatible types 'IFooBroker' and 'IBaseBroker'
        TIBaseExt<IFooBroker>.Create(BaseBroker);
    
        //This Create will lead to the same call, but the compiler wont complain:
        Foo := TIFoo.Create(Broker);
        try
            Foo.Test;
        finally
            Foo.Free;
        end;
    end;

    @Anders Melander A GUID for IFooBroker wont change anything. IFooBroker and IBaseBroker are different interfaces and the compiler should IMO not allow a call with IBaseBroker if I is instantiated with IFooBroker.

     


  4. Consider the following code:

     

    type
    
        IBaseBroker = interface
        ['{FE71BBA5-A6F8-4E75-894E-54F830023E99}']
        end;
    
        IFooBroker = interface(IBaseBroker)
            function GetMsg(): string;
        end;
    
        TIBase<I: IBaseBroker> = class
        private
            FBroker: I;
        protected
            property Broker: I read FBroker;
        public
            constructor Create(ABroker: I); virtual;
        end;
    
        TIBaseExt<I: IBaseBroker> = class (TIBase<I>)
        public
            constructor Create(ABroker: I); override;
        end;
    
        TIFoo = class (TIBaseExt<IFooBroker>)
        public
            constructor Create(ABroker: IFooBroker); override;
            procedure Test;
        end;
    
        TIBaseBroker = class(TInterfacedObject, IBaseBroker)
        end;
    
        TIFooBroker = class(TIBaseBroker, IFooBroker)  //no AV with ,IBaseBroker!
        protected
            function GetMsg(): string;
        end;
    
    
    implementation
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
        Broker: IFooBroker;
        Foo: TIFoo;
    begin
        Broker := TIFooBroker.Create();
        Foo := TIFoo.Create(Broker);
        try
        	//AV here:
            Foo.Test;
        finally
            Foo.Free;
        end;
    end;
    
    constructor TIFoo.Create(ABroker: IFooBroker);
    begin
        inherited Create(ABroker);
    end;
    
    procedure TIFoo.Test;
    begin
        //Access violation:
        ShowMessage(Broker.GetMsg());
    end;
    
    constructor TIBase<I>.Create(ABroker: I);
    begin
        FBroker := ABroker;
    end;
    
    constructor TIBaseExt<I>.Create(ABroker: I);
    var
        BaseBroker: IBaseBroker;
    begin
        //silly cast:
        if not Supports(ABroker, IBaseBroker, BaseBroker) then
          raise Exception.Create('...');
        // I thought the following line should not compile for TIFoo = TIBaseExt<IFooBroker>:
        inherited Create(BaseBroker);
    end;
    
    function TIFooBroker.GetMsg: string;
    begin
        Result := 'OK';
    end;

    I thought Create(I: IBaseBroker) should not compile, once I is instantiated with IFooBroker. But it compiles and I get an AV (at least with XE4). Or do I miss something?


  5. We had a similar error with TMS TPlannerCalendar: The TMS code had an assumption, that mouse events are always processed after the paint message (where FCanvas was set). But this did not always hold true, eg if the control was created invisible.

     

    Our workaround was to force a call to Paint in FormCreate of the form holding the planner control:

     

    procedure WorkaroundPlannerCalendarCanvasAccessViolation(ACalendar: TPlannerCalendar);
    begin
        ACalendar.BeginUpdate;  
        TPlannerCalendarCracker(ACalendar).Paint();  //forces initialization of TPlannerCalendar.FCanvas
        ACalendar.EndUpdate;
    end;
    

     

×