COM 中 CComPtr 优于 CComQIPtr 的用途是啥?
Posted
技术标签:
【中文标题】COM 中 CComPtr 优于 CComQIPtr 的用途是啥?【英文标题】:What is the use of CComPtr over CComQIPtr in COM?COM 中 CComPtr 优于 CComQIPtr 的用途是什么? 【发布时间】:2011-10-14 06:26:57 【问题描述】:谁能解释一下,COM 中 CComPtr 而不是 CComQIPtr 的用途是什么?
CComPtr<ISampleInterface> Sample1;
CComQIPtr<ISampleInterface> Sample2;
【问题讨论】:
【参考方案1】: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 );
根本不会编译 - 它会产生
错误 C2664: 'ATL::CComPtr::CComPtr(IDispatch *) throw()' : 无法将参数 1 从 'IUnknown *' 转换为 'IDispatch *'
这提供了更好的编译时类型安全性。
【讨论】:
是否有任何理由不在所有情况下使用 CComQIPtr? @MattMcNabb 当然。当您的代码使用CComQIPtr
时,它可以尝试将任何类型指针绑定到任何类型对象,如果该接口不受支持,则会产生一个空指针,并且您必须在运行时检查它并为此提供额外的代码。跨度>
好的。我认为 OP 试图问:为什么有人会使用 CComPtr ,因为 CComQIPtr 做所有相同的事情但具有额外的功能。
@MattMcNabb 在某些情况下它做的太多了,这会破坏编译时类型检查。
好的,我明白了。您的最后一段提到了这一点,但您的 cmets 为我澄清了这一点。我可以建议编辑您的答案,因为 CComPtr 为您提供更好的类型安全性的原因是如果您无意中进行了分配,则会出现编译错误。【参考方案2】:
template<class T,
const IID* piid = &__uuidof(T)>
class CComQIPtr: public CComPtr<T>
Former 通过默认模板参数自动推断给定类型的 UUID。
【讨论】:
【参考方案3】:下面的 MSDN 文章解释了区别并建议使用 CComPtr 而不是 CComQIPtr
How to: Create and Use CComPtr and CComQIPtr Instances
【讨论】:
我不认为该页面建议使用 CComPtr 而不是 CComQIPtr。 (它说使用 CComPtr 而不是 _com_ptr,但我认为这意味着使用 CComPtr 或 CComQIPtr 而不是 _com_ptr)。 该页面实际上将QueryInterface
ing 推荐为CComPtr
,在那里你会得到一个说明失败原因的HRESULT,而不是使用CComQIPtr
,你总是得到nullptr
,你不知道为什么(接口未实现?访问被拒绝?没有代理/存根?代理/存根未注册?代理/存根 dll 未找到?没有类型库?类型库未注册?类型库未找到?rpc 错误?没有更多内存?)跨度>
【参考方案4】:
评论尖牙的答案。只是试图编译某事。喜欢
CComQIPtr<IInterface2> to( from );
失败了。分配反而起作用了:
CComQIPtr<IInterface2> to = from;
很遗憾,我没有时间进一步分析这个......
【讨论】:
【参考方案5】:“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 对应的接口指针。
【讨论】:
以上是关于COM 中 CComPtr 优于 CComQIPtr 的用途是啥?的主要内容,如果未能解决你的问题,请参考以下文章
访问 ccomptr 指针和应用程序崩溃时访问冲突(c 系统异常代码:c0000005)
通过 CComPtr<IDispatch> Invoke 检索数组
错误 C2664:无法将参数 2 从 'const ATL::CAdapt<ATL::CComPtr<IZipFileEntry>> *' 转换为 'ATL::CAdapt&l