21

Can any one explain, What is the use of CComPtr over CComQIPtr in COM?

CComPtr<ISampleInterface> Sample1;
CComQIPtr<ISampleInterface> Sample2;
sharptooth
  • 167,383
  • 100
  • 513
  • 979
Ramesh
  • 257
  • 1
  • 3
  • 5

5 Answers5

32

CComQIPtr is for cases when you want to call QueryInterface() in a convenient manner to know whether an interface is supported:

IInterface1* from = ...
CComQIPtr<IInterface2> to( from );
if( to != 0 ) {
   //supported - use
}

This way you can request an interface from a pointer to any (unrelated) COM interface and check whether that request succeeded.

CComPtr is used for managing objects that surely support some interface. You use it as a usual smart pointer with reference counting. It is like CComQIPtr, but doesn't allow the usecase described above and this gives you better type safety.

This code:

IUnknown* unknown = ... ;
CComQIPtr<IDispatch> dispatch( unknown );

compiles and maybe yields a null pointer if unknown is bound to an object that doesn't implement IDispatch. You now have to check for that in runtime which is good if you wanted a runtime check in the first place but bad if you'd prefer a compile time type check.

This code:

IUnknown* unknown = ... ;
CComPtr<IDispatch> dispatch( unknown );

will simply not compile - it yields

error C2664: 'ATL::CComPtr::CComPtr(IDispatch *) throw()' : cannot convert parameter 1 from 'IUnknown *' to 'IDispatch *'

which provides for better compile time type safety.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • Is there any reason not to use CComQIPtr in all cases? – M.M Jun 15 '15 at 08:06
  • @MattMcNabb Sure. When your code uses `CComQIPtr` it can try bind any type pointer to any type object which will yield a null pointer if the interface is not supported and you'll have to check for that in runtime and have extra code for that. – sharptooth Jun 15 '15 at 08:14
  • OK. I think the OP was trying to ask: why would anyone use CComPtr , given that CComQIPtr does all the same things but has extra functionality. – M.M Jun 15 '15 at 08:17
  • @MattMcNabb It does too much in some cases and that subverts compile time type checks. – sharptooth Jun 15 '15 at 08:18
  • OK I see. Your last para touches on that but your comments clarified it for me. Can I suggest editing into your answer that the reason CComPtr gives you better type safety is because of the compilation error if you inadvertantly make an assignment. – M.M Jun 15 '15 at 08:24
  • This doesn't really make sense. COM expressly uses runtime type polymorphism. Compile time checks don't buy you anything. This is not the reason why you'd favor one over the other. The **only** reason to use `CComPtr` over `CComQIPtr` is, that the former communicates additional error information in case a `QueryInterface` call fails. – IInspectable Aug 13 '19 at 20:08
  • This does make a lot of sense. A COM object will typically implement up to three interfaces all in one inheritance chain and any reasonable use requires the most derived one. Compile-time checks make the code much more maintainable. – sharptooth Aug 14 '19 at 14:59
  • Where does that *"up to three interfaces"* come from? All COM objects implement 1 or more interfaces. COM objects that implement more than 1 interface usually use multiple inheritance, so there is no single *"most derived"* interface. – IInspectable Aug 15 '19 at 13:43
  • A typical situation is that a COM object implements one interface of interest which is derived from IUnknown and also maybe derived from IDispatch, that's up to three interfaces, and you only care of that one interface in the most of your code so CComPtr has good chances to make your code better. – sharptooth Aug 16 '19 at 08:40
2
template<class T,
   const IID* piid = &__uuidof(T)>
class CComQIPtr: public CComPtr<T>

Former deduces the UUID of given type automatically, via default template argument.

Ajay
  • 18,086
  • 12
  • 59
  • 105
1

The following MSDN article explains the difference and recommends using CComPtr instead of CComQIPtr

How to: Create and Use CComPtr and CComQIPtr Instances

vikas pachisia
  • 553
  • 5
  • 8
  • I don't think that page is recommending to use CComPtr over CComQIPtr. (It says to use CComPtr instead of _com_ptr, but I think it means to use either CComPtr or CComQIPtr instead of _com_ptr). – M.M Jun 15 '15 at 08:05
  • 2
    That page actually recommends `QueryInterface`ing into a `CComPtr`, where you get an HRESULT stating what failed, over using `CComQIPtr`, where you always get `nullptr` and you have no idea why (interface not implemented? access denied? no proxy/stub? proxy/stub not registered? proxy/stub dll not found? no type library? type library not registered? type library not found? rpc error? no more memory?) – acelent Jun 18 '15 at 17:00
0

"ATL uses CComQIPtr and CComPtr to manage COM interface pointers. Both classes perform automatic reference counting through calls to AddRef and Release. Overloaded operators handle pointer operations. CComQIPtr additionally supports automatic querying of interfaces though QueryInterface."

And where do you use one over the other?

When you do not want to call 'QueryInterface()' 'manually', use 'CComQIPtr':

CComQIPtr( T* lp );

CComQIPtr( const CComQIPtr< T, piid >& lp );

If you pass a pointer type derived from T, the constructor sets p to the T* parameter and calls AddRef. If you pass a pointer type not derived from T, the constructor calls QueryInterface to set p to an interface pointer corresponding to piid.

kevinLi
  • 11
0

Remark on the answer of sharptooth. Just tried to compile sth. like

CComQIPtr<IInterface2> to( from );

and failed. Assignment instead worked:

CComQIPtr<IInterface2> to = from;

Unfortunately I have no time to analyse this further...

yau
  • 537
  • 6
  • 14