Brian Frost
Brian Frost

Reputation: 13454

How to store and locate multiple interface types within a Delphi TInterfaceList

I'm storing small interfaces from a range of objects into a single TInterfaceList 'store' with the intention of offering list of specific interface types to the end user, so each interface will expose a 'GetName' function but all other methods are unique to that interface type. For example here are two interfaces:

  IBase = interface
    //----------------------------------------
    function GetName : string;
    //----------------------------------------
  end;

  IMeasureTemperature = interface(IBase)
    //------------------------------------
    function MeasureTemperature : double;
    //----------------------------------------
  end;

  IMeasureHumidity = interface(IBase)
    //----------------------------------------
    function MeasureHumidity: double;
    //----------------------------------------
  end;

I put several of these interfaces into a single TInterfaceList and then I'd like to scan the list for a specific interface type (e.g. 'IMeasureTemperature') building another list of pointers to the objects exporting those interfaces. I wish to make no assumptions about the locations of those objects, some may export more than one type of interface. I know I could do this with a class hierarchy using something like:

  If FList[I] is TMeasureTemperature then ..

but I'd like to do something simliar with an interface type, Is this possible?

Upvotes: 6

Views: 1722

Answers (3)

Ken Bourassa
Ken Bourassa

Reputation: 6487

I guess that might satisfy your needs.

function InterfaceRefIsInterface(Intf : IUnknown; ExpectedIntf : TGUID) : Boolean;
var vReference : IUnknown;
begin
  if Supports(Intf, ExpectedIntf, vReference)  then
    Result := Intf = vReference
  else
    Result := False;
end;

I'm not sure how the function will behave when Intf and ExpectedIntf inherits from one another, but this will return TRUE in the case Intf is an exact match of ExpectedIntf.

In your exemple, IMeasureHumidity won't return true on IMeasureTemperature, but I'm not sure how it will react to IBase. According to preliminary testing, it will also return FALSE on IBase.

Upvotes: 2

Viktor Svub
Viktor Svub

Reputation: 1469

You may use the Supports function in SysUtils, they are pretty safe (unless you try them on unitialized memory) and you only need a target variable of the exact interface type you try to cast to:


procedure DoSomethingInList(AList: IInterfaceList;);
var
  i: Integer;
  liItem: IInterface;
  liMeasureTemp: IMeasureTemperature;
  liMeasureHumi: IMeasureHumidity;
begin
  AList.Lock;
  try
    for i := 0 to AList.Count - 1 do
    begin
      liItem := AList[i];
      if Supports(liItem, IMeasureTemperature, liMeasureTemp) then
        //... liMeasureTemp.MeasureTemperature ...
      else if Supports(liItem, IMeasureHumidity, liMeasureHumi) then
        //... liMeasureHumi.MeasureHumidity ...
      else 
        //...
    end;
  finally
    AList.Unlock;
  end;
end; 

Upvotes: 2

da-soft
da-soft

Reputation: 7750

Just use Supports, like this:

var
  oMTIntf: IMeasureTemperature;
...
  If Supports(FList[I], IMeasureTemperature, oMTIntf) then .. 

Upvotes: 6

Related Questions