Partilhar via


Regras para implementar QueryInterface

Há três regras principais que regem a implementação do método IUnknown::QueryInterface em um objeto COM:

  • Os objetos devem ter identidade.
  • O conjunto de interfaces em uma instância de objeto deve ser estático.
  • Deve ser possível consultar com êxito qualquer interface em um objeto a partir de qualquer outra interface.

Os objetos devem ter identidade

Para qualquer instância de objeto específico, uma chamada para QueryInterface com IID_IUnknown deve sempre retornar o mesmo valor de ponteiro físico. Isso permite que você chame QueryInterface em quaisquer duas interfaces e compare os resultados para determinar se eles apontam para a mesma instância de um objeto.

O conjunto de interfaces em uma instância de objeto deve ser estático

O conjunto de interfaces acessíveis em um objeto por meio de QueryInterface deve ser estático, não dinâmico. Especificamente, se QueryInterface retornar S_OK para um determinado IID uma vez, ele nunca deverá retornar E_NOINTERFACE em chamadas subsequentes no mesmo objeto, e se QueryInterface retornar E_NOINTERFACE para um determinado IID, as chamadas subsequentes para o mesmo IID no mesmo objeto nunca deverão retornar S_OK.

Deve ser possível consultar com êxito qualquer interface em um objeto de qualquer outra interface

Ou seja, dado o seguinte código:

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

Aplicam-se as seguintes regras:

  • Se você tiver um ponteiro para uma interface em um objeto, uma chamada como a seguinte para QueryInterface para essa mesma interface deverá ser bem-sucedida:

    pA->QueryInterface(IID_IA, ...) 
    
    
  • Se uma chamada para QueryInterface para um segundo ponteiro de interface for bem-sucedida, uma chamada para QueryInterface desse ponteiro para a primeira interface também deverá ser bem-sucedida. Se pB foi obtido com sucesso, o seguinte também deve ter êxito:

    pB->QueryInterface(IID_IA, ...) 
    
    
  • Qualquer interface deve ser capaz de consultar qualquer outra interface em um objeto. Se pB foi obtido com êxito e você consulta com êxito para uma terceira interface (IC) usando esse ponteiro, você também deve ser capaz de consultar com êxito para IC usando o primeiro ponteiro, pA. Nesse caso, a seguinte sequência deve ser bem-sucedida:

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

As implementações de interface devem manter um contador de referências de ponteiro pendentes para todas as interfaces em um determinado objeto. Você deve usar um inteiro não assinado para o contador.

Se um cliente precisa saber que os recursos foram liberados, ele deve usar um método em alguma interface no objeto com semântica de nível superior antes de chamar IUnknown::Release.

Usando e implementando IUnknown