Реализация IAccessibleEx для поставщиков
В этом разделе объясняется, как добавить возможности поставщика microsoft модель автоматизации пользовательского интерфейса на сервер Microsoft Active Accessibility, реализуя интерфейс IAccessibleEx.
Перед реализацией IAccessibleEx рассмотрите следующие требования:
- Базовая иерархия объектов специальных возможностей Майкрософт должна быть чистой. IAccessibleEx не может исправить проблемы с существующими иерархиями объектов со специальными возможностями. Все проблемы со структурой объектной модели должны быть исправлены в реализации Microsoft Active Accessibility перед реализацией IAccessibleEx.
- Реализация IAccessibleEx должна соответствовать спецификации Microsoft Active Accessibility и спецификации модель автоматизации пользовательского интерфейса. Средства доступны для проверки соответствия в обоих спецификациях. Дополнительные сведения см. в разделе "Тестирование специальных возможностей" и модель автоматизации пользовательского интерфейса "Проверка (проверка UIA) Test Automation Framework.
Реализация IAccessibleEx требует выполнения следующих основных действий.
- Реализуйте IServiceProvider в объекте со специальными возможностями, чтобы интерфейс IAccessibleEx можно было найти в этом или отдельном объекте.
- Реализуйте IAccessibleEx в объекте со специальными возможностями.
- Создайте объекты со специальными возможностями для всех дочерних элементов Microsoft Active Accessibility, которые в Microsoft Active Accessibility представлены интерфейсом IAccessible в родительском объекте (например, элементы списка). Реализуйте IAccessibleEx для этих объектов.
- Реализуйте IRawElementProviderSimple для всех доступных объектов.
- Реализуйте соответствующие интерфейсы шаблонов управления на доступных объектах.
Реализация интерфейса IServiceProvider
Так как реализация IAccessibleEx для элемента управления может находиться в отдельном объекте, клиентские приложения не могут полагаться на QueryInterface для получения этого интерфейса. Вместо этого клиенты должны вызывать IServiceProvider::QueryService. В следующем примере реализации этого метода предполагается, что IAccessibleEx не реализован в отдельном объекте, поэтому метод просто вызывает запросInterface.
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;
}
};
Реализация интерфейса IAccessibleEx
В Microsoft Active Accessibility элемент пользовательского интерфейса всегда определяется интерфейсом IAccessible и дочерним идентификатором. Один экземпляр IAccessible может представлять несколько элементов пользовательского интерфейса.
Так как каждый экземпляр IAccessibleEx представляет только один элемент пользовательского интерфейса, каждая пара идентификаторов IAccessible и дочернего идентификатора должна быть сопоставлена с одним экземпляром IAccessibleEx. IAccessibleEx включает два метода для обработки этого сопоставления:
- GetObjectForChild — извлекает интерфейс IAccessibleEx для указанного дочернего элемента. Этот метод возвращает значение NULL , если реализация IAccessibleEx не распознает указанный дочерний идентификатор, не имеет IAccessibleEx для указанного дочернего элемента или представляет дочерний элемент.
- GetIAccessiblePair — извлекает интерфейс IAccessible и дочерний идентификатор элемента IAccessibleEx. Для реализаций IAccessible, которые не используют дочерний идентификатор, этот метод извлекает соответствующий объект IAccessible и CHILDID_SELF.
В следующем примере показана реализация методов GetObjectForChild и GetIAccessiblePair для элемента в пользовательском представлении списка. Методы позволяют модель автоматизации пользовательского интерфейса сопоставлять пару идентификаторов IAccessible и дочернего идентификатора с соответствующим экземпляром IAccessibleEx.
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;
}
}
Если реализация доступного объекта не использует дочерний идентификатор, методы по-прежнему можно реализовать, как показано в следующем фрагменте кода.
// 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;
}
Реализация интерфейса IRawElementProviderSimple
Серверы используют IRawElementProviderSimple для предоставления сведений о модель автоматизации пользовательского интерфейса свойствах и шаблонах элементов управления. IRawElementProviderSimple включает следующие методы:
- GetPatternProvider— этот метод используется для предоставления интерфейсов шаблонов управления. Он возвращает объект, поддерживающий указанный шаблон элемента управления, или NULL , если шаблон элемента управления не поддерживается.
- GetPropertyValue— этот метод используется для предоставления модель автоматизации пользовательского интерфейса значений свойств.
- HostRawElementProvider— этот метод не используется с реализацией IAccessibleEx .
- ProviderOptions— этот метод не используется с реализациями IAccessibleEx .
Сервер IAccessibleEx предоставляет шаблоны управления путем реализации IRawElementProviderSimple::GetPatternProvider. Этот метод принимает целочисленный параметр, указывающий шаблон элемента управления. Сервер возвращает значение NULL , если шаблон не поддерживается. Если интерфейс шаблона элемента управления поддерживается, серверы возвращают IUnknown , а клиент вызывает QueryInterface , чтобы получить соответствующий шаблон элемента управления.
Сервер IAccessibleEx может поддерживать свойства модель автоматизации пользовательского интерфейса (например, LabeledBy и IsRequiredForForm), реализуя IRawElementProviderSimple::GetPropertyValue и указав целочисленный PROPERTYID, определяющий свойство как параметр. Этот метод применяется только к свойствам модель автоматизации пользовательского интерфейса, которые не включены в интерфейс шаблона элемента управления. Свойства, связанные с интерфейсом шаблона элемента управления, предоставляются с помощью метода интерфейса шаблона элемента управления. Например, свойство IsSelected из шаблона элемента управления SelectionItem будет предоставлено с помощью ISelectionItemProvider::get_IsSelected.