Implementazione di IAccessibleEx per i provider
Questa sezione illustra come aggiungere funzionalità del provider di automazione interfaccia utente Microsoft a un server microsoft Active Accessibility implementando l'interfaccia IAccessibleEx.
Prima di implementare IAccessibleEx, considerare i requisiti seguenti:
- La gerarchia di oggetti accessibili di Microsoft Active Accessibility di base deve essere pulita. IAccessibleEx non è in grado di risolvere i problemi relativi alle gerarchie di oggetti accessibili esistenti. Eventuali problemi relativi alla struttura del modello a oggetti devono essere corretti nell'implementazione di Microsoft Active Accessibility prima di implementare IAccessibleEx.
- L'implementazione IAccessibleEx deve essere conforme sia alla specifica Microsoft Active Accessibility che alla specifica di automazione interfaccia utente. Gli strumenti sono disponibili per convalidare la conformità in entrambe le specifiche. Per ulteriori informazioni, vedere Testing per l'accessibilità e UI Automation Verify (UIA Verify) Test Automation Framework.
L'implementazione di IAccessibleEx richiede questi passaggi principali:
- Implementare IServiceProvider nell'oggetto accessibile in modo che l'interfacciaIAccessibleExsia disponibile in questo oggetto o in un oggetto separato.
- Implementare IAccessibleEx nell'oggetto accessibile.
- Creare oggetti accessibili per tutti gli elementi figlio di Microsoft Active Accessibility, che in Microsoft Active Accessibility sono rappresentati dall'interfaccia IAccessible nell'oggetto padre, ad esempio elementi elenco. Implementare IAccessibleEx su questi oggetti.
- Implementare IRawElementProviderSimple in tutti gli oggetti accessibili.
- Implementare le interfacce appropriate del pattern di controllo sugli oggetti accessibili.
Implementazione dell'interfaccia IServiceProvider
Poiché l'implementazione di IAccessibleEx per un controllo può risiedere in un oggetto separato, le applicazioni client non possono basarsi su QueryInterface per ottenere questa interfaccia. I client devono invece chiamare IServiceProvider::QueryService. Nell'implementazione di esempio seguente di questo metodo si presuppone che IAccessibleEx non sia implementato in un oggetto separato; pertanto il metodo chiama semplicemente tramite per 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;
}
};
Implementazione dell'interfaccia IAccessibleEx
In Microsoft Active Accessibility, un elemento dell'interfaccia utente viene sempre identificato da un'interfaccia IAccessible e da un ID figlio. Una singola istanza di IAccessible può rappresentare più elementi dell'interfaccia utente.
Poiché ogni istanza di IAccessibleEx rappresenta solo un singolo elemento dell'interfaccia utente, è necessario eseguire il mapping di ogni coppia IAccessible e ID figlio a una singola istanza IAccessibleEx. IAccessibleEx include due metodi per gestire questo mapping:
- GetObjectForChild— recupera l'interfaccia IAccessibleEx per l'elemento figlio specificato. Questo metodo restituisce NULL se l'implementazione IAccessibleEx non riconosce l'ID figlio specificato, non dispone di un IAccessibleEx per l'elemento figlio specificato o rappresenta un elemento figlio.
- GetIAccessiblePair— recupera l'interfaccia IAccessible e l'ID figlio per l'elemento IAccessibleEx. Per implementazioni di IAccessible che non usano un ID figlio, questo metodo recupera l'oggetto IAccessible corrispondente e CHILDID_SELF.
Nell'esempio seguente viene illustrata l'implementazione dei metodi getObjectForChilde GetIAccessiblePair per un elemento in una visualizzazione elenco personalizzata. I metodi consentono ad Automazione Interfaccia Utente di mappare la coppia IAccessible e l'ID figlio a un'istanza IAccessibleEx corrispondente.
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 un'implementazione di un oggetto accessibile non usa un ID figlio, i metodi possono comunque essere implementati come illustrato nel frammento di codice seguente.
// 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;
}
Implementare l'interfaccia IRawElementProviderSimple
I server usano IRawElementProviderSimple per esporre informazioni sulle proprietà di automazione interfaccia utente e sui pattern di controllo. IRawElementProviderSimple include i metodi seguenti:
- GetPatternProvider: questo metodo viene usato per esporre le interfacce del pattern di controllo. Restituisce un oggetto che supporta il pattern di controllo specificato oppure NULL se il pattern di controllo non è supportato.
- GetPropertyValue: questo metodo viene usato per esporre i valori delle proprietà di automazione interfaccia utente.
- HostRawElementProvider— questo metodo non viene usato con le implementazioni IAccessibleEx.
- ProviderOptions: questo metodo non viene usato con le implementazioni diIAccessibleEx.
Un serverIAccessibleExespone modelli di controllo implementando IRawElementProviderSimple::GetPatternProvider. Questo metodo accetta un parametro integer che specifica il pattern di controllo. Il server restituisce NULL se il modello non è supportato. Se l'interfaccia del pattern di controllo è supportata, i server restituiscono unIUnknowne il client chiama QueryInterface per ottenere il pattern di controllo appropriato.
Un serverIAccessibleExpuò supportare le proprietà di automazione interfaccia utente (ad esempio LabeledBy e IsRequiredForForm) implementando IRawElementProviderSimple::GetPropertyValue e fornendo un PROPERTYID integer che identifica la proprietà come parametro. Questa tecnica si applica solo alle proprietà dell'Automazione dell'interfaccia utente che non sono incluse in un'interfaccia modello di controllo. Le proprietà associate a un'interfaccia del modello di controllo vengono esposte tramite il metodo dell'interfaccia del modello di controllo. Ad esempio, la proprietà IsSelected dal pattern di controllo SelectionItem verrà esposta con ISelectionItemProvider::get_IsSelected.