Как работает IUnknown
[Функция, связанная с этой страницей DirectShow, является устаревшей функцией. Он был заменен MediaPlayer, IMFMediaEngine, и аудио/ видео захвата в Media Foundation. Эти функции оптимизированы для Windows 10 и Windows 11. Корпорация Майкрософт настоятельно рекомендует использовать в новом коде MediaPlayer, IMFMediaEngine и аудио/видеозахват в Media Foundation вместо DirectShow, когда это возможно. Корпорация Майкрософт предлагает переписать существующий код, в котором используются устаревшие API, чтобы по возможности использовать новые API.]
Методы в IUnknown позволяют приложению запрашивать интерфейсы в компоненте и управлять количеством ссылок компонента.
Количество ссылок
Число ссылок — это внутренняя переменная, увеличенная в методе AddRef и уменьшенная в методе Release . Базовые классы управляют количеством ссылок и синхронизируют доступ к счетчику ссылок между несколькими потоками.
Запросы интерфейса
Запрос к интерфейсу также является простым. Вызывающий объект передает два параметра: идентификатор интерфейса (IID) и адрес указателя. Если компонент поддерживает запрошенный интерфейс, он задает указатель на интерфейс, увеличивает собственное число ссылок и возвращает S_OK. В противном случае он задает для указателя значение NULL и возвращает E_NOINTERFACE. В следующем псевдокоде показан общий контур метода QueryInterface . Агрегат компонентов, описанный в следующем разделе, представляет дополнительную сложность.
if (IID == IID_IUnknown)
set pointer to (IUnknown *)this
AddRef
return S_OK
else if (IID == IID_ISomeInterface)
set pointer to (ISomeInterface *)this
AddRef
return S_OK
else if ...
else
set pointer to NULL
return E_NOINTERFACE
Единственное различие между методом QueryInterface одного компонента и методом QueryInterface другого заключается в списке идентификаторов IID, которые тестируются каждым компонентом. Для каждого интерфейса, который поддерживает компонент, компонент должен проверить наличие IID этого интерфейса.
Агрегирование и делегирование
Агрегирование компонентов должно быть прозрачным для вызывающей стороны. Таким образом, агрегат должен предоставлять один интерфейс IUnknown , при этом агрегированный компонент откладывается на реализацию внешнего компонента. В противном случае вызывающий объект увидит два разных интерфейса IUnknown в одном агрегате. Если компонент не является агрегированным, он использует собственную реализацию.
Для поддержки этого поведения компонент должен добавить уровень косвенного обращения. Делегирование IUnknown делегирует работу в соответствующее место: внешнему компоненту, если он есть, или во внутреннюю версию компонента. Неразделяющий IUnknown выполняет эту работу, как описано в предыдущем разделе.
Делегированная версия является общедоступной и сохраняет имя IUnknown. Неотделяющая версия переименована в INonDelegatingUnknown. Это имя не является частью спецификации COM, так как оно не является общедоступным интерфейсом.
Когда клиент создает экземпляр компонента, он вызывает метод IClassFactory::CreateInstance . Один из параметров является указателем на интерфейс IUnknown компонента агрегирования или значение NULL , если новый экземпляр не является агрегированным. Компонент использует этот параметр для хранения переменной-члена, указывающей, какой интерфейс IUnknown использовать, как показано в следующем примере:
CMyComponent::CMyComponent(IUnknown *pOuterUnkown)
{
if (pOuterUnknown == NULL)
m_pUnknown = (IUnknown *)(INonDelegatingUnknown *)this;
else
m_pUnknown = pOuterUnknown;
[ ... more constructor code ... ]
}
Каждый метод в делегировании IUnknown вызывает его неделегирующие аналоги, как показано в следующем примере:
HRESULT QueryInterface(REFIID iid, void **ppv)
{
return m_pUnknown->QueryInterface(iid, ppv);
}
По характеру делегирования методы делегирования выглядят идентичными в каждом компоненте. Изменяются только неразделяющие версии.
Связанные темы