The secret QueryInterface call of CComPtr

CComPtr is a convenient smart pointer ATL class to manage reference counting of COM objects.
However, it seems that sometimes smart pointers are too smart… In particular, I’m referring to the secret QueryInterface‘ing assignment operator discussed by Jared Parsons on his blog:

http://blogs.msdn.com/jaredpar/archive/2009/11/04/type-safety-issue-when-assigning-ccomptr-t-instances.aspx

The problem is the IUnknown::QueryInterface call performed by AtlComQIPtrAssign in the following templated assignment operator overload of CComPtr:

template <typename Q>

T* operator=(_In_ const CComPtr<Q>& lp) throw()

{

  if( !IsEqualObject(lp) )

  {

    return static_cast<T*>(AtlComQIPtrAssign((IUnknown**)&p, lp, __uuidof(T)));

  }

  return *this;

}

As an example, the following C++ code compiles fine (and I think it shouldn’t) on VC9 (VS2008 SP1):

#include <atlcomcli.h>

 

int main()

{

    CComPtr<IMarshal> sp1;

    CComPtr<IPersist> sp2;

 

    // I think the following statement should not compile,

    // but instead it does compile…

    sp1 = sp2;

 

    return 0;

}

Frankly speaking, I consider this behavior of CComPtr a bug; in fact, CComPtr isn’t supposed to call QueryInterface automatically: there’s CComQIPtr for that.
A possible fix to the aforementioned CComPtr behavior (bug) could be to redefine the templated assignment operator using implicit conversion for underlying raw pointers (instead of using IUnknown::QueryInterface via AtlComQIPtrAssign), e.g.:

    template <typename Q>

    T* operator=(_In_ const CComPtr<Q>& lp) throw()

    {

        return (*this = lp.p);

    }

 

A VS2008 solution with sample C++ code including the fix to CComPtr is attached to this blog post.

Thanks to Igor Tandetnik for private communication about this issue.

 

 

 

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *


*