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


Использование CUnknown

[Функция, связанная с этой страницей DirectShow, является устаревшей функцией. Он был заменен MediaPlayer, IMFMediaEngine, и аудио/ видео захвата в Media Foundation. Эти функции оптимизированы для Windows 10 и Windows 11. Корпорация Майкрософт настоятельно рекомендует использовать в новом коде MediaPlayer, IMFMediaEngine и аудио/видеозахват в Media Foundation вместо DirectShow, когда это возможно. Корпорация Майкрософт предлагает переписать существующий код, в котором используются устаревшие API, чтобы по возможности использовать новые API.]

DirectShow реализует IUnknown в базовом классе CUnknown. CUnknown можно использовать для получения других классов, переопределяя только методы, которые изменяются в разных компонентах. Большинство других базовых классов в DirectShow являются производными от CUnknown, поэтому компонент может наследовать непосредственно от CUnknown или от другого базового класса.

INonDelegatingUnknown

CUnknown реализует INonDelegatingUnknown. Он управляет счетчиками ссылок внутри организации, и в большинстве случаев производный класс может наследовать два метода подсчета ссылок без изменений. Имейте в виду, что CUnknown удаляет себя, когда количество ссылок падает до нуля. С другой стороны, необходимо переопределить CUnknown::NonDelegatingQueryInterface, так как метод в базовом классе возвращает E_NOINTERFACE, если получает какие-либо IID, отличные от IID_IUnknown. В производном классе проверьте наличие идентификаторов IID интерфейсов, которые вы поддерживаете, как показано в следующем примере:

STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
    if (riid == IID_ISomeInterface)
    {
        return GetInterface((ISomeInterface*)this, ppv);
    }
    // Default: Call parent class method. 
    // The CUnknown class must be in the inheritance chain.
    return CParentClass::NonDelegatingQueryInterface(riid, ppv);
}

Служебная функция GetInterface (см. раздел Вспомогательные функции COM) задает указатель, увеличивает число ссылок потокобезопасно и возвращает S_OK. В случае по умолчанию вызовите метод базового класса и верните результат. Если вы наследуете от другого базового класса, вызовите его метод NonDelegatingQueryInterface . Это позволяет поддерживать все интерфейсы, поддерживаемые родительским классом.

IUnknown

Как упоминалось ранее, делегированная версия IUnknown одинакова для каждого компонента, так как она выполняет не более чем вызов правильного экземпляра неделегирующих версий. Для удобства файл заголовка Combase.h содержит макрос DECLARE_IUNKNOWN, который объявляет три метода делегирования как встроенные методы. Он разворачивается до следующего кода:

STDMETHODIMP QueryInterface(REFIID riid, void **ppv) {      
    return GetOwner()->QueryInterface(riid,ppv);            
};                                                          
STDMETHODIMP_(ULONG) AddRef() {                             
    return GetOwner()->AddRef();                            
};                                                          
STDMETHODIMP_(ULONG) Release() {                            
    return GetOwner()->Release();                           
};

Служебная функция CUnknown::GetOwner извлекает указатель на интерфейс IUnknown компонента, которому принадлежит этот компонент. Для агрегированного компонента владельцем является внешний компонент. В противном случае компонент владеет самим собой. Включите макрос DECLARE_IUNKNOWN в открытый раздел определения класса.

Конструктор класса

Конструктор класса должен вызывать метод конструктора для родительского класса в дополнение к действиям, которые относятся к вашему классу. В следующем примере показан типичный метод конструктора:

CMyComponent(TCHAR *tszName, LPUNKNOWN pUnk, HRESULT *phr) 
    : CUnknown(tszName, pUnk, phr)
{ 
    /* Other initializations */ 
};

Метод принимает следующие параметры, которые передаются непосредственно методу конструктора CUnknown .

  • tszName указывает имя компонента.
  • pUnk — это указатель на агрегирование IUnknown.
  • pHr — это указатель на значение HRESULT, указывающее на успешное или неудачное выполнение метода.

Итоги

В следующем примере показан производный класс, поддерживающий IUnknown , и гипотетический интерфейс ISomeInterface:

class CMyComponent : public CUnknown, public ISomeInterface
{
public:

    DECLARE_IUNKNOWN;

    STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv)
    {
        if( riid == IID_ISomeInterface )
        {
            return GetInterface((ISomeInterface*)this, ppv);
        }
        return CUnknown::NonDelegatingQueryInterface(riid, ppv);
    }

    CMyComponent(TCHAR *tszName, LPUNKNOWN pUnk, HRESULT *phr) 
        : CUnknown(tszName, pUnk, phr)
    { 
        /* Other initializations */ 
    };

    // More declarations will be added later.
};

В этом примере показаны следующие моменты:

  • Класс CUnknown реализует интерфейс IUnknown . Новый компонент наследует от CUnknown и от любых интерфейсов, поддерживаемых компонентом. Вместо этого компонент может быть производным от другого базового класса, наследуемого от CUnknown.
  • Макрос DECLARE_IUNKNOWN объявляет делегированные методы IUnknown как встроенные методы.
  • Класс CUnknown предоставляет реализацию для INonDelegatingUnknown.
  • Для поддержки интерфейса, отличного от IUnknown, производный класс должен переопределить метод NonDelegatingQueryInterface и проверить наличие IID нового интерфейса.
  • Конструктор класса вызывает метод конструктора для CUnknown.

Следующий шаг при написании фильтра — разрешить приложению создавать новые экземпляры компонента. Для этого необходимо понимать библиотеки DLL и их отношение к фабрикам классов и методам конструктора классов. Дополнительные сведения см. в разделе How to Create a DirectShow Filter DLL.

Реализация IUnknown