Funzionamento di IUnknown
[La funzionalità associata a questa pagina, DirectShow, è una funzionalità legacy. È stata sostituita da MediaPlayer, IMFMediaEngine e Audio/Video Capture in Media Foundation. Queste funzionalità sono state ottimizzate per Windows 10 e Windows 11. Microsoft consiglia vivamente che il nuovo codice usi MediaPlayer, IMFMediaEngine e Audio/Video Capture in Media Foundation invece di DirectShow, quando possibile. Microsoft suggerisce che il codice esistente che usa le API legacy venga riscritto per usare le nuove API, se possibile.
I metodi in IUnknown consentono a un'applicazione di eseguire query per le interfacce nel componente e gestire il conteggio dei riferimenti del componente.
Conteggio riferimenti
Il conteggio dei riferimenti è una variabile interna, incrementata nel metodo AddRef e decrementata nel metodo Release . Le classi di base gestiscono il conteggio dei riferimenti e sincronizzano l'accesso al conteggio dei riferimenti tra più thread.
Query di interfaccia
Anche l'esecuzione di query per un'interfaccia è semplice. Il chiamante passa due parametri: un identificatore di interfaccia (IID) e l'indirizzo di un puntatore. Se il componente supporta l'interfaccia richiesta, imposta il puntatore sull'interfaccia , incrementa il proprio conteggio dei riferimenti e restituisce S_OK. In caso contrario, imposta il puntatore su NULL e restituisce E_NOINTERFACE. Lo pseudocodice seguente mostra la struttura generale del metodo QueryInterface . L'aggregazione dei componenti, descritta nella sezione successiva, introduce alcune complessità aggiuntive.
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
L'unica differenza tra il metodo QueryInterface di un componente e il metodo QueryInterface di un altro è l'elenco di ID DI cui ogni componente esegue il test. Per ogni interfaccia supportata dal componente, il componente deve testare l'IID di tale interfaccia.
Aggregazione e delega
L'aggregazione dei componenti deve essere trasparente per il chiamante. Pertanto, l'aggregazione deve esporre una singola interfaccia IUnknown , con il componente aggregato che rinvia all'implementazione del componente esterno. In caso contrario, il chiamante visualizzerà due interfacce IUnknown diverse nella stessa aggregazione. Se il componente non è aggregato, usa la propria implementazione.
Per supportare questo comportamento, il componente deve aggiungere un livello di riferimento indiretto. Un delegato IUnknown delega il lavoro alla posizione appropriata: al componente esterno, se presente, o alla versione interna del componente. Un oggetto IUnknown nondelegante esegue il lavoro, come descritto nella sezione precedente.
La versione di delega è pubblica e mantiene il nome IUnknown. La versione nondelegating viene rinominata INonDelegatingUnknown. Questo nome non fa parte della specifica COM, perché non è un'interfaccia pubblica.
Quando il client crea un'istanza del componente, chiama il metodo IClassFactory::CreateInstance . Un parametro è un puntatore all'interfaccia IUnknown del componente di aggregazione oppure NULL se la nuova istanza non è aggregata. Il componente usa questo parametro per archiviare una variabile membro che indica l'interfaccia IUnknown da usare, come illustrato nell'esempio seguente:
CMyComponent::CMyComponent(IUnknown *pOuterUnkown)
{
if (pOuterUnknown == NULL)
m_pUnknown = (IUnknown *)(INonDelegatingUnknown *)this;
else
m_pUnknown = pOuterUnknown;
[ ... more constructor code ... ]
}
Ogni metodo nella delega di IUnknown chiama la controparte non delegata, come illustrato nell'esempio seguente:
HRESULT QueryInterface(REFIID iid, void **ppv)
{
return m_pUnknown->QueryInterface(iid, ppv);
}
Per natura della delega, i metodi di delega hanno un aspetto identico in ogni componente. Cambiano solo le versioni nondeleganti.
Argomenti correlati