4

If I have two COM interface pointers (i.e. ID3D11Texture2D), and I want to check if they are the same underlying class instance, can I compare the two pointers directly for equality? I have seen code where we cast it to something else before the comparison is done, so wanted to confirm.

BOOL IsEqual (ID3D11Texture2D *pTexture1, ID3D11Texture2D *pTexture2)
{
    if (pTexture1 == pTexture2)
    {
        return true;
    }
    else
    {
        return false;
    }
} 

Thanks.

lancery
  • 658
  • 1
  • 6
  • 18

1 Answers1

9

The correct COM way to do this is to query interface with IUnknown. A quote from the remarks here in MSDN:

For any one object, a specific query for the IUnknown interface on any of the object's interfaces must always return the same pointer value. This enables a client to determine whether two pointers point to the same component by calling QueryInterface with IID_IUnknown and comparing the results. It is specifically not the case that queries for interfaces other than IUnknown (even the same interface through the same pointer) must return the same pointer value.

So the correct code is

BOOL IsEqual (ID3D11Texture2D *pTexture1, ID3D11Texture2D *pTexture2)
{
    IUnknown *u1, *u2;

    pTexture1->QueryInterface(IID_IUnknown, &u1);
    pTexture2->QueryInterface(IID_IUnknown, &u2);

    BOOL areSame = u1 == u2;
    u1->Release();
    u2->Release();

    return areSame;
}

Update

  1. Added a call to Release so decrease reference counts. Thanks for the good comments.
  2. You can also use ComPtr for this job. Please look in MSDN.
Alex Shtoff
  • 2,520
  • 1
  • 25
  • 53
  • 2
    Don't forget that `Release()` will need to be called on those pointers. – Michael Burr May 01 '14 at 07:42
  • I can see why QI for IUKnown before the pointer comparison needs to be done. However, I struggle to understand this from a pragmatic perspective. An interface pointer is just a vtbl pointer for the interface methods that an underlying class implements. In fact, most implementations of QI I have seen are simple static_casts of the "this" pointer, which simply traverses the memory layout of the class implementation to get to the vtbl pointer. Therefore, I cannot help but wonder under what circumstances would we not return the same pointer if we are QI for the same interface via the same pointer? – lancery May 01 '14 at 07:42
  • @lancery - COM identity is only on IUnknown. You can't assume anything for other IID, although some implementations do return the same pointer behind the scenes. Also check this: http://msdn.microsoft.com/en-us/library/windows/desktop/ms686590(v=vs.85).aspx – Simon Mourier May 01 '14 at 07:51
  • @Simon - I totally get the COM contract now. I am just curious what are the scenarios where we would purposefully implement QI so that QI for the same interface via the same pointer wouldn't return the same pointer value, and what are the advantages of doing that versus the alternative, which seems much more intuitive. – lancery May 01 '14 at 07:56
  • You should also check the return value to see if QI succeeded (or initialize the pointers to null). – M.M May 01 '14 at 08:07
  • @lancery: You can't assume an interface pointer is a vtbl pointer. You can't even assume the other side is C++ ! If it's a script language, it might create an interface on the fly. – MSalters May 01 '14 at 08:34
  • In his specific case the other side is Direct3D. But I would not make assumptions on Direct3D either. – Alex Shtoff May 01 '14 at 08:35