QueryInterface: навигация в объекте
После того как у вас есть начальный указатель на интерфейс объекта, COM имеет очень простой механизм, чтобы узнать, поддерживает ли объект другой конкретный интерфейс и, если да, получить указатель на него. (Сведения о получении начального указателя на интерфейс в объекте см. в разделе Получение указателя на объект.) Этот механизм является методом QueryInterface интерфейса IUnknown. Если объект поддерживает запрошенный интерфейс, метод должен вернуть указатель на этот интерфейс. Это позволяет объекту свободно перемещаться через интерфейсы, поддерживаемые объектом. QueryInterface отделяет запрос "Поддерживаете ли вы указанный контракт?" от высокопроизводительного использования этого контракта после успешного выполнения переговоров.
Когда клиент изначально получает доступ к объекту, этот клиент получит, по крайней мере, указатель интерфейса IUnknown (самый фундаментальный интерфейс), с помощью которого он может управлять временем существования объекта, сказав объекту, когда он будет выполнен с помощью объекта, и вызовите QueryInterface. Клиент запрограммирован на запрос каждого объекта, который он управляет выполнением некоторых операций, но интерфейс IUnknown не имеет функций для этих операций. Вместо этого эти операции выражаются с помощью других интерфейсов. Таким образом, клиент запрограммирован для согласования с объектами для этих интерфейсов. В частности, клиент вызовет QueryInterface запрос объекта для интерфейса, через который клиент может вызвать нужные операции.
Так как объект реализует QueryInterface, он имеет возможность принимать или отклонять запрос. Если объект принимает запрос клиента, QueryInterface возвращает новый указатель на запрошенный интерфейс клиенту. Через этот указатель интерфейса клиент имеет доступ к методам этого интерфейса. Если, с другой стороны, объект отклоняет запрос клиента, QueryInterface возвращает пустой указатель — ошибку, и клиент не имеет указателя, через который следует вызывать нужные функции. В этом случае клиент должен корректно работать с этой возможностью. Например, предположим, что клиент имеет указатель на интерфейс A на объект и запрашивает интерфейсы B и C. Предположим, что объект поддерживает интерфейс B, но не поддерживает интерфейс C. Результатом является то, что объект возвращает указатель на B и сообщает, что C не поддерживается.
Ключевой точкой является то, что, когда объект отклоняет вызов QueryInterface, клиенту невозможно попросить объект выполнять операции, выраженные через запрошенный интерфейс. Клиент должен иметь указатель интерфейса для вызова методов в этом интерфейсе. Если объект отказывается предоставить запрошенный указатель, клиент должен быть готов сделать без этого, не выполняя никаких действий, которые он намеревался сделать с этим объектом или пытаясь вернуться к другому, возможно, менее мощному интерфейсу. Эта функция COM хорошо работает в сравнении с другими объектно-ориентированными системами, в которых нельзя знать, будет ли функция работать, пока не вызовете эту функцию, и даже тогда обработка сбоя не определена. QueryInterface предоставляет надежный и согласованный способ узнать, поддерживает ли объект интерфейс перед попыткой вызова методов.
Метод QueryInterface также предоставляет надежный и надежный способ для объекта, указывающего, что он не поддерживает заданный контракт. То есть, если при вызове QueryInterface один запрашивает "старый" объект, поддерживает ли он "новый" интерфейс (например, который был изобретен после отправки старого объекта), старый объект будет надежно, не вызывая аварии, ответ "нет". Технология, поддерживающая это алгоритм, с помощью которого выделяются идентификаторы IID. Хотя это может показаться небольшой моментом, крайне важно для общей архитектуры системы, и возможность узнать о устаревших элементах о новых функциональных возможностях, удивительно, функция, которая не присутствует в большинстве других архитектур объектов.
См. также