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.
Tópicos relacionados