Solicitando um objeto para uma interface
Vimos anteriormente que um objeto pode implementar mais de uma interface. O objeto Common Item Dialog é um exemplo real disso. Para dar suporte aos usos mais típicos, o objeto implementa a interface IFileOpenDialog . Essa interface define métodos básicos para exibir a caixa de diálogo e obter informações sobre o arquivo selecionado. No entanto, para uso mais avançado, o objeto também implementa uma interface chamada IFileDialogCustomize. Um programa pode usar essa interface para personalizar a aparência e o comportamento da caixa de diálogo, adicionando novos controles de interface do usuário.
Lembre-se de que cada interface COM deve herdar, direta ou indiretamente, da interface IUnknown . O diagrama a seguir mostra a herança do objeto Common Item Dialog.
Como você pode ver no diagrama, o ancestral direto de IFileOpenDialog é a interface IFileDialog , que por sua vez herda IModalWindow. Conforme você sobe a cadeia de herança de IFileOpenDialog para IModalWindow, as interfaces definem a funcionalidade de janela cada vez mais generalizada. Por fim, a interface IModalWindow herda IUnknown. O objeto Common Item Dialog também implementa IFileDialogCustomize, que existe em uma cadeia de herança separada.
Agora suponha que você tenha um ponteiro para a interface IFileOpenDialog . Como você obteria um ponteiro para a interface IFileDialogCustomize ?
Simplesmente converter o ponteiro IFileOpenDialog em um ponteiro IFileDialogCustomize não funcionará. Não há uma maneira confiável de "conversão cruzada" em uma hierarquia de herança, sem alguma forma de RTTI (informações de tipo de tempo de execução), que é um recurso altamente dependente de idioma.
A abordagem COM é solicitar que o objeto forneça um ponteiro IFileDialogCustomize , usando a primeira interface como um canal para o objeto . Isso é feito chamando o método IUnknown::QueryInterface do primeiro ponteiro de interface. Você pode pensar em QueryInterface como uma versão independente da linguagem do dynamic_cast palavra-chave no C++.
O método QueryInterface tem a seguinte assinatura:
HRESULT QueryInterface(REFIID riid, void **ppvObject);
Com base no que você já sabe sobre CoCreateInstance, talvez seja possível adivinhar como o QueryInterface funciona.
- O parâmetro riid é o GUID que identifica a interface que você está solicitando. O tipo de dados REFIID é um typedef para
const GUID&
. Observe que o CLSID (identificador de classe) não é necessário, pois o objeto já foi criado. Somente o identificador de interface é necessário. - O parâmetro ppvObject recebe um ponteiro para a interface. O tipo de dados desse parâmetro é void**, pelo mesmo motivo pelo qual CoCreateInstance usa esse tipo de dados: QueryInterface pode ser usado para consultar qualquer interface COM, portanto, o parâmetro não pode ser fortemente tipado.
Veja como você chamaria QueryInterface para obter um ponteiro IFileDialogCustomize :
hr = pFileOpen->QueryInterface(IID_IFileDialogCustomize,
reinterpret_cast<void**>(&pCustom));
if (SUCCEEDED(hr))
{
// Use the interface. (Not shown.)
// ...
pCustom->Release();
}
else
{
// Handle the error.
}
Como sempre, marcar o valor retornado HRESULT, caso o método falhe. Se o método for bem-sucedido, você deverá chamar Release quando terminar de usar o ponteiro, conforme descrito em Gerenciando o tempo de vida de um objeto.
Avançar