Usando CUnknown

O DirectShow implementa o IUnknown em uma classe base chamada CUnknown. Você pode usar o CUnknown para derivar outras classes, substituindo apenas os métodos que mudam entre componentes. A maioria das outras classes base no DirectShow deriva de CUnknown, para que seu componente possa herdar diretamente do CUnknown ou de outra classe base.

Inondelegatingunknown

O CUnknown implementa INonDelegatingUnknown. Ele gerencia contagens de referência internamente e, na maioria das situações, sua classe derivada pode herdar os dois métodos de contagem de referência sem nenhuma alteração. Lembre-se de que o CUnknown se exclui quando a contagem de referência cai para zero. Por outro lado, você deve substituir CUnknown::NonDelegatingQueryInterface, pois o método na classe base retorna E_NOINTERFACE se ele receber qualquer IID diferente de IID_IUnknown. Em sua classe derivada, teste para os IIDs de interfaces compatíveis, conforme mostrado no exemplo a seguir:

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);
}

A função de utilitário GetInterface (consulte COM Helper Functions) define o ponteiro, incrementa a contagem de referência de uma maneira thread-safe e retorna S_OK. No caso padrão, chame o método de classe base e retorne o resultado. Se você derivar de outra classe base, chame seu método NonDelegatingQueryInterface . Isso permite que você dê suporte a todas as interfaces compatíveis com a classe pai.

IUnknown

Conforme mencionado anteriormente, a versão delegada do IUnknown é a mesma para cada componente, pois não faz nada mais do que invocar a instância correta da versão não desdlegante. Para conveniência, o arquivo de cabeçalho Combase.h contém uma macro, DECLARE_IUNKNOWN, que declara os três métodos delegantes como métodos embutidos. Ele se expande para o seguinte código:

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

A função de utilitário CUnknown::GetOwner recupera um ponteiro para a interface IUnknown do componente que possui esse componente. Para um componente agregado, o proprietário é o componente externo. Caso contrário, o componente é proprietário. Inclua a macro DECLARE_IUNKNOWN na seção pública de sua definição de classe.

Construtor de classe

O construtor de classe deve invocar o método de construtor para a classe pai, além de tudo o que ele faz que seja específico para sua classe. O exemplo a seguir é um método de construtor típico:

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

O método usa os parâmetros a seguir, que ele passa diretamente para o método construtor CUnknown .

  • tszName especifica um nome para o componente.
  • pUnk é um ponteiro para o IUnknown agregador.
  • pHr é um ponteiro para um valor HRESULT, indicando o êxito ou a falha do método.

Resumo

O exemplo a seguir mostra uma classe derivada que dá suporte a IUnknown e a uma interface hipotética chamada 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.
};

Este exemplo ilustra os seguintes pontos:

  • A classe CUnknown implementa a interface IUnknown . O novo componente herda do CUnknown e de todas as interfaces compatíveis com o componente. O componente pode derivar em vez de outra classe base que herda de CUnknown.
  • A macro DECLARE_IUNKNOWN declara os métodos IUnknown delegantes como métodos embutidos.
  • A classe CUnknown fornece a implementação para INonDelegatingUnknown.
  • Para dar suporte a uma interface diferente de IUnknown, a classe derivada deve substituir o método NonDelegatingQueryInterface e testar a IID da nova interface.
  • O construtor de classe invoca o método de construtor para CUnknown.

A próxima etapa na gravação de um filtro é habilitar um aplicativo para criar novas instâncias do componente. Isso requer uma compreensão das DLLs e sua relação com fábricas de classes e métodos de construtor de classe. Para obter mais informações, consulte Como criar uma DLL de filtro do DirectShow.

Como implementar o IUnknown