QueryInterface:在对象中导航

当对象上具有指向接口的初始指针后,COM 有一种非常简单的机制,用于确定该对象是否支持另一个特定接口,如果是,则获取指向该接口的指针。 (有关获取指向对象上接口的初始指针的信息,请参阅获取指向对象的指针。)此机制是 IUnknown 接口的 QueryInterface 方法。 如果对象支持请求的接口,该方法必须返回指向该接口的指针。 这允许对象通过对象支持的接口自由导航。 QueryInterface 将请求“是否支持给定协定?”与协商成功后该协定的高性能使用分开。

当客户端最初获取对象访问权限时,该客户端至少会收到一个 IUnknown 接口指针(最基本的接口),由此可以通过告知对象何时使用对象完成并调用 QueryInterface 来控制对象的生存期。 对进行客户端编程,要求其管理的每个对象执行某些操作,但 IUnknown 接口没有函数可执行这些操作。 相反,这些操作通过其他接口表示。 因此,对客户端进行编程,以与对象就这些接口进行协商。 具体而言,客户端将调用 QueryInterface 来要求对象提供客户端可以调用所需操作的接口。

实现 QueryInterface 的对象能够接受或拒绝此请求。 如果对象接受客户端的请求,QueryInterface 将向客户端返回一个指向请求的接口的新指针。 通过该接口指针,客户端可以访问该接口的方法。 另一方面,如果对象拒绝客户端的请求,QueryInterface 将返回空指针(错误),并且客户端没有调用所需函数的指针。 在这种情况下,客户端必须妥善处理这种可能性。 例如,假设客户端具有指向对象上接口 A 的指针,并请求接口 B 和 C。同时假设该对象支持接口 B,但不支持接口 C。结果是对象返回指向 B 的指针,并报告 C 不受支持。

关键点是,当对象拒绝调用 QueryInterface 时,客户端无法要求该对象执行通过请求的接口表示的操作。 客户端必须具有接口指针才能调用该接口中的方法。 如果对象拒绝提供请求的指针,则客户端必须准备好在不使用任何指针时执行操作,要么通过不执行任何意图使用该对象的操作,要么通过尝试回退到另一个(可能不太强大)接口。 COM 的这一功能与其他面向对象的系统相比非常有效,在该系统中,你不知道函数在调用之前是否有效,即使这样,处理失败也不确定。 QueryInterface 提供一种可靠且一致的方法来了解对象在尝试调用接口的方法之前是否支持该接口。

QueryInterface 方法还提供一种强大且可靠的方法来指示对象不支持给定协定。 也就是说,如果在对 QueryInterface 的调用中,询问一个“旧”对象是否支持“新”接口(例如,在旧对象交付后创建的接口),旧对象将可靠地(而不会造成崩溃)回答“否”。支持此功能的技术是分配 IID 的算法。 虽然这似乎是一个小功能,但却对系统的整个体系结构非常重要,并且查询旧元素的新功能的能力令人惊叹,大多数其他对象体系结构中不存在这一功能。

使用和实现 IUnknown