Implementando IAccessibleEx para provedores
Esta seção explica como adicionar recursos do provedor de Automação da Interface do Usuário da Microsoft a um servidor Microsoft Active Accessibility implementando a interface IAccessibleEx.
Antes de implementar IAccessibleEx, considere os seguintes requisitos:
- A hierarquia de objetos acessíveis do Microsoft Ative Accessibility de linha de base deve estar limpa. IAccessibleEx não pode corrigir problemas com hierarquias de objetos acessíveis existentes. Quaisquer problemas com a estrutura do modelo de objeto devem ser corrigidos na implementação do Microsoft Ative Accessibility antes de implementar IAccessibleEx.
- A implementação IAccessibleEx deve estar em conformidade com a especificação Microsoft Ative Accessibility e a especificação UI Automation. Estão disponíveis ferramentas para validar a conformidade de acordo com ambas as especificações. Para obter mais informações, consulte Teste de acessibilidade e UI Automation Verify (UIA Verify) Test Automation Framework.
A implementação IAccessibleEx requer estas etapas principais:
- Implemente IServiceProvider no objeto acessível para que o interface IAccessibleEx possa ser encontrado neste ou em um objeto separado.
- Implemente IAccessibleEx no objeto acessível.
- Crie objetos acessíveis para qualquer item filho do Microsoft Active Accessibility, que no Microsoft Active Accessibility são representados pela interface IAccessible no objeto pai (por exemplo, itens de lista). Implemente IAccessibleEx nesses objetos.
- Implemente IRawElementProviderSimple em todos os objetos acessíveis.
- Implemente as interfaces de padrão de controle apropriadas nos objetos acessíveis.
Implementando a interface IServiceProvider
Como a implementação de IAccessibleEx para um controle pode residir em um objeto separado, os aplicativos cliente não podem confiar em QueryInterface para obter essa interface. Em vez disso, espera-se que os clientes chamem IServiceProvider::QueryService. Na implementação de exemplo deste método a seguir, supõe-se que IAccessibleEx não é implementado em um objeto separado; portanto, o método simplesmente faz uma chamada a QueryInterface.
HRESULT CListboxAccessibleObject::QueryService(REFGUID guidService, REFIID riid, LPVOID *ppvObject)
{
if (ppvObject == NULL)
{
return E_INVALIDARG;
}
*ppvObject = NULL;
if (guidService == __uuidof(IAccessibleEx))
{
return QueryInterface(riid, ppvObject);
}
else
{
return E_NOINTERFACE;
}
};
Implementando a interface IAccessibleEx
No Microsoft Ative Accessibility, um elemento de interface do utilizador é sempre identificado por uma interface IAccessible e uma ID de filho. Uma única instância de IAccessible pode representar vários elementos da interface do usuário.
Como cada instância de IAccessibleEx representa apenas um único elemento da interface do usuário, cada par IAccessible e ID filho deve ser mapeado para uma única instância IAccessibleEx. IAccessibleEx inclui dois métodos para lidar com esse mapeamento:
- GetObjectForChild—Recupera o interface IAccessibleEx para o filho especificado. Esse método retorna NULL se a implementação IAccessibleEx não reconhecer a ID filho especificada, não tiver um IAccessibleEx para o filho especificado ou representar um elemento filho.
- GetIAccessiblePair—Recupera a interfaceIAccessiblee a ID filho para o elemento IAccessibleEx. Para implementações IAccessible que não usam uma ID filho, esse método recupera o objeto IAccessible correspondente e CHILDID_SELF.
O exemplo a seguir mostra a implementação dos métodos GetObjectForChild e GetIAccessiblePair para um item num modo de lista personalizado. Os métodos permitem que o UI Automation mapeie o par IAccessible e ID filho para uma instância de IAccessibleEx correspondente.
HRESULT CListboxAccessibleObject::GetObjectForChild(
long idChild, IAccessibleEx **ppRetVal)
{
VARIANT vChild;
vChild.vt = VT_I4;
vChild.lVal = idChild;
HRESULT hr = ValidateChildId(vChild);
if (FAILED(hr))
{
return E_INVALIDARG;
}
// List item accessible objects are stored as an array of
// pointers; for the purpose of this example it is assumed that
// the list contents will not change. Accessible objects are
// created only when needed.
if (itemProviders[idChild - 1] == NULL)
{
// Create an object that supports UI Automation and
// IAccessibleEx for the item.
itemProviders[idChild - 1] =
new CListItemAccessibleObject(idChild,
g_pListboxControl);
if (itemProviders[idChild - 1] == NULL)
{
return E_OUTOFMEMORY;
}
}
IAccessibleEx* pAccEx = static_cast<IAccessibleEx*>
(itemProviders[idChild - 1]);
if (pAccEx != NULL)
{
pAccEx->AddRef();
}
*ppRetVal = pAccEx;
return S_OK;
}
HRESULT CListItemAccessibleObject::GetIAccessiblePair(
IAccessible **ppAcc, long *pidChild)
{
if (ppAcc == NULL || pidChild == NULL)
{
return E_INVALIDARG;
}
CListboxAccessibleObject* pParent =
m_control->GetAccessibleObject();
HRESULT hr = pParent->QueryInterface(
__uuidof(IAccessible), (void**)ppAcc);
if (FAILED(hr))
{
*pidChild = 0;
return E_NOINTERFACE;
}
*pidChild = m_childID;
return S_OK;
}
}
Se uma implementação de objeto acessível não usar uma ID de filho, os métodos ainda poderão ser implementados conforme mostrado no trecho de código a seguir.
// This sample implements IAccessibleEx on the same object; it could use a tear-off
// or inner object instead.
class MyAccessibleImpl: public IAccessible,
public IAccessibleEx,
public IRawElementProviderSimple
{
public:
...
HRESULT STDMETHODCALLTYPE GetObjectForChild( long idChild, IAccessibleEx **ppRetVal )
{
// This implementation does not support child IDs.
*ppRetVal = NULL;
return S_OK;
}
HRESULT STDMETHODCALLTYPE GetIAccessiblePair( IAccessible ** ppAcc, long * pidChild )
{
// This implementation assumes that IAccessibleEx is implemented on same object as
// IAccessible.
*ppAcc = static_cast<IAccessible *>(this);
(*ppAcc)->AddRef();
*pidChild = CHILDID_SELF;
return S_OK;
}
Implementar a interface IRawElementProviderSimple
Os servidores usam IRawElementProviderSimple para expor informações sobre propriedades de automação da interface do usuário e padrões de controle. IRawElementProviderSimple inclui os seguintes métodos:
- GetPatternProvider—Este método é usado para expor interfaces de padrão de controle. Ele retorna um objeto que suporta o padrão de controle especificado ou NULL se o padrão de controle não for suportado.
- GetPropertyValue—Este método é usado para expor valores de propriedade de UI Automation.
- HostRawElementProvider—Este método não é usado com implementações IAccessibleEx.
- ProviderOptions—Este método não é usado com implementações de IAccessibleEx.
Um servidor IAccessibleEx expõe padrões de controle implementando IRawElementProviderSimple::GetPatternProvider. Esse método usa um parâmetro inteiro que especifica o padrão de controle. O servidor retorna NULL se o padrão não for suportado. Se a interface de padrão de controle for suportada, os servidores retornarão um IUnknown e o cliente chamará QueryInterface para obter o padrão de controle apropriado.
Um servidorIAccessibleExpode oferecer suporte a propriedades de automação da interface do usuário (como LabeledBy e IsRequiredForForm) implementando IRawElementProviderSimple::GetPropertyValue e fornecendo um inteiro PROPERTYID identificando a propriedade como um parâmetro. Essa técnica se aplica somente às propriedades de automação da interface do usuário que não estão incluídas em uma interface de padrão de controle. As propriedades associadas a uma interface de padrão de controle são expostas por meio do método de interface de padrão de controle. Por exemplo, a propriedade IsSelected do padrão de controle SelectionItem seria exposta com ISelectionItemProvider::get_IsSelected.