在COM中,CComPtr相对于CComQIPtr有什么用处?

21

有人能解释一下,CComPtr在COM中的作用是什么,与CComQIPtr相比有何优劣之处?

CComPtr<ISampleInterface> Sample1;
CComQIPtr<ISampleInterface> Sample2;
5个回答

32

CComQIPtr是用于在方便的方式下调用QueryInterface()以了解接口是否被支持的情况:

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

使用这种方法,您可以从指向任何(不相关的)COM接口的指针请求一个接口,并检查该请求是否成功。

CComPtr 用于管理肯定支持某些接口的对象。您可以将其用作具有引用计数的智能指针。它类似于 CComQIPtr,但不允许上述用例,并且这样可以提供更好的类型安全性。

这段代码:

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

如果unknown绑定到未实现IDispatch的对象,则编译可能会生成空指针。您现在必须在运行时检查,如果您一开始就想要运行时检查,那么这是好的,但如果您更喜欢编译时类型检查,则不好。

这段代码:

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

无法编译 - 它会产生错误:

error C2664:'ATL :: CComPtr :: CComPtr(IDispatch *)throw()':无法将参数1从'IUnknown *'转换为'IDispatch *'

这提供了更好的编译时类型安全性。


在所有情况下都使用CComQIPtr有没有任何不适用的理由? - M.M
@MattMcNabb 当你的代码使用 CComQIPtr 时,它可以尝试将任何类型指针绑定到任何类型对象,如果接口不受支持,则会生成一个空指针,你将需要在运行时检查并编写额外的代码来处理该情况。 - sharptooth
еҘҪзҡ„гҖӮжҲ‘и®ӨдёәOPжғій—®пјҡ既然CComQIPtrе…·жңүйўқеӨ–зҡ„еҠҹиғҪпјҢдёәд»Җд№ҲиҝҳиҰҒдҪҝз”ЁCComPtrе‘ўпјҹ - M.M
@MattMcNabb 在某些情况下,它做了太多的事情,这会破坏编译时类型检查。 - sharptooth
好的,我明白了。你最后一段提到了这一点,但是你的评论为我澄清了这一点。我可以建议你将原因编辑到你的答案中,即CComPtr会在意外赋值时产生编译错误,从而给你更好的类型安全性。 - M.M
显示剩余4条评论

2
template<class T,
   const IID* piid = &__uuidof(T)>
class CComQIPtr: public CComPtr<T>

默认模板参数会自动推断给定类型的UUID。


1

我认为该页面并没有推荐使用CComPtr而不是CComQIPtr。(它建议使用CComPtr代替_com_ptr,但我认为它的意思是使用CComPtr或CComQIPtr代替_com_ptr)。 - M.M
2
该页面实际上建议使用QueryInterface进入CComPtr,在其中获取一个HRESULT来说明失败的原因,而不是使用CComQIPtr,在其中你总是会得到nullptr,并且你不知道为什么(接口未实现?访问被拒绝?没有代理/存根?代理/存根未注册?代理/存根DLL未找到?没有类型库?类型库未注册?类型库未找到?RPC错误?没有更多内存?) - acelent

0
ATL使用CComQIPtr和CComPtr来管理COM接口指针。这两个类通过调用AddRef和Release来自动进行引用计数。重载的运算符处理指针操作。CComQIPtr还支持通过QueryInterface自动查询接口。
那么你在什么情况下使用其中一个而不是另一个呢?
当你不想手动调用'QueryInterface()'时,使用'CComQIPtr'。
CComQIPtr( T* lp );

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

如果您传递的是从 T 派生的指针类型,则构造函数将 p 设置为 T* 参数并调用 AddRef。如果您传递的是不从 T 派生的指针类型,则构造函数将调用 QueryInterface 来将 p 设置为与 piid 相应的接口指针。


0

关于sharptooth的回答,我刚试着编译了一些类似的东西。

CComQIPtr<IInterface2> to( from );

失败了。改为赋值就可以了:

CComQIPtr<IInterface2> to = from;

很遗憾我没有时间进一步分析这个问题...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接