views:

212

answers:

1

In Delphi you can pass class references around to compare the types of objects, and to instantiate them. Can you do the same with interface references being passed to a COM automation server?

For example, you can define a method taking a GUID parameter using the type library editor:

function ChildNodesOfType(NodeType: TGUID): IMBNode; safecall;

In this function I would like to return automation types that support the interface specified by NodeType, e.g.

if Supports(SomeNode, NodeType) then
      result := SomeNode;

But the Supports call always fails, I tried passing in the Guids defined in the type library but none of the different types (Ixxx, Class_xxxx, IId_Ixxxx) seem to work.

+4  A: 

The SysUtils unit comes with at least five overloads of Supports, and they all accept a TGUID value for their second parameters.

You can indeed pass interface types as parameters, but they're really just GUIDs. That is, when a function expects a TGUID argument, you can pass it the interface type identifier, such as IMBNode or IUnknown. For that to work, though, the interface type needs to include a GUID in its declaration, like this:

type
  IMBNode = interface
    ['{GUID-goes-here}']
    // methods and properties
  end;

When the first parameter to Supports is an interface reference, the function calls its QueryInterface method. If it returns S_OK, then Supports return true; otherwise, it returns false. When the first parameter is an object reference, then it first calls the object's GetInterface method to get its IUnknown interface, and calls Supports on that like before. If it doesn't work that way, then it falls back to asking for the requested interface directly from GetInterface. If you've implemented QueryInterface correctly on your object, or if you've used the default implementation from TInterfacedObject, then everything should work fine.

If Supports never returns true for you, then you should revisit some assumptions. Are you sure your node really supports the interface you're requesting? Go make sure the class declaration includes that interface. Make sure QueryInterface is implemented properly. And make sure SomeNode actually refers to the node you're expecting it to.

Rob Kennedy
Hi Rob, thanks, great answer. There was no reason that it shouldn't work, as I was using TInterfacedObject with no frills. So I checked my assumptions and the failure was indeed a result of accidentally passing an object to Supports that didn't implement the interface.
Alan Clark