Partilhar via


Usando CUnknown

[O recurso associado a esta página, DirectShow, é um recurso herdado. Foi substituído por MediaPlayer, IMFMediaEnginee Audio/Video Capture in Media Foundation. Esses recursos foram otimizados para Windows 10 e Windows 11. A Microsoft recomenda vivamente que o novo código utilize MediaPlayer, IMFMediaEngine e Captura de Áudio/Vídeo no Media Foundation em vez de DirectShow, quando possível. A Microsoft sugere que o código existente que usa as APIs herdadas seja reescrito para usar as novas APIs, se possível.]

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

INonDelegatingUnknown

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 alteração. Lembre-se de que CUnknown se remove quando a contagem de referência cai para zero. Por outro lado, deves sobrescrever CUnknown::NonDelegatingQueryInterface, porque o método na classe base retorna E_NOINTERFACE se receber qualquer IID diferente de IID_IUnknown. Em sua classe derivada, teste os IIDs das interfaces que você suporta, 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 utilitária GetInterface (consulte COM Helper Functions) define o ponteiro, incrementa a contagem de referência de forma segura para subprocessos 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 em vez disso. Isso permite que você suporte todas as interfaces que a classe pai suporta.

IUnknown

Como mencionado anteriormente, a versão delegada de IUnknown é a mesma para todos os componentes, porque não faz nada mais do que invocar a instância correta da versão não delegante. Por conveniência, o arquivo de cabeçalho Combase.h contém uma macro, DECLARE_IUNKNOWN, que declara os três métodos de delegação 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 este componente. Para um componente agregado, o proprietário é o componente externo. Caso contrário, o componente é dono de si mesmo. Inclua a macro DECLARE_IUNKNOWN na seção pública da sua definição de classe.

Class Construtor

Seu construtor de classe deve invocar o método de construtor para a classe pai, além de qualquer coisa que ele faça 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 seguintes parâmetros, que ele passa diretamente para o CUnknown método construtor.

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

Resumo

O exemplo a seguir mostra uma classe derivada que suporta IUnknown e 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 o IUnknown interface. O novo componente herda de CUnknown e de todas as interfaces que o componente suporta. Em vez disso, o componente poderia derivar de outra classe base que herda de CUnknown.
  • A macro DECLARE_IUNKNOWN declara os métodos dedelegadosIUnknown como métodos embutidos.
  • A classe CUnknown fornece a implementação para INonDelegatingUnknown .
  • Para suportar uma interface diferente de IUnknown, a classe derivada deve sobrescrever o método NonDelegatingQueryInterface e testar o IID da nova interface.
  • O construtor de classe invoca o método construtor para CUnknown.

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

Como implementar IUnknown