Использование IAccessibleEx из клиента

В этом разделе объясняется, как клиенты получают доступ к реализации IAccessEx сервера и используют ее для получения модель автоматизации пользовательского интерфейса свойств и шаблонов элементов управления для элементов пользовательского интерфейса.

В процедурах и примерах в этом разделе предполагается, что клиент IAccessible уже является внутрипроцессным, и существующий сервер Microsoft Active Accessibility. Они также предполагают, что клиент уже получил объект IAccessible с помощью одной из функций платформы специальных возможностей, таких как AccessibleObjectFromEvent, AccessibleObjectFromPoint или AccessibleObjectFromWindow.

Получение интерфейса IAccessibleEx из интерфейса IAccessible

Клиент, имеющий интерфейс IAccessible для объекта со специальными возможностями, может использовать его для получения соответствующего интерфейса IAccessibleEx , выполнив следующие действия:

  • Вызовите QueryInterface для исходного объекта IAccessible с идентификатором __uuidof(IServiceProvider).
  • Вызовите IServiceProvider::QueryService , чтобы получить IAccessibleEx.

Обработка идентификатора дочернего элемента

Клиенты должны быть подготовлены для серверов с идентификатором дочерних элементов, отличных от CHILDID_SELF. После получения интерфейса IAccessEx из IAccess клиенты должны вызывать IAccessEx::GetObjectForChild , если дочерний идентификатор не CHILDID_SELF (указывающий родительский объект).

В следующем примере показано, как получить IAccessibleEx для определенного объекта IAccessible и идентификатора дочернего элемента.

   
HRESULT GetIAccessibleExFromIAccessible(IAccessible * pAcc, long idChild, 
                                           IAccessibleEx ** ppaex)
{
    *ppaex = NULL;

    // First, get IServiceProvider from the IAccessible.
    IServiceProvider * pSp = NULL;
    HRESULT hr = pAcc->QueryInterface(IID_IServiceProvider, (void **) & pSp);
    if(FAILED(hr))
        return hr;
    if(pSp == NULL)
        return E_NOINTERFACE;

    // Next, get the IAccessibleEx for the parent object.
    IAccessibleEx * paex = NULL;
    hr = pSp->QueryService(__uuidof(IAccessibleEx), __uuidof(IAccessibleEx),
                                                                 (void **)&paex);
    pSp->Release();
    if(FAILED(hr))
        return hr;
    if(paex == NULL)
        return E_NOINTERFACE;

    // If this is for CHILDID_SELF, we're done. Otherwise, we have a child ID and 
    // can request the object for child.
    if(idChild == CHILDID_SELF)
    {
        *ppaex = paex;
        return S_OK;
    }
    else
    {
        // Get the IAccessibleEx for the specified child.
        IAccessibleEx * paexChild = NULL;
        hr = paex->GetObjectForChild(idChild, &paexChild);
        paex->Release();
        if(FAILED(hr))
            return hr;
        if(paexChild == NULL)
            return E_NOINTERFACE;
        *ppaex = paexChild;
        return S_OK;
    }
}

Получение интерфейса IRawElementProviderSimple

Если у клиента есть интерфейс IAccessibleEx , он может использовать QueryInterface для доступа к интерфейсу IRawElementProviderSimple , как показано в следующем примере.

HRESULT GetIRawElementProviderFromIAccessible(IAccessible * pAcc, long idChild,
                                                 IRawElementProviderSimple ** ppEl)
{
    * ppEl = NULL;

    // First, get the IAccessibleEx for the IAccessible and child ID pair.
    IAccessibleEx * paex;
    HRESULT hr = GetIAccessibleExFromIAccessible( pAcc, idChild, &paex );
    if(FAILED(hr))
        return hr;

    // Next, use QueryInterface.
    hr = paex->QueryInterface(__uuidof(IRawElementProviderSimple), (void **)ppEl);
    paex->Release();
    return hr;
}

Получение шаблонов элементов управления

Если клиент имеет доступ к интерфейсу IRawElementProviderSimple , он может получить интерфейсы шаблонов управления, реализованные поставщиками, а затем вызывать методы в этих интерфейсах. В приведенном ниже примере показано, как это сделать.

// Helper function to get a pattern interface from an IAccessible and child ID 
// pair. Gets the IAccessibleEx, then calls GetPatternObject and QueryInterface.
HRESULT GetPatternFromIAccessible(IAccessible * pAcc, long idChild,
                                     PATTERNID patternId, REFIID iid, void ** ppv)
{
    // First, get the IAccesibleEx for this IAccessible and child ID pair.
    IRawElementProviderSimple * pel;
    HRESULT hr = GetIRawElementProviderSimpleFromIAccessible(pAcc, idChild, &pel);
    if(FAILED(hr))
        return hr;
    if(pel == NULL)
        return E_NOINTERFACE;

    // Now get the pattern object.
    IUnknown * pPatternObject = NULL;
    hr = pel->GetPatternProvider(patternId, &pPatternObject);
    pel->Release();
    if(FAILED(hr))
        return hr;
    if(pPatternObject == NULL)
        return E_NOINTERFACE;

    // Finally, use QueryInterface to get the correct interface type.
    hr = pPatternObject->QueryInterface(iid, ppv);
    pPatternObject->Release();
    if(*ppv == NULL)
        return E_NOINTERFACE;
    return hr;
}

