Compartir a través de


Cómo funciona IUnknown

[La característica asociada a esta página, DirectShow, es una característica heredada. Se ha reemplazado por MediaPlayer, IMFMediaEngine y Captura de audio/vídeo en Media Foundation. Esas características se han optimizado para Windows 10 y Windows 11. Microsoft recomienda encarecidamente que el nuevo código use MediaPlayer, IMFMediaEngine y Audio/Video Capture en Media Foundation en lugar de DirectShow, siempre que sea posible. Microsoft sugiere que el código existente que usa las API heredadas se reescriba para usar las nuevas API si es posible.

Los métodos de IUnknown permiten a una aplicación consultar interfaces en el componente y administrar el recuento de referencias del componente.

Recuento de referencias

El recuento de referencias es una variable interna, incrementada en el método AddRef y disminuyeda en el método Release . Las clases base administran el recuento de referencias y sincronizan el acceso al recuento de referencias entre varios subprocesos.

Consultas de interfaz

La consulta de una interfaz también es sencilla. El autor de la llamada pasa dos parámetros: un identificador de interfaz (IID) y la dirección de un puntero. Si el componente admite la interfaz solicitada, establece el puntero a la interfaz, incrementa su propio recuento de referencias y devuelve S_OK. De lo contrario, establece el puntero en NULL y devuelve E_NOINTERFACE. El siguiente pseudocódigo muestra el esquema general del método QueryInterface . La agregación de componentes, descrita en la sección siguiente, presenta cierta complejidad adicional.

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

La única diferencia entre el método QueryInterface de un componente y el método QueryInterface de otro es la lista de IID que prueba cada componente. Para cada interfaz que admita el componente, el componente debe probar para el IID de esa interfaz.

Agregación y delegación

La agregación de componentes debe ser transparente para el autor de la llamada. Por lo tanto, el agregado debe exponer una única interfaz IUnknown , con el componente agregado que se aplaza a la implementación del componente externo. De lo contrario, el autor de la llamada vería dos interfaces IUnknown diferentes en el mismo agregado. Si el componente no se agrega, usa su propia implementación.

Para admitir este comportamiento, el componente debe agregar un nivel de direccionamiento indirecto. Una delegación de IUnknown delega el trabajo en el lugar adecuado: al componente externo, si hay uno o a la versión interna del componente. Un IUnknown no delegado realiza el trabajo, como se describe en la sección anterior.

La versión de delegación es pública y mantiene el nombre IUnknown. Se ha cambiado el nombre de INonDelegatingUnknown a la versión que no es de delegación. Este nombre no forma parte de la especificación COM, porque no es una interfaz pública.

Cuando el cliente crea una instancia del componente, llama al método IClassFactory::CreateInstance . Un parámetro es un puntero a la interfaz IUnknown del componente agregado o NULL si la nueva instancia no se agrega. El componente usa este parámetro para almacenar una variable miembro que indica la interfaz IUnknown que se va a usar, como se muestra en el ejemplo siguiente:

CMyComponent::CMyComponent(IUnknown *pOuterUnkown)
{
    if (pOuterUnknown == NULL)
        m_pUnknown = (IUnknown *)(INonDelegatingUnknown *)this;
    else
        m_pUnknown = pOuterUnknown;

    [ ... more constructor code ... ]
}

Cada método de la delegación de IUnknown llama a su homólogo no delegado, como se muestra en el ejemplo siguiente:

HRESULT QueryInterface(REFIID iid, void **ppv) 
{
    return m_pUnknown->QueryInterface(iid, ppv);
}

Por naturaleza de delegación, los métodos de delegación tienen un aspecto idéntico en todos los componentes. Solo cambian las versiones que no son de delegación.

Cómo implementar IUnknown