实现 QueryInterface 的规则

有三个主要规则管理在 COM 对象上实现 IUnknown::QueryInterface 方法:

  • 对象必须具有标识。
  • 对象实例上的接口集必须是静态。
  • 必须能够从任何其他接口成功查询对象上的任何接口。

对象必须具有标识

对于任何给定的对象实例,使用 IID_IUnknown 调用 QueryInterface 必须始终返回相同的物理指针值。 这样就可以对任意两个接口调用 QueryInterface,并比较结果以确定它们是否指向同一对象实例。

对象实例上的接口集必须是静态

通过 QueryInterface 在对象上访问的接口集必须是静态,而不是动态。 具体而言,如果 QueryInterface 为给定 IID 返回 S_OK 一次,则同一对象上的后续调用决不能返回 E_NOINTERFACE;如果 QueryInterface 返回给定 IID 的 E_NOINTERFACE,则同一对象上对同一 IID 的后续调用绝不能返回 S_OK。

必须能够从任何其他接口成功查询对象上的任何接口

也就是说,给定以下代码:

IA * pA = (some function returning an IA *); 
IB * pB = NULL; 
HRESULT   hr; 
hr = pA->QueryInterface(IID_IB, &pB); 
 

下列规则适用:

  • 如果有指向对象上的接口的指针,则以下对同一接口的 QueryInterface 的调用必须成功:

    pA->QueryInterface(IID_IA, ...) 
    
    
  • 如果对第二个接口指针的 QueryInterface 调用成功,则从该指针对第一个接口的 QueryInterface 调用也必须成功。 如果 pB 已成功获取,则以下操作也必须成功:

    pB->QueryInterface(IID_IA, ...) 
    
    
  • 任何接口都必须能够查询对象上的任何其他接口。 如果 pB 已成功获取,并且已成功使用该指针查询第三个接口 (IC),则还必须能够使用第一个指针 pA 成功查询 IC。 在这种情况下,以下序列必须成功:

    IC * pC = NULL; 
    hr = pB->QueryInterface(IID_IC, &pC); 
    pA->QueryInterface(IID_IC, ...) 
    
    

接口实现必须维护对给定对象上所有接口的未完成指针引用的计数器。 应为计数器使用无符号整数

如果客户端需要知道资源已释放,则必须在调用 IUnknown::Release 之前,在对象的某些接口中使用具有更高级别语义的方法。

使用和实现 IUnknown