HRESULT CallInvokePatternMethod(IAccessible * pAcc, long idChild)
{
    IInvokeProvider * pPattern;
    HRESULT hr = GetPatternFromIAccessible(pAcc, varChild,
                                  UIA_InvokePatternId, __uuidof(IInvokeProvider),
                                  (void **)&pPattern);
    if(FAILED(hr))
        return hr;

    hr = pPattern->Invoke();
    pPattern->Release();
    return hr;
}

Получение значений свойств

Если клиент имеет доступ к IRawElementProviderSimple, он может получить значения свойств. В следующем примере показано, как получить значения для свойств AutomationId и LabeledBy Microsoft модель автоматизации пользовательского интерфейса.

#include <initguid.h>
#include <uiautomationcoreapi.h> // Includes the UI Automation property GUID definitions.
#include <uiautomationcoreids.h> // Includes definitions of pattern/property IDs.

// Assume we already have a IRawElementProviderSimple * pEl.

VARIANT varValue;

// Get AutomationId property:
varValue.vt = VT_EMPTY;
HRESULT hr = pEl->GetPropertyValue(UIA_AutomationIdPropertyId, &varValue);
if(SUCCEEDED(hr))
{
    if(varValue.vt == VT_BSTR)
    {
        // AutomationId is varValue.bstrVal.
    }
    VariantClear(&varValue);
}


// Get LabeledBy property:
varValue.vt = VT_EMPTY;
hr = pEl->GetPropertyValue(UIA_LabeledByPropertyId, &varValue);
if(SUCCEEDED(hr))
{
    if(varValue.vt == VT_UNKNOWN || varValue.punkVal != NULL)
    {
        // Use QueryInterface to get IRawElementProviderSimple.
        IRawElementProviderSimple * pElLabel = NULL;
        hr = varValue.punkVal->QueryInterface(__uuidof(IRawElementProviderSimple),
                                              (void**)& pElLabel);
        if (SUCCEEDED(hr))
        {
            if(pElLabel != NULL)
            {
            // Use the pElLabel pointer here.
            pElLabel ->Release();
            }
        }
    }
    VariantClear(&varValue);
}

Предыдущий пример применяется к свойствам, которые не связаны с шаблоном элемента управления. Чтобы получить доступ к свойствам шаблона управления, клиент должен получить и использовать интерфейс шаблона элемента управления.

Получение интерфейса IAccessible из интерфейса IRawElementProviderSimple

Если клиент получает интерфейс IRawElementProviderSimple для элемента пользовательского интерфейса, клиент может использовать этот интерфейс для получения соответствующего интерфейса IAccessible для элемента . Это полезно, если клиенту требуется доступ к свойствам Microsoft Active Accessibility для элемента .

Клиент может получить интерфейс IRawElementProviderSimple в качестве значения свойства (например, путем вызова IRawElementProviderSimple::GetPropertyValue с UIA_LabeledByPropertyId) или в качестве элемента, полученного методом (например, путем вызова ISelectionProvider::GetSelection для получения массива интерфейсов IRawElementProviderSimple выбранных элементов). После получения интерфейса IRawElementProviderSimple клиент может использовать его для получения соответствующего IAccessible , выполнив следующие действия:

  • Попробуйте использовать QueryInterface для получения интерфейса IAccessibleEx .
  • Если queryInterface завершается сбоем, вызовите метод IAccessibleEx::ConvertReturnedElement в экземпляре IAccessibleEx , из которого изначально было получено свойство.
  • Вызовите метод GetIAccessiblePair в новом экземпляре IAccessibleEx , чтобы получить идентификатор интерфаксов IAccessible и дочерний идентификатор.

В следующем фрагменте кода показано, как получить интерфейс IAccessible из ранее полученного интерфейса IRawElementProviderSimple .

// IRawElementProviderSimple * pVal - an element returned by a property or method
// from another IRawElementProviderSimple.

IAccessible * pAcc = NULL;
long idChild;

// First, try to use QueryInterface to get the IAccessibleEx interface.
IAccessibleEx * pAccEx;
HRESULT hr = pVal->QueryInterface(__uuidof(IAccessibleEx), (void**)&pAccEx);
if (SUCCEEDED(hr)
{
    if (!pAccEx)
    {
        // If QueryInterface fails, and the IRawElementProviderSimple was 
              // obtained as a property or return value from another 
              // IRawElementProviderSimple, pass it to the 
              // IAccessibleEx::ConvertReturnedValue method of the
        // originating element.

        pAccExOrig->ConvertReturnedElement(pVal, &pAccEx);
    }

    if (pAccEx)
    {
        // Call GetIAccessiblePair to get an IAccessible interface and 
              // child ID.
        pAccEx->GetIAccessiblePair(&pAcc, &idChild);
    }

    // Finally, use the IAccessible interface and child ID.
    if (pAcc)
    {
        // Use IAccessible methods to get further information about this UI
              // element, or pass it to existing code that works in terms of 
              // IAccessible.
        ...
    }
}