Implémentation d'IAccessibleEx pour les fournisseurs
Cette section explique comment ajouter les capacités du fournisseur Microsoft UI Automation à un serveur Microsoft Active Accessibility en implémentant l'interface IAccessibleEx.
Avant d'implémenter IAccessibleEx, tenez compte des exigences suivantes :
- La hiérarchie d'objets accessibles de Microsoft Active Accessibility doit être propre. IAccessibleEx ne peut pas corriger les problèmes liés aux hiérarchies d'objets accessibles existantes. Tout problème lié à la structure du modèle d'objet doit être corrigé lors de l'implémentation de Microsoft Active Accessibility avant celle d'IAccessibleEx.
- L'implémentation d'IAccessibleEx doit être conforme à la fois à la spécification de Microsoft Active Accessibility et à la spécification d'UI Automation. Les outils sont disponibles pour valider la conformité dans les deux spécifications. Pour en savoir plus, reportez-vous à Test d'accessibilité et à Infrastructure d'automatisation des tests UI Automation Verify (UIA Verify).
Pour implémenter IAccessibleEx, procédez comme suit :
- Implémentez IServiceProvider sur l'objet accessible de sorte que l'interface IAccessibleEx se trouve sur cet objet ou sur un objet séparé.
- implémentez IAccessibleEx sur l'objet accessible.
- Créez des objets accessibles pour tous les éléments enfants de Microsoft Active Accessibility, qui, dans Microsoft Active Accessibility, sont représentés par l'interface IAccessible de l'objet parent (par exemple, les éléments de liste). Implémentez IAccessibleEx sur ces objets.
- Implémentez IRawElementProviderSimple sur tous les objets accessibles.
- Implémentez les interfaces de modèle de contrôle appropriées sur les objets accessibles.
Implémentation de l'interface IServiceProvider
L'implémentation d'IAccessibleEx pour un contrôle peut résider dans un objet distinct. Par conséquent, les applications clientes ne peuvent pas compter sur QueryInterface pour obtenir cette interface. Les clients devraient plutôt émettre un appel IServiceProvider::QueryService. Dans l'exemple d'implémentation suivant de cette méthode, il est supposé que IAccessibleEx n'est pas implémenté sur un objet distinct. Par conséquent, la méthode émet des appels simplement via 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;
}
};
Implémentation de l'interface IAccessibleEx
Dans Microsoft Active Accessibility, un élément d'interface utilisateur est toujours identifié par une interface IAccessible et un ID enfant. Une instance unique d'IAccessible peut représenter plusieurs éléments d'interface utilisateur.
Chaque instance IAccessibleEx ne représente qu'un seul élément d'interface utilisateur. Par conséquent, chaque couple IAccessible et ID enfant doit être mappé à une seule instance IAccessibleEx. IAccessibleEx inclut deux méthodes de gestion de ce mappage :
- GetObjectForChild : récupère l'interface IAccessibleEx pour l'enfant spécifié. Cette méthode renvoie NULL si l'implémentation d'IAccessibleEx ne reconnaît pas l'ID enfant spécifié, n'a pas d'IAccessibleEx pour l'enfant spécifié ou représente un élément enfant.
- GetIAccessiblePair : récupère l'interface IAccessible et l'ID enfant pour l'élément IAccessibleEx. Pour les implémentations IAccessible qui n'utilisent pas d'ID enfant, cette méthode récupère l'objet IAccessible et CHILDID_SELF correspondants.
L'exemple suivant présente l'implémentation des méthodes GetObjectForChild et GetIAccessiblePair pour un élément dans un mode Liste personnalisé. Ces méthodes permettent à UI Automation d'afficher sur la carte le couple IAccessible et ID enfant avec une instance IAccessibleEx correspondante.
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;
}
}
Si l'implémentation d'un objet accessible n'utilise pas d'ID enfant, les méthodes peuvent toujours être implémentées comme le présente l'extrait de code suivant.
// 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;
}
Implémenter l'interface IRawElementProviderSimple
Les serveurs utilisent IRawElementProviderSimple pour exposer des informations sur les propriétés d'UI Automation et les modèles de contrôle. IRawElementProviderSimple comprend les méthodes suivantes :
- GetPatternProvider : cette méthode est utilisée pour exposer des interfaces de modèle de contrôle. Elle renvoie un objet qui prend en charge le modèle de contrôle spécifié, ou NULL si le modèle de contrôle n'est pas pris en charge.
- GetPropertyValue : cette méthode est utilisée pour exposer les valeurs des propriétés d'UI Automation.
- HostRawElementProvider : cette méthode n'est pas utilisée avec les implémentations d'IAccessibleEx.
- ProviderOptions : cette méthode n'est pas utilisée avec les implémentations d'IAccessibleEx.
Un serveur IAccessibleEx expose des modèles de contrôle en implémentant IRawElementProviderSimple::GetPatternProvider. Cette méthode adopte un paramètre entier qui spécifie le modèle de contrôle. Le serveur retourne NULL si le modèle n'est pas pris en charge. Si l'interface de modèle de contrôle est prise en charge, les serveurs retournent un IUnknown et le client émet ensuite des appels QueryInterface pour obtenir le modèle de contrôle approprié.
Un serveur IAccessibleEx peut prendre en charge les propriétés UI Automation (comme LabeledBy et IsRequiredForForm) en implémentant IRawElementProviderSimple::GetPropertyValue et en fournissant un entier PROPERTYID identifiant la propriété comme paramètre. Cette technique ne s'applique qu'aux propriétés UI Automation qui ne sont pas incluses dans l'interface d'un modèle de contrôle. Les propriétés associées à une interface de modèle de contrôle sont exposées via la méthode d'interface du modèle de contrôle. Par exemple, la propriété IsSelected du modèle de contrôle SelectionItem serait exposée avec ISelectionItemProvider::get_IsSelected.