Implementazione di IAccessibleEx per i provider

Questa sezione illustra come aggiungere funzionalità del provider Di Microsoft Automazione interfaccia utente 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 Automazione interfaccia utente. Gli strumenti sono disponibili per convalidare la conformità in entrambe le specifiche. Per altre informazioni, vedere Testing for accessibility and Automazione interfaccia utente Verify (UIA Verify) Test Automation Framework (UIA Verify).

L'implementazione di IAccessibleEx richiede questi passaggi principali:

  • Implementare IServiceProvider nell'oggetto accessibile in modo che l'interfaccia IAccessibleEx sia 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 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;
    }
};      

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 IAccessibleEx rappresenta solo un singolo elemento dell'interfaccia utente, ogni coppia IAccessible e ID figlio deve essere mappata 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 oggetto 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 le implementazioni IAccessible che non usano un ID figlio, questo metodo recupera l'oggetto IAccessible corrispondente e CHILDID_edizione Standard LF.

Nell'esempio seguente viene illustrata l'implementazione dei metodi GetObjectForChild e GetIAccessiblePair per un elemento in una visualizzazione elenco personalizzata. I metodi consentono Automazione interfaccia utente di eseguire il mapping della coppia ID IAccessible e 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à Automazione interfaccia utente e sui pattern di controllo. IRawElementProviderSimple include i metodi seguenti:

Un server IAccessibleEx espone i pattern 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 un oggetto IUnknown e il client chiama QueryInterface per ottenere il pattern di controllo appropriato.

Un server IAccessibleEx può supportare Automazione interfaccia utente proprietà (ad esempio LabeledBy e IsRequiredForForm) implementando IRawElementProviderSimple::GetPropertyValue e fornendo un VALORE PROPERTYID intero che identifica la proprietà come parametro. Questa tecnica si applica solo alle proprietà Automazione interfaccia utente non incluse in un'interfaccia del pattern di controllo. Le proprietà associate a un'interfaccia del pattern di controllo vengono esposte tramite il metodo di interfaccia del pattern di controllo. Ad esempio, la proprietà IsSelected dal pattern di controllo SelectionItem verrà esposta con ISelectionItemProvider::get_IsSelected.