从客户端使用 IAccessibleEx
本主题说明客户端如何访问服务器的 IAccessibleEx 实现,并使用它来获取 UI 元素UI 自动化属性和控件模式。
本节中的过程和示例假定 IAccessible 客户端已在进程内,以及现有的 Microsoft Active Accessibility 服务器。 它们还假定客户端已使用辅助功能框架函数之一(如 AccessibleObjectFromEvent、AccessibleObjectFromPoint 或 AccessibleObjectFromWindow)获取了 IAccessible 对象。
从 IAccessible 接口获取 IAccessibleEx 接口
具有可访问对象的 IAccessible 接口的客户端可以使用它通过以下步骤获取相应的 IAccessibleEx 接口:
- 使用 IServiceProvider) 的 II __uuidof (D 对原始 IAccessible 对象调用 QueryInterface。
- 调用 IServiceProvider::QueryService 以获取 IAccessibleEx。
处理子 ID
必须为具有除 CHILDID_SELF 以外的子 ID 的服务器准备客户端。 从 IAccessible 获取 IAccessibleEx 接口 后,如果子 ID 不CHILDID_SELF (指示父对象) ,则客户端必须调用 IAccessibleEx::GetObjectForChild 。
以下示例演示如何获取特定 IAccessible 对象和子 ID 的 IAccessibleEx 。
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 UI 自动化 属性的值。
#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);
}
前面的示例适用于未与控件模式关联的属性。 若要访问控制模式属性,客户端必须获取并使用控件模式接口。
从 IRawElementProviderSimple 接口检索 IAccessible 接口
如果客户端获取 UI 元素的 IRawElementProviderSimple 接口,则客户端可以使用该接口获取元素的相应 IAccessible 接口。 如果客户端需要访问 元素的 Microsoft Active Accessibility 属性,这很有用。
客户端可以将 IRawElementProviderSimple 接口作为属性值 (获取,例如,通过使用 UIA_LabeledByPropertyId) 调用 IRawElementProviderSimple::GetPropertyValue ,或作为方法检索的项 (,例如,通过调用 ISelectionProvider::GetSelection 来检索选定元素) 的 IRawElementProviderSimple 接口数组。 获取 IRawElementProviderSimple 接口后,客户端可以使用它通过以下步骤获取相应的 IAccessible :
- 尝试使用 QueryInterface 获取 IAccessibleEx 接口。
- 如果 QueryInterface 失败,请在最初从中获取属性的 IAccessibleEx 实例上调用 IAccessibleEx::ConvertReturnedElement。
- 在新的 IAccessibleEx 实例上调用 GetIAccessiblePair 方法以获取 IAccessible interfae 和子 ID。
以下代码片段演示如何从以前获取的 IRawElementProviderSimple 接口获取 IAccessible 接口。
// 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.
...
}
}