Regole per l'implementazione di QueryInterface

Esistono tre regole principali che regolano l'implementazione del metodo IUnknown::QueryInterface in un oggetto COM:

  • Gli oggetti devono avere un'identità.
  • Il set di interfacce in un'istanza dell'oggetto deve essere statico.
  • Deve essere possibile eseguire query correttamente per qualsiasi interfaccia su un oggetto da qualsiasi altra interfaccia.

Gli oggetti devono avere un'identità

Per qualsiasi istanza dell'oggetto specificato, una chiamata a QueryInterface con IID_IUnknown deve restituire sempre lo stesso valore del puntatore fisico. In questo modo è possibile chiamare QueryInterface su due interfacce e confrontare i risultati per determinare se puntano alla stessa istanza di un oggetto.

Il set di interfacce in un'istanza dell'oggetto deve essere statico

Il set di interfacce accessibili in un oggetto tramite QueryInterface deve essere statico, non dinamico. In particolare, se QueryInterface restituisce S_OK per un id IID specificato, non deve mai restituire E_NOINTERFACE sulle chiamate successive sullo stesso oggetto; e se QueryInterface restituisce E_NOINTERFACE per un determinato IID, le chiamate successive per lo stesso IID sullo stesso oggetto non devono mai restituire S_OK.

Deve essere possibile eseguire una query per qualsiasi interfaccia in un oggetto da qualsiasi altra interfaccia

Ovvero, dato il codice seguente:

IA * pA = (some function returning an IA *); 
IB * pB = NULL; 
HRESULT   hr; 
hr = pA->QueryInterface(IID_IB, &pB); 
 

si applicano le regole seguenti:

  • Se si dispone di un puntatore a un'interfaccia in un oggetto, una chiamata simile alla seguente a QueryInterface per la stessa interfaccia deve avere esito positivo:

    pA->QueryInterface(IID_IA, ...) 
    
    
  • Se una chiamata a QueryInterface per un secondo puntatore di interfaccia ha esito positivo, deve essere eseguita anche una chiamata a QueryInterface da tale puntatore per la prima interfaccia. Se pB è stato ottenuto correttamente, è necessario che anche le operazioni seguenti abbiano esito positivo:

    pB->QueryInterface(IID_IA, ...) 
    
    
  • Qualsiasi interfaccia deve essere in grado di eseguire query per qualsiasi altra interfaccia in un oggetto . Se pB è stato ottenuto correttamente ed è stata eseguita correttamente una query per una terza interfaccia (IC) usando tale puntatore, è anche necessario essere in grado di eseguire query correttamente per ic usando il primo puntatore, pA. In questo caso, la sequenza seguente deve avere esito positivo:

    IC * pC = NULL; 
    hr = pB->QueryInterface(IID_IC, &pC); 
    pA->QueryInterface(IID_IC, ...) 
    
    

Le implementazioni dell'interfaccia devono mantenere un contatore di riferimenti puntatori in sospeso a tutte le interfacce di un determinato oggetto. È consigliabile utilizzare un intero senza segno per il contatore.

Se un client deve sapere che le risorse sono state liberate, deve usare un metodo in un'interfaccia nell'oggetto con semantica di livello superiore prima di chiamare IUnknown::Release.

Uso e implementazione di IUnknown