[fpc-pascal] Interfaces via implements keyword

Denis Golovan d.golovan.ml at gmail.com
Sat Nov 28 11:39:22 CET 2009


Hi Andrew

On Thu, Nov 26, 2009 at 4:48 AM, Andrew Hall <andrew.hall at shaw.ca> wrote:

> 1) Always reference your host class through an interface you know will be
> implemented by the host class, therefore calling "as" from this interface
> will always find any of the interfaces your class may support.  The easiest
> would be to declare "I1: IUnknown" in the code below - I haven't tried it
> but that should work.
>

Yes. At first of this too.


>
> 2) Store the host class reference in the other classes that implement the
> host and provide an "Owner: IUnknown" property in your "child" implementing
> classes to allow you to cast to any interface supported by the host class:
> "I2 := I1.Owner as IIntf2"
>
>
And that's my current solution for some classes :)


> PS - normally your host class would not support the interface you are using
> "implements" to achieve...


Normally yes. Unfortunately it's not my case.


> therefore the confusing circumstances of your first example would not
> normally happen - you'd be more likely to see this second example which is a
> little easier to decipher...
>
> Regards,
>
> Andrew Hall.


But I think I found a better solution. The only way that needed to be
changed is the way of QueryInterface works.
I just took the idea with Owner and redefined QueryInterface method to use
it. Like following:

  { TInterfacedObj }

  TInterfacedObj = class(TObject, IUnknown)
    private
      FOwner:TInterfacedObj;

      function GetInterface(const iid : tguid;out obj):longint;
    public
      function QueryInterface(const iid : tguid;out obj) :
longint;virtual;stdcall;
      function _AddRef : longint;stdcall;
      function _Release : longint;stdcall;

      constructor Create(Owner:TInterfacedObj);
  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;

  function TInterfacedObj.QueryInterface(const iid: tguid; out obj):
longint;stdcall;
  begin
    WriteLn('QueryInterface ', ClassName);

    if FOwner = nil then
      Result:=GetInterface(iid, obj)
      else
      begin
        Result:=FOwner.QueryInterface(iid, obj);

        //try to find interface in itself
        if Result = Err then
           Result:=GetInterface(iid, obj);
      end;
  end;

  constructor TInterfacedObj.Create(Owner: TInterfacedObj);
  begin
    FOwner:=Owner;
  end;

Now it is possible to start interface search from the owner and only if
owner has no appropriate interface, it queries itself.
That's seems pretty nice solution.


-- 
Best regards,
Denis Golovan
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freepascal.org/pipermail/fpc-pascal/attachments/20091128/dae9b619/attachment.html>


More information about the fpc-pascal mailing list