How to check if a class implements an interface, with respecting supersets?

com, delphi, interface, oop

Solution

This is a known quirk of Delphi. Even though `IB` inherits from `IA`, `TBO` must explicitly specify both `IA` and `IB` in order for `Supports()` to retrieve both interfaces.

TBO = class(TInterfacedObject, IA, IB)

I forget the technical reason for this. Something to do with a limitation in how the compiler generates the interface table for `TBO`. It does not automatically include inherited interfaces.

Problem

I am learning about COM and Interfaces and have following experimental code: ``` type IA = interface(IInterface) ['{C9C5C992-3F67-48C5-B215-7DCE6A61F0E8}'] end; IB = interface(IA) ['{F1799437-AD12-471B-8716-F1D93D1692FC}'] end; IC = interface(IB) ['{01780E8C-C47D-468E-8E42-4BFF3F495D51}'] end; TBO = class(TInterfacedObject, IB) end; procedure TForm1.FormCreate(Sender: TObject); var x: TBO; a: IInterface; begin x := TBO.Create; IInterface(x)._AddRef; if Assigned(TBO.GetInterfaceEntry(IA)) then memo1.lines.add('GetInterfaceEntry IA: OK'); // Why not? if Assigned(TBO.GetInterfaceEntry(IB)) then memo1.lines.add('GetInterfaceEntry IB: OK'); if Assigned(TBO.GetInterfaceEntry(IC)) then memo1.lines.add('GetInterfaceEntry IC: OK'); if x.QueryInterface(IA, a)=S_OK then memo1.lines.add('QueryInterface TA: OK'); // Why not? if x.QueryInterface(IB, a)=S_OK then memo1.lines.add('QueryInterface TB: OK'); if x.QueryInterface(IC, a)=S_OK then memo1.lines.add('QueryInterface TC: OK'); if Supports(TBO, IA) then memo1.lines.add('Supports TA: OK'); // Why not? if Supports(TBO, IB) then memo1.lines.add('Supports TB: OK'); if Supports(TBO, IC) then memo1.lines.add('Supports TC: OK'); if Supports(x, IA, a) then memo1.lines.add('Supports(2) TA: OK'); // Why not? if Supports(x, IB, a) then memo1.lines.add('Supports(2) TB: OK'); if Supports(x, IC, a) then memo1.lines.add('Supports(2) TC: OK'); end; ``` Output: ``` GetInterfaceEntry IB: OK QueryInterface TB: OK Supports TB: OK Supports(2) TB: OK ``` But I need: ``` GetInterfaceEntry IA: OK GetInterfaceEntry IB: OK QueryInterface TA: OK QueryInterface TB: OK Supports TA: OK Supports TB: OK Supports(2) TA: OK Supports(2) TB: OK ``` I understand that `IB` is a superset of `IA` due to the Interface inheritance. In my understanding, since `TBO` implements `IB`, it automatically implements `IA`. But why does `Supports()`, `QueryInterface()`, `GetInterfaceEntry()` return false? How do I query if `TBO` implements `IA` directly OR indirectly, i.e. by implementing a superset of `IA`? I need both, a static class function like `GetInterfaceEntry` and a dynamic object reference variant like `QueryInterface`.

Original source

Related problems