Condividi tramite


QueryInterface: Spostamento in un oggetto

Dopo aver ottenuto un puntatore iniziale a un'interfaccia su un oggetto, COM ha un meccanismo molto semplice per scoprire se l'oggetto supporta un'altra interfaccia specifica e, in tal caso, per ottenere un puntatore a esso. Per informazioni sul recupero di un puntatore iniziale a un'interfaccia in un oggetto, vedere Recupero di un puntatore a un oggetto. Questo meccanismo è il metodo QueryInterface dell'interfaccia IUnknown. Se l'oggetto supporta l'interfaccia richiesta, il metodo deve restituire un puntatore a tale interfaccia. Ciò consente a un oggetto di spostarsi liberamente tra le interfacce supportate da un oggetto. QueryInterface separa la richiesta "Si supporta un determinato contratto?" dall'uso ad alte prestazioni di tale contratto una volta che i negoziati hanno avuto esito positivo.

Quando un client ottiene inizialmente l'accesso a un oggetto, tale client riceverà almeno un puntatore di interfaccia IUnknown, tramite cui può controllare la durata dell'oggetto, notificandogli quando ha terminato di utilizzarlo e invocando QueryInterface. Il client è programmato per chiedere a ogni oggetto che riesce a eseguire alcune operazioni, ma l'interfaccia IUnknown non ha funzioni per tali operazioni. Queste operazioni vengono invece espresse tramite altre interfacce. Il client è quindi programmato per negoziare con gli oggetti per tali interfacce. In particolare, il client chiamerà QueryInterface per chiedere a un oggetto un'interfaccia tramite cui il client può richiamare le operazioni desiderate.

Poiché l'oggetto implementa QueryInterface, può accettare o rifiutare la richiesta. Se l'oggetto accetta la richiesta del client, QueryInterface restituisce un nuovo puntatore all'interfaccia richiesta al client. Tramite tale puntatore di interfaccia, il client ha accesso ai metodi di tale interfaccia. Se, invece, l'oggetto rifiuta la richiesta del client, QueryInterface restituisce un puntatore Null, un errore, e il client non dispone di un puntatore attraverso il quale chiamare le funzioni desiderate. In questo caso, il cliente deve gestire correttamente tale possibilità. Si supponga, ad esempio, che un client disponga di un puntatore all'interfaccia A su un oggetto e richieda interfacce B e C. Si supponga anche che l'oggetto supporti l'interfaccia B ma non supporti l'interfaccia C. Il risultato è che l'oggetto restituisce un puntatore a B e segnala che C non è supportato.

Un punto chiave è che quando un oggetto rifiuta una chiamata a QueryInterface, è impossibile che il client richieda all'oggetto di eseguire le operazioni espresse tramite l'interfaccia richiesta. Un client deve avere un puntatore all'interfaccia per richiamare i metodi in tale interfaccia. Se l'oggetto rifiuta di fornire il puntatore richiesto, il client deve essere preparato a farne a meno, non effettuando l'operazione che intendeva fare con tale oggetto o tentando di eseguire il fallback su un'altra, forse meno potente, interfaccia. Questa funzionalità di funzionalità COM funziona bene rispetto ad altri sistemi orientati agli oggetti in cui non è possibile sapere se una funzione funzionerà fino a quando non si chiama tale funzione e, anche allora, la gestione degli errori è incerta. QueryInterface fornisce un modo affidabile e coerente per sapere se un oggetto supporta un'interfaccia prima di tentare di chiamare i relativi metodi.

Il metodo QueryInterface fornisce anche un modo affidabile e affidabile per un oggetto per indicare che non supporta un determinato contratto. Ciò significa che, se in una chiamata a QueryInterface uno chiede a un oggetto "vecchio" se supporta un'interfaccia "nuova" (una, ad esempio, che è stata inventata dopo la spedizione dell'oggetto precedente), l'oggetto precedente sarà affidabile, senza causare un arresto anomalo, rispondere "no". La tecnologia che supporta questo è l'algoritmo in base al quale vengono allocati ID. Anche se questo può sembrare un piccolo punto, è estremamente importante per l'architettura complessiva del sistema e la possibilità di interrogare gli elementi legacy su nuove funzionalità è, sorprendentemente, una funzionalità non presente nella maggior parte delle altre architetture di oggetti.

Utilizzo e implementazione di IUnknown