Funzionamento di IUnknown
[La funzionalità associata a questa pagina, DirectShow, è una funzionalità legacy. È stata sostituita da MediaPlayer, IMFMediaEnginee Acquisizione audio/video in Media Foundation. Queste funzionalità sono state ottimizzate per Windows 10 e Windows 11. Microsoft consiglia vivamente di usare un nuovo codice MediaPlayer, IMFMediaEngine e Acquisizione audio/video in Media Foundation anziché 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 di gestire il conteggio dei riferimenti del componente.
Conteggio dei 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.
Interrogazioni dell'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 illustra la struttura generale del metodo QueryInterface. L'aggregazione dei componenti, descritta nella sezione successiva, presenta 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 IIDs che ogni componente testa. 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 delegando IUnknown delega il lavoro alla posizione appropriata: al componente esterno, se presente o alla versione interna del componente. Un non delegante IUnknown fa 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 o NULL se la nuova istanza non è aggregata. Il componente usa questo parametro per archiviare una variabile membro che indica quale 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 IUnknown chiama la controparte nondelegante, 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. Solo le versioni non deleganti cambiano.
Argomenti correlati