Поделиться через


Запрос объекта для интерфейса

Ранее мы видели, что объект может реализовать несколько интерфейсов. Объект Common Item Dialog является реальным примером этого. Для поддержки наиболее типичных вариантов использования объект реализует интерфейс IFileOpenDialog . Этот интерфейс определяет основные методы для отображения диалогового окна и получения сведений о выбранном файле. Однако для более расширенного использования объект также реализует интерфейс IFileDialogCustomize. Программа может использовать этот интерфейс для настройки внешнего вида и поведения диалогового окна путем добавления новых элементов управления пользовательского интерфейса.

Помните, что каждый COM-интерфейс должен наследовать прямо или косвенно от интерфейса IUnknown . На следующей схеме показано наследование объекта Common Item Dialog.

схема, показывающая интерфейсы, предоставляемые объектом диалогового окна общего элемента

Как видно на схеме, прямым предком IFileOpenDialog является интерфейс IFileDialog , который, в свою очередь, наследует IModalWindow. По мере перехода по цепочке наследования из IFileOpenDialog в IModalWindow интерфейсы определяют все более обобщенные функции окна. Наконец, интерфейс IModalWindow наследует IUnknown. Объект Common Item Dialog также реализует IFileDialogCustomize, который существует в отдельной цепочке наследования.

Теперь предположим, что у вас есть указатель на интерфейс IFileOpenDialog . Как получить указатель на интерфейс IFileDialogCustomize ?

Схема, показывающая два указателя интерфейса на интерфейсы в одном объекте

Простое приведение указателя IFileOpenDialog к указателю IFileDialogCustomize не будет работать. Нет надежного способа "перекрестного приведения" в иерархии наследования без какой-то формы сведений о типах времени выполнения (RTTI), которая является в значительной степени зависящей от языка функцией.

Com-подход заключается в том, чтобы запросить у объекта указатель IFileDialogCustomize , используя первый интерфейс в качестве канала в объект. Для этого вызывается метод IUnknown::QueryInterface из первого указателя интерфейса. QueryInterface можно считать независимой от языка версией dynamic_cast ключевое слово в C++.

Метод QueryInterface имеет следующую сигнатуру:

HRESULT QueryInterface(REFIID riid, void **ppvObject);

Основываясь на том, что вы уже знаете о CoCreateInstance, вы можете угадать, как работает QueryInterface .

  • Параметр riid — это GUID, определяющий интерфейс, который вы запрашиваете. Тип данных REFIID является определением типа для const GUID&. Обратите внимание, что идентификатор класса (CLSID) не требуется, так как объект уже создан. Требуется только идентификатор интерфейса.
  • Параметр ppvObject получает указатель на интерфейс . Тип данных этого параметра — void**, по той же причине, по которой coCreateInstance использует этот тип данных: QueryInterface можно использовать для запроса любого com-интерфейса, поэтому параметр не может быть строго типизирован.

Вот как можно вызвать QueryInterface для получения указателя IFileDialogCustomize :

hr = pFileOpen->QueryInterface(IID_IFileDialogCustomize, 
    reinterpret_cast<void**>(&pCustom));
if (SUCCEEDED(hr))
{
    // Use the interface. (Not shown.)
    // ...

    pCustom->Release();
}
else
{
    // Handle the error.
}

Как всегда, проверка возвращаемое значение HRESULT в случае сбоя метода. Если метод завершается успешно, необходимо вызвать Release после завершения с помощью указателя, как описано в разделе Управление временем существования объекта.

Следующая

Выделение памяти в COM