Richiesta di un oggetto per un'interfaccia
È stato visto in precedenza che un oggetto può implementare più di un'interfaccia. L'oggetto Common Item Dialog è un esempio reale di questo. Per supportare gli usi più tipici, l'oggetto implementa l'interfaccia IFileOpenDialog . Questa interfaccia definisce i metodi di base per visualizzare la finestra di dialogo e ottenere informazioni sul file selezionato. Per un uso più avanzato, tuttavia, l'oggetto implementa anche un'interfaccia denominata IFileDialogCustomize. Un programma può usare questa interfaccia per personalizzare l'aspetto e il comportamento della finestra di dialogo aggiungendo nuovi controlli dell'interfaccia utente.
Tenere presente che ogni interfaccia COM deve ereditare, direttamente o indirettamente, dall'interfaccia IUnknown . Il diagramma seguente mostra l'ereditarietà dell'oggetto Common Item Dialog.
Come si può vedere dal diagramma, il predecessore diretto di IFileOpenDialog è l'interfaccia IFileDialog , che a sua volta eredita IModalWindow. Man mano che si passa alla catena di ereditarietà da IFileOpenDialog a IModalWindow, le interfacce definiscono funzionalità finestra sempre più generalizzate. Infine, l'interfaccia IModalWindow eredita IUnknown. L'oggetto Common Item Dialog implementa anche IFileDialogCustomize, che esiste in una catena di ereditarietà separata.
Si supponga ora di avere un puntatore all'interfaccia IFileOpenDialog . Come si ottiene un puntatore all'interfaccia IFileDialogCustomize ?
Semplicemente eseguire il cast del puntatore IFileOpenDialog a un puntatore IFileDialogCustomize non funzionerà. Non esiste un modo affidabile per "cross cast" in una gerarchia di ereditarietà, senza una forma di informazioni sui tipi di runtime (RTTI), che è una funzionalità altamente dipendente dal linguaggio.
L'approccio COM consiste nel chiedere all'oggetto di fornire un puntatore IFileDialogCustomize , usando la prima interfaccia come canale nell'oggetto. Questa operazione viene eseguita chiamando il metodo IUnknown::QueryInterface dal primo puntatore dell'interfaccia. È possibile pensare a QueryInterface come versione indipendente dal linguaggio della parola chiave dynamic_cast in C++.
Il metodo QueryInterface ha la firma seguente:
HRESULT QueryInterface(REFIID riid, void **ppvObject);
In base a ciò che si conosce già su CoCreateInstance, potrebbe essere possibile indovinare il funzionamento di QueryInterface .
- Il parametro riid è il GUID che identifica l'interfaccia richiesta. Il tipo di dati REFIID è un typedef per
const GUID&
. Si noti che l'identificatore di classe (CLSID) non è obbligatorio, perché l'oggetto è già stato creato. È necessario solo l'identificatore dell'interfaccia. - Il parametro ppvObject riceve un puntatore all'interfaccia. Il tipo di dati di questo parametro è void**, per lo stesso motivo per cui CoCreateInstance usa questo tipo di dati: QueryInterface può essere usato per eseguire query per qualsiasi interfaccia COM, pertanto il parametro non può essere fortemente tipizzato.
Ecco come chiamare QueryInterface per ottenere un puntatore IFileDialogCustomize :
hr = pFileOpen->QueryInterface(IID_IFileDialogCustomize,
reinterpret_cast<void**>(&pCustom));
if (SUCCEEDED(hr))
{
// Use the interface. (Not shown.)
// ...
pCustom->Release();
}
else
{
// Handle the error.
}
Come sempre, controllare il valore restituito HRESULT , nel caso in cui il metodo ha esito negativo. Se il metodo ha esito positivo, è necessario chiamare Release quando si usa il puntatore, come descritto in Gestione della durata di un oggetto.
Prossima
Allocazione della memoria in COM