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)。 该页面实际上将QueryInterfaceing 推荐为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 参数

访问 ccomptr 指针和应用程序崩溃时访问冲突(c 系统异常代码:c0000005)

通过 CComPtr<IDispatch> Invoke 检索数组

错误 C2664:无法将参数 2 从 'const ATL::CAdapt<ATL::CComPtr<IZipFileEntry>> *' 转换为 'ATL::CAdapt&l

DialogFragment 优于 AlertDialog [重复]

如何在应用程序退出时诊断 comptr 版本中的异